iOS Swift:如何使用TwitterKit将视频发布到Twitter?

时间:2016-03-27 15:15:20

标签: ios swift video twitter

我还没有找到关于SO的相关和最新答案。

以下是我目前正在使用的代码,所有请求都已正确处理但未发布视频?

if let userID = Twitter.sharedInstance().sessionStore.session()?.userID {
    var client = TWTRAPIClient(userID: userID)

    let text: String = "Testing Video"
    let videoLength: String = "\(self.video.length)"
    print(videoLength)
    var initError: NSError?
    var message = ["status": text, "command" : "INIT", "media_type" : "video/m4v", "total_bytes" : videoLength]
    let preparedRequest: NSURLRequest = client.URLRequestWithMethod("POST", URL: self.strUploadUrl, parameters: message, error: &initError)
    client.sendTwitterRequest(preparedRequest, completion: { (urlResponse: NSURLResponse?, responseData: NSData?, error: NSError?) -> Void in
        if error == nil {

            do {


                let json: NSDictionary = try (NSJSONSerialization.JSONObjectWithData(responseData!, options: NSJSONReadingOptions(rawValue: 0)) as? NSDictionary)!
                print("JSON is \(json)")


                let mediaID = json.objectForKey("media_id_string") as! String

                client = TWTRAPIClient(userID: userID)
                var uploadError: NSError?
                let videoString = self.video.base64EncodedStringWithOptions([])

                message = ["command" : "APPEND", "media_id" : mediaID, "segment_index" : "0", "media" : videoString]
                let preparedRequest = client.URLRequestWithMethod("POST", URL: self.strUploadUrl, parameters: message, error: &uploadError)
                client.sendTwitterRequest(preparedRequest, completion: { (urlResponse: NSURLResponse?, responseData: NSData?, error: NSError?) -> Void in
                    if error == nil {
                        client = TWTRAPIClient(userID: userID)
                        var finalizeError: NSError?
                        message = ["command":"FINALIZE", "media_id": mediaID]
                        let preparedRequest = client.URLRequestWithMethod("POST", URL: self.strUploadUrl, parameters: message, error: &finalizeError)
                        client.sendTwitterRequest(preparedRequest, completion: { (urlResponse: NSURLResponse?, responseData: NSData?, error: NSError?) -> Void in
                            if error == nil {
                                client = TWTRAPIClient(userID: userID)
                                var sendError: NSError?
                                let message = ["status": text, "wrap_links": "true", "media_ids": mediaID]
                                //var updateMessage = NSMutableDictionary(dictionary: message)
                                let preparedRequest = client.URLRequestWithMethod("POST", URL: self.strStatusUrl, parameters: message , error: &sendError)
                                client.sendTwitterRequest(preparedRequest, completion: { (urlResponse: NSURLResponse?, responseData: NSData?, error: NSError?) -> Void in

                                })
                            } else {
                                print("Command FINALIZE failed \n \(error!)")
                            }
                        })
                    } else {
                        print("Command APPEND failed")
                    }
                })
            }

            catch {
                print("\(error)")
            }
        }

        else {
            print("\(error.debugDescription)Command INIT failed")
        }
    })
    }

上述所有代码均有效,但视频未上传。我无法弄清楚我错过了什么,Twitter的文档在发布视频时非常糟糕。

2 个答案:

答案 0 :(得分:3)

如果您想将@ Trung的代码转换为Swift 4,并且如果您想使用TwitterKit,则可以使用此枚举来处理所有上传阶段:

enum UploadStage {
    case initial(size: String, videoDuration: Int?) // if your video duration is <= 30s, you can pass nil here
    case append(mediaId: String, videoData: Data, segment: Int)
    case finalize(mediaId: String)
    case status(status: String, mediaId: String)

    static let videoChunkMaxSize = 5 * 1000 * 1000

    var parameters: [String: Any] {
        get {
            switch self {

            case .initial(let size, let videoDuration):
                var params = ["command":stageName, "total_bytes": size, "media_type": "video/mp4"]
                if let videoDuration = videoDuration, videoDuration > 30 {
                    params["media_category"] = "tweet_video"
                }
                return params
            case .append(let mediaId, _ , let segment):
                let videoChunkString = self.videoChunk!.base64EncodedString(options: [])
                return ["command":stageName, "media_id": mediaId, "segment_index": "\(segment)", "media": videoChunkString]
            case .finalize(let mediaId):
                return ["command":stageName, "media_id": mediaId]
            case .status(let status, let mediaId):
                return ["status": status, "wrap_links": "true", "media_ids": mediaId]
            }
        }
    }

    var stageName: String {
        get {
            switch self {
            case .initial:
                return "INIT"
            case .append:
                return "APPEND"
            case .finalize:
                return "FINALIZE"
            case .status:
                return "STATUS"

            }
        }
    }

    var videoChunk: Data? {
        switch self {
        case .append(_ , let videoData, let segment):
            if videoData.count > UploadStage.videoChunkMaxSize {
                let maxPos = segment * UploadStage.videoChunkMaxSize + UploadStage.videoChunkMaxSize
                let range: Range<Data.Index> = segment * UploadStage.videoChunkMaxSize..<(maxPos >= videoData.count ? videoData.count : maxPos)
                return videoData.subdata(in: range)

            }
            return videoData
        default:
            return nil
        }
    }

    var urlString: String {
        switch self {
        case .initial, .append, .finalize:
            return "https://upload.twitter.com/1.1/media/upload.json"
        case .status:
            return "https://api.twitter.com/1.1/statuses/update.json"
        }
    }
}

通过传递下一阶段枚举值,可以在具有递归调用的方法中使用UploadStage枚举:

func uploadTwitterVideo(videoData: Data, status: String, stage: UploadStage, success: @escaping () -> Void, failure: @escaping (Error?) -> Void) {

    let client = TWTRAPIClient.withCurrentUser()

    var clientError: NSError?
    let urlRequest = client.urlRequest(withMethod: "POST", urlString: stage.urlString, parameters: stage.parameters, error: &clientError)
    if clientError == nil {
        client.sendTwitterRequest(urlRequest) { (urlResponse, responseData, connectionError) in

            guard connectionError == nil else {
                print("There was an error: \(connectionError!.localizedDescription)")
                failure(connectionError)
                return
            }

            self.handleError(urlResponse, failure: failure)
            if let data = responseData, let dataString = String(data: data, encoding: .utf8), let urlResponse = urlResponse {
                print("Twitter stage \(stage.stageName) URL response : \(urlResponse), response data: \(dataString)")


                var nextStage: UploadStage?
                do {
                    switch stage {
                    case .initial:
                        let returnedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String:Any]
                        if let mediaId = returnedJSON["media_id_string"] as? String {
                            print("stage one success, mediaID -> \(mediaId)")
                            nextStage = .append(mediaId: mediaId, videoData:videoData, segment: 0)
                        }
                    case .append(let mediaId, let videoData, let segment):
                        if ((segment + 1) * UploadStage.videoChunkMaxSize < videoData.count) {
                            nextStage = .append(mediaId: mediaId, videoData: videoData, segment: segment + 1)
                        } else {
                            nextStage = .finalize(mediaId: mediaId)
                        }
                    case .finalize(let mediaId):
                        nextStage = .status(status: status, mediaId: mediaId)
                    case .status:
                        success()
                    }

                    if let nextStage = nextStage {
                        self.uploadTwitterVideo(videoData: data, status: status, stage: nextStage, success: success, failure: failure)
                    }
                } catch let error as NSError {
                    failure(error)
                }
            }
        }
    }
}

答案 1 :(得分:2)

我很同情你关于Twitter糟糕的文档。 找出你得到的错误。

以下是我希望它有用的实施说明:

  1. Twitter视频要求: https://dev.twitter.com/rest/public/uploading-media#videorecs
  2. FINALIZE命令根据Twitter视频要求验证视频文件 在完成上传之前。
  3. 如果您收到“HTTP状态400错误请求”,其响应数据包含“媒体无效或不受支持,原因:不支持的媒体”。发送FINALIZE命令后出错,您需要使用Twitter视频要求验证您的视频文件。
  4. 查看我的项目https://github.com/mtrung/TwitterVideoUpload。我知道它在Obj-C中但它有效。