YouTubeKit 是一个强大的 Swift 包,无需任何 API 密钥即可向 YouTube API 发送请求。
DocC 文档可在此处查看。
请确保您对 YouTubeKit 的实现和使用是合法的,并务必告知您的应用程序的潜在用户,在使用您的实现时可能遇到的潜在风险。
Add Package
。import YouTubeKit
。请注意,这是从另一个 iOS 应用程序改编而来,因此正在不断开发中。
以下是 YouTubeKit 支持的默认请求列表,您可以获得的所有信息如下:
HomeScreenResponse -> 从 YouTube 主页获取视频,其 Continuation 也是可用的。
SearchResponse -> 获取文本查询的结果,其 Continuation 也是可用的。
SearchResponse.Restricted -> 获取文本查询的 Creative Commons 版权结果。
VideoInfosResponse -> 通过 ID 获取视频的信息。 警告:使用此请求时,将 useCookies
参数设置为 true 不会有任何效果(除非您使用 YouTubeModel
发起请求),因为它不适用于 YouTube API。
VideoInfosWithDownloadFormatsResponse -> 通过 ID 获取视频的信息和 DownloadFormats,比 VideoInfosResponse 消耗更多带宽,但具有 DownloadFormat 数组。
MoreVideoInfosResponse 获取有关视频的各种信息(请参阅文档)。
TrendingVideosResponse 获取热门标签。
AutoCompletionResponse -> 从文本查询获取自动完成建议。
ChannelInfosResponse -> 通过 ID 获取 YouTube 频道的信息。
PlaylistInfosResponse -> 获取播放列表的信息及其包含的视频。 其 Continuation 也是可用的。
YouTubeKit 中的每个可能的请求都符合协议 YouTubeResponse,它包含一些有用的方法
static var headersType
是一个静态变量,指示用于发出请求的标头的类型,其文档指示要提供哪些参数才能使请求正常工作。static var parametersValidationList
是一个静态变量,指示是否应该对请求的参数执行进一步的处理和验证。 它可以验证 videoId 是否具有正确的格式,或者仅仅是提供了一个参数。static func validateRequest(data: inout RequestData) throws
是在通过互联网发送请求之前将调用的方法。 如果存在一些验证器,它将转发来自 parametersValidationList
的验证器给出的错误。static func decodeData(data: Data) throws -> Self
是一个静态方法,用于解码一些 Data 并返回 YouTubeResponse
的实例。 除了某些特殊情况(例如,原始数据不能直接转换为 JSON),您不需要覆盖此方法的默认实现。static func decodeJSON(json: JSON) throws -> Self
是一个静态方法,用于解码一些 JSON 并返回 YouTubeResponse
的实例,如果 JSON 不能代表正确的响应,它将返回一个空响应(仅 nil 和空数组)。 如果关键提取步骤失败,则可以抛出 ResponseExtractionError
。static func checkForErrors(json: JSON) throws
是一个静态方法,应该在调用 decodeJSON(json: JSON)
之前调用,以避免尝试解码表示错误的 JSON。 除了某些特殊情况(为此请求返回的错误采用非标准格式),您不需要覆盖默认实现。static func sendNonThrowingRequest()
和 static func sendThrowingRequest()
是静态方法,允许您通过使用 async await 系统或闭包来发出请求。 其用法将在以下教程中详细说明。使用 YouTubeKit,你可以向 YouTube API 发送各种各样的请求。我们经常添加新的请求类型,你甚至可以在自定义请求/响应中创建自己的请求类型。
YouTubeModel
实例,如果没有,你可以这样创建一个:let YTM = YouTubeModel()
定义请求的数据参数。要获取所需的头部信息,你可以查看 YouTubeResponse.headersType
的定义,它应该描述要发送哪些数据。以下是一个 SearchResponse
的示例:
a. 右键单击请求类型,然后按 Jump to definition
。SearchResponse.headersType
是 HeaderTypes.search
。
b. 它的定义是:
/// Get search results.
/// - Parameter query: Search query
case search
这意味着你必须提供一个查询才能使请求工作并给出相关结果。
c. 你可以这样定义数据参数:
let textQuery: String = "my super query"
let dataParameters: [HeadersList.AddQueryInfo.ContentTypes : String] = [
.query: textQuery
]
使用以下方式执行请求(例如,一个 SearchResponse
请求):
SearchResponse.sendNonThrowingRequest(youtubeModel: YTM, data: dataParameters, result: { result, error in
switch result {
case .success(let response):
/// Process here the result.
print(response)
case .failure(let error):
/// If there is no result you should obtain an error explaining why there is none.
print(error)
}
})
你也可以像这样发送请求,而无需显式声明 dataParameters
:
SearchResponse.sendNonThrowingRequest(youtubeModel: YTM, data: [.query: textQuery], result: { result in
switch result {
case .success(let response):
/// Process here the result.
print(response)
case .failure(let error):
/// If there is no result you should obtain an error explaining why there is none.
print(error)
}
})
甚至可以像这样使用 async/throws API:
let result = try await SearchResponse.sendThrowingRequest(youtubeModel: YTM, data: [.query: textQuery])
switch result {
case .success(let response):
/// Process here the result.
print(response)
case .failure(let error):
/// If there is no result you should obtain an error explaining why there is none.
print(error)
}
YouTubeKit 允许你通过以下步骤将帐户的 Cookie 添加到请求中:
let YTM = YouTubeModel()
YTM.cookies = "myCookies"
YouTubeModel
的 alwaysUseCookies
:let YTM = YouTubeModel()
YTM.cookies = "myCookies"
YTM.alwaysUseCookies = true
useCookies
参数来选择按请求使用 Cookie。YouTubeKit 具有一种内置方式,可以在运行时主动调试请求/响应。
RequestsLogger
类型,并将其添加到 YouTubeModel
的 logger
属性中。class Logger: RequestsLogger {
var loggedTypes: [any YouTubeResponse.Type]? = nil
var logs: [YouTubeKit.RequestLog] = []
var isLogging: Bool = false
var maximumCacheSize: Int? = nil
}
let logger = Logger()
YTM.logger = logger
startLogging
方法启用日志记录:logger.startLogging()
logger.isLogging
为 true 时,每个已完成请求的完整日志按时间顺序存储在 logger.logs
中。 请注意,启用日志记录可能会消耗大量 RAM,因为记录器会存储大量原始信息。 因此,请确保定期使用 logger.clearLogs
清除 logger.logs
,在不需要时禁用日志记录,或者使用 logger.setCacheSize()
设置合理的缓存限制。许多结构和协议都有自定义请求调用(各种 YouTubeResponse
的快捷方式),这里有一些示例:
1. `YouTubeVideo` (`YTVideo` conforms to it) has:
1. `fetchStreamingInfos` that can be used to retrieve the basic streaming data.
2. `fetchStreamingInfosWithDownloadFormats` that is the same as `fetchStreamingInfos` but it includes the download formats (all the different video/audio formats you can stream/download the video).
3. `fetchMoreInfos` that can be used to retrieve more infos about the video (recommended videos, description with chapters and links, and more!).
4. `likeVideo`, `dislikeVideo`, `removeLikeFromVideo`.
5. `fetchAllPossibleHostPlaylists`
2. `YouTubeChannel` (`YTChannel`and `YTLittleChannelInfos` are conform to it) has:
1. `fetchInfos` that can be used to retrieve various informations about the channel.
3. `ContinuableResponse` (`HomeScreenResponse`, `SearchResponse`, `PlaylistInfosResponse` are conform to it) has:
1. `mergeContinuation` to merge the continuations easily.
2. `fetchContinuation` to get those continuations.
4. `HistoryResponse` has `removeVideo` that can be used to remove a video from the history.
要创建自定义标头以及自定义请求/响应函数,你必须:
HeadersList
的函数附加到 YouTubeModel.customHeadersFunctions
中,例如:let YTM = YouTubeModel()
let myCustomHeadersFunction: () -> HeadersList = {
HeadersList(
url: URL(string: "https://www.myrequesturl.com")!,
method: .POST,
headers: [
.init(name: "Accept", content: "*/*"),
.init(name: "Accept-Encoding", content: "gzip, deflate, br"),
.init(name: "Accept-Language", content: "\(YTM.selectedLocale);q=0.9"),
],
addQueryAfterParts: [
.init(index: 0, encode: true)
],
httpBody: [
"my query is: ",
" and it is really cool!"
]
)
}
YouTubeModel.shared.customHeadersFunctions["myHeadersID"] = myCustomHeadersFunction
/*
We imagine that the JSON is of the form:
{
"name": "myName",
"surname": "mySurname"
}
*/
/// Struct representing a getNameAndSurname response.
public struct NameAndSurnameResponse: YouTubeResponse {
public static let headersType: HeaderTypes = .customHeaders("myHeadersID") //<- the myHeadersID has to be the same as the one you defined in step 1!
public static let parametersValidationList: ValidationList = [:] // we don't need any validators here as there's no parameters to provide.
/// String representing a name.
public var name: String = ""
/// String representing a surname.
public var surname: String = ""
public static func decodeJSON(json: JSON) -> NameAndSurnameResponse {
/// Initialize an empty response.
var nameAndSurnameResponse = NameAndSurnameResponse()
nameAndSurnameResponse.name = json["name"].stringValue
nameAndSurnameResponse.surname = json["surname"].stringValue
return nameAndSurnameResponse
}
}
func sendRequest( youtubeModel: YouTubeModel, data: [HeadersList.AddQueryInfo.ContentTypes : String], result: @escaping (Result<ResponseType, Error>) -> () )
例如:/// We continue with our example:
NameAndSurnameResponse.sendNonThrowingRequest(youtubeModel: YTM, data: [:], result: { result in
switch result {
case .success(let response):
/// Process here the result.
print(response)
case .failure(let error):
/// If there is no result you should obtain an error explaining why there is none.
print(error)
}
})
注意:你会在请求中包含参数,如果需要,例如:query、browseId 或任何放入请求体中发送的内容。
此类别列出了你使用 YouTubeKit 时可能遇到的问题的解决方案。
错误 Domain=NSURLErrorDomain 代码=-1003 “找不到具有指定主机名的服务器。”
可以通过在 Xcode 中项目的目标的 Signing & Capabilities
类别中启用 Outgoing Connections (Client)
来解决此问题。
下载纯音频 DownloadFormat
时下载速度非常慢:可以通过将 range: bytes=0-(CONTENT_LENGHT_BYTES)
HTTP 标头添加到你的 URLRequest
来解决此问题(例如 request.addValue("bytes=0-\(myDownloadFormat.contentLength ?? "")", forHTTPHeaderField: "range")
)。
YouTubeModel.selectedLocale
类似于 en-US
。感谢 SwiftyJSON 库,它方便了 JSON 提取!
Copyright (c) 2014 - 2017 Ruoyu Fu, Pinglin Tang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
``