YouTubeKit

YouTubeKit 是一个强大的 Swift 包,无需任何 API 密钥即可向 YouTube API 发送请求。

DocC 文档可在此查看。

免责声明

请确保您对 YouTubeKit 的实现和使用是合法的,并务必告知您的应用程序的潜在用户,在使用您的实现时可能遇到的潜在风险。

安装

  1. 将软件包安装到您的 Xcode 项目中
  2. 在顶部菜单中,转到 File->Add Packages...
  3. 输入此仓库的链接:https://github.com/b5i/YouTubeKit (您可能需要将 Xcode 连接到您的 github 帐户)。
  4. 点击 Add Package
  5. 通过导入它在您的项目中使用它:import YouTubeKit

请注意,这是从另一个 iOS 应用程序改编而来,因此正在不断开发中。

默认请求

以下是 YouTubeKit 支持的默认请求列表,您可以获得的所有信息如下:

常规

帐户

播放列表

评论(用于回复和编辑,评论和对评论的回复有所区分)

发起请求

YouTubeKit 中的每个可能的请求都符合协议 YouTubeResponse,它包含一些有用的方法

使用 YouTubeKit,你可以向 YouTube API 发送各种各样的请求。我们经常添加新的请求类型,你甚至可以在自定义请求/响应中创建自己的请求类型。

  1. 请确保你拥有一个 YouTubeModel 实例,如果没有,你可以这样创建一个:
let YTM = YouTubeModel()
  1. 定义请求的数据参数。要获取所需的头部信息,你可以查看 YouTubeResponse.headersType 的定义,它应该描述要发送哪些数据。以下是一个 SearchResponse 的示例:

    a. 右键单击请求类型,然后按 Jump to definitionSearchResponse.headersTypeHeaderTypes.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
    ]
  2. 使用以下方式执行请求(例如,一个 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)
}

Cookie 的使用

YouTubeKit 允许你通过以下步骤将帐户的 Cookie 添加到请求中:

  1. 在你的 YouTubeModel 中定义 cookies 变量:
let YTM = YouTubeModel()
YTM.cookies = "myCookies"
  1. 如果你希望在发出请求时始终使用 Cookie,你可以选择像这样设置 YouTubeModelalwaysUseCookies
let YTM = YouTubeModel()
YTM.cookies = "myCookies"
YTM.alwaysUseCookies = true
  1. 你也可以通过指定每个请求函数中存在的 useCookies 参数来选择按请求使用 Cookie。

调试请求/响应

YouTubeKit 具有一种内置方式,可以在运行时主动调试请求/响应。

  1. 为此,创建你的 RequestsLogger 类型,并将其添加到 YouTubeModellogger 属性中。
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
  1. 通过调用 logger 的 startLogging 方法启用日志记录:
logger.startLogging()
  1. 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.

自定义请求和响应

要创建自定义标头以及自定义请求/响应函数,你必须:

  1. 将用于生成 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
  1. 创建符合 YouTubeResponse 协议的响应,例如:
/*
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
    }
}
  1. 要执行它,你只需调用 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 时可能遇到的问题的解决方案。

连接问题

请求结果问题

鸣谢

感谢 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.
``