使用它的REST API,而不iOS SDK中的视频上传到YouTube(Uploading vid

2019-10-28 12:02发布

还是一个菜鸟,所以大家多多包涵。 我使用SWIFT 3与REST的V3 YouTube数据API。 所以我的连接和授权工作就好了,我可以拉我的视频列表。

我似乎无法弄清楚如何上传虽然。 我发现了一个古老的职位,是非常相似的矿( 设置片段数据通过YouTube的使用雨燕REST API上传 )。

我很困惑,他们都可以从该令牌变量,以及他们如何将它传递到这个函数。 另外,不知道如何设置上传变量是后前右。 任何帮助表示赞赏!

func uploadVideo(token: String, callback: @escaping (Bool) -> Void){

    let headers = ["Authorization": "Bearer \(token)"]

    let path = Bundle.main.path(forResource: "intro", ofType: "mov")
    let videodata: NSData = NSData.dataWithContentsOfMappedFile(path!)! as! NSData
    upload(
        .POST,
        "https://www.googleapis.com/upload/youtube/v3/videos?part=snippet",
        headers: headers,
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(data:"{'snippet':{'title' : 'TITLE_TEXT', 'description': 'DESCRIPTION_TEXT'}}".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"snippet", mimeType: "application/json")
            multipartFormData.appendBodyPart(data: videodata, name: "intro", fileName: "intro.mov", mimeType: "application/octet-stream")
    },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { request, response, error in
                    print(response)
                    callback(true)
                }
            case .Failure(_):
                callback(false)
            }
    })
}

Answer 1:

从更新的代码https://github.com/mfriedl89/Developer5/blob/master/Conari/Conari/ 。 这只是一个POC居多,重构需要(如:使用Codable为JSON解析,而不是强制解包)。 和适当的OAuth2流程应采用以下方式实现SFSafariViewController / SFAuthenticationSession (取决于目标的iOS版本)或谷歌登入

import Foundation

class YoutubeTokenProvider {

    // TODO: Store token, evaluate ttl, retry request if needed
    static func getAccessToken(callback: @escaping (String?) -> Void){

        /* Remark (Security)
         Storing the data inside here is not secure, but still better than requesting it from a custom request.
         Two possibilities:
         1. Storing all data here
         2. Storing all data on an external server and only requesting the access token from this server
         Option 1 was chosen based on the assumption that decompiling the app should be more difficult than just
         monitoring the request and getting the access token (which allows the attacker to do anything with our
         YouTube account). The disadvantage is that an attacker gets everything after a successful decompilation
         and not only the access token.
         */

        let client_secret = "..."
        let grant_type = "refresh_token"
        let refresh_token = "..."
        let client_id = "..."

        var request = URLRequest(url: URL(string: "https://accounts.google.com/o/oauth2/token")!)
        request.httpMethod = "POST"
        let postString = "client_secret=" + client_secret +
            "&grant_type=" + grant_type +
            "&refresh_token=" + refresh_token +
            "&client_id=" + client_id
        request.httpBody = postString.data(using: .utf8)

        URLSession.shared.dataTask(with: request, completionHandler: {data, response, error in
            guard let data = data, error == nil else {
                callback(nil)
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                callback(nil)
                return
            }

            do {
                let jsonData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! YouTubeManager.JSON
                let accessToken = jsonData["access_token"]! as? String
                callback(accessToken)
            } catch {
                callback(nil)
            }
            return
        }).resume()
    }
}


import Foundation

struct YoutubeVideo {
    let title, thumbnailUrl, videoId: String
}


import Foundation
import Alamofire

/// This file will act as our YouTube manager.
class YouTubeManager {

    typealias JSON = [String:AnyObject]
    typealias SearchByTitleCallback = (_ response: [YoutubeVideo], _ success:Bool, _ message:String) -> Void
    typealias PostVideoCallback = (String, Bool) -> Void

    /** Singletone instance. */
    static let sharedManager = YouTubeManager()

    let apiKey       = "..."
    let channelID    = "..."
    let searchApiUrl = "https://www.googleapis.com/youtube/v3/search"
    let identifier   = "videoID: "


    func parseIdentifier(input: String) -> String? {
        let seperator = "videoID: "

        if input.contains(self.identifier) {
            let videoID = input.components(separatedBy: seperator)
            return videoID.last
        }

        return nil
    }

    func searchVideoByTitle(title: String, completionHandler: @escaping SearchByTitleCallback) -> Void {
        let eTitle = title.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
        let urlString = searchApiUrl + "?part=snippet&q=" + eTitle + "&type=video&key=" + apiKey

        let targetURL = URL(string: urlString)!
        var returnArray = [YoutubeVideo]()

        let task = URLSession.shared.dataTask(with: targetURL) { (data, response, error) in
            guard error == nil else {
                completionHandler(returnArray, false, "error = \(error!)")
                return
            }
            guard let data = data else {
                completionHandler(returnArray, false, "error = data is nil")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                completionHandler(returnArray, false, "response = \(response!)")
                return
            }

            do {
                let resultsDict = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! JSON

                let items = resultsDict["items"] as! [JSON]
                returnArray = items.map { item in
                    let snippetDict = item["snippet"] as! JSON
                    let title = snippetDict["title"] as! String
                    let thumbnail = ((snippetDict["thumbnails"] as! JSON)["default"] as! JSON)["url"] as! String
                    let videoid = (item["id"] as! JSON)["videoId"] as! String

                    return YoutubeVideo(title: title, thumbnailUrl: thumbnail, videoId: videoid)
                }
                completionHandler(returnArray, true, "")

            } catch {
                completionHandler(returnArray, false, "error serializing JSON: \(error)")
            }
        }
        task.resume()
    }

    func postVideoToYouTube(uploadUrl: String, videoData: Data, title: String, callback: @escaping PostVideoCallback){

        YoutubeTokenProvider.getAccessToken { (accessToken) in
            guard let accessToken = accessToken
                else { return }

            let headers: HTTPHeaders = ["Authorization": "Bearer \(accessToken)"]

            Alamofire.upload(
                multipartFormData: { multipartFormData in
                    let metadata = "{'snippet':{'title' : '\(title)', 'description': 'This video was uploaded using Mr Tutor.'}}".data(using: .utf8, allowLossyConversion: false)!
                    multipartFormData.append(metadata, withName: "snippet", mimeType: "application/json")
                    multipartFormData.append(videoData, withName: "video", fileName: "sample.mp4", mimeType: "application/octet-stream")
            },
                to: "https://www.googleapis.com/upload/youtube/v3/videos?part=snippet",
                headers: headers,
                encodingCompletion: { encodingResult in
                    switch encodingResult {
                    case .success(let upload, _, _):
                        upload.responseJSON { response in

                            do {
                                let jsonData = try JSONSerialization.jsonObject(with: response.data!, options: .allowFragments) as! JSON

                                let videoID = jsonData["id"] as! String
                                let identifierFinal = self.identifier + videoID
                                callback(identifierFinal, true)
                            } catch {
                                print("error serializing JSON: \(error)")
                                callback("", false)
                            }

                            print("Success")
                        }
                    case .failure(_):
                        print("Failure")
                        callback("", false)
                    }
            })
        }

    }

}


文章来源: Uploading video to Youtube using its REST API without the iOS SDK