Swift - 将视频上传到Twitter时请求状态为400

时间:2018-04-24 07:12:41

标签: ios swift twitter

我正在尝试上传即使用我的设备分享视频到Twitter。到目前为止,我已经使用了以下代码来做到这一点。

     // video Upload

    func requestAccessToTwitterAccount(videoURL:NSURL,fileSize:UInt32){

        let accountStore = ACAccountStore()
        let twitterAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
        accountStore.requestAccessToAccounts(with: twitterAccountType, options: nil) { (granted, error) in

            if granted {
                let accounts = accountStore.accounts(with: twitterAccountType)
                if (accounts?.count)! > 0 {
                    self.twitterAccount = accounts?.last as! ACAccount
                    self.uploadVideoToTwitter(videoURL: videoURL, fileSize: fileSize)
                }
            else{
                    let error = "Please set your twitter account in Settings."
                    print(error)
                }
            }
        else {
            print("App permissions are disabled in device twitter settings, please enable it.")
        }
    }
}
    func uploadVideoToTwitter(videoURL:NSURL,fileSize: UInt32){
        print(videoURL.path!)
        if let videoData = NSData(contentsOfFile: videoURL.path!){

            self.tweetVideoInit(videoData: videoData, videoSize: Int(fileSize))
        }else{
            print("Something Wrong")
        }
    }

    func tweetVideoInit(videoData:NSData,videoSize:Int) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "INIT"
        params["total_bytes"]  = String(videoData.length)
        params["media_type"]  = "video/MOV"

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(error!)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {

                        if let tweetID = dictionary["media_id_string"] as? String{
                            self.tweetVideoApped(videoData: videoData, videoSize: videoSize, mediaId: tweetID, chunk: 0)
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }



    func tweetVideoApped(videoData:NSData,videoSize:Int ,mediaId:String,chunk:NSInteger) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "APPEND"
        params["media_id"]  = mediaId
        params["segment_index"]  = String(chunk)

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.addMultipartData(videoData as Data!, withName: "media", type: "video/mov", filename:"mediaFile")

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(err)

            }else{
                self.tweetVideoFinalize(mediaId: mediaId)
            }
        })
    }

    func tweetVideoFinalize(mediaId:String) {
        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()
        params["command"] = "FINALIZE"
        params["media_id"]  = mediaId

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        self.postStatus(mediaId: mediaId)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatus(mediaId:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:String]()
        //params["status"] = twitterDescription
        params["media_ids"]  = mediaId

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in

            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

现在问题就是这样,我不确定问题出在哪里,但当我尝试上传的视频少于10 secs时,它已上传成功,但是当我尝试超过10秒的视频会在请求状态400 时出现错误,并且视频无法上传。

注意:我的视频格式为 .MOV ,大​​小约为 6.4MB 。所以我想根据Twitter的视频上传指南接受它。

仅供参考: - 我也提到了此链接 - Twitter Upload Demo

  

此外,Official Documentation表示以下限制   我不会超过。

enter image description here

有人可以帮我解决这个问题的原因。

2 个答案:

答案 0 :(得分:1)

这是我之前使用的代码,对我来说效果很好。试试这个

let account = ACAccountStore()
            let accountType = account.accountType(
                withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)

            account.requestAccessToAccounts(with: accountType, options: nil,
                                            completion: {(success, error) in

                                                if success {
                                                    let arrayOfAccounts =
                                                        account.accounts(with: accountType)

                                                    if (arrayOfAccounts?.count)! > 0 {
                                                        let twitterAccount = arrayOfAccounts?.last as! ACAccount
                                                        let message = “your text here”
                                                        print(twitterAccount)


                                                        self.socialVideo.uploadTwitterVideo(self.coachController?.videoData as Data!, comment: message, account: twitterAccount, withCompletion: { (success, value) in


                                                            if success == true {

                                                                self.showToast(message: "Uploaded Succesfully")
                                                            }

                                                        })
                                                    }
                                                }
            })

链接下载SocialVideo Helper - > https://github.com/liu044100/SocialVideoHelper

答案 1 :(得分:0)

研究Docs后没有找到任何办法。对我有用的东西就像Compressing视频。

我使用以下代码压缩视频并将其转换为.m4v格式以及它如何对我有用。

  

注意:上传视频的限制为 15MB 30秒最高

将视频上传到Twitter的完整代码是:

func imagePickerController(_ picker: UIImagePickerController,
                           didFinishPickingMediaWithInfo info: [String : Any])
{
    if  let video = info[UIImagePickerControllerMediaURL] as? URL{
        let asset = AVURLAsset(url: video)
        let durationInSeconds = asset.duration.seconds
        print(durationInSeconds)

        if durationInSeconds < 30{
            arrImageURL.removeAll()
            btnSelectImage.setBackgroundImage(nil, for: .normal)
            btnSelectImage.setTitle("Select Image to attach", for: .normal)
            videoURL = video
            print(videoURL)
            let innerVideoURL = video
            let data = NSData(contentsOf: innerVideoURL as URL)!
            print("File size before compression: \(Double(data.length / 1048576)) mb")
            let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".m4v")
            compressVideo(inputURL: innerVideoURL , outputURL: compressedURL) { (exportSession) in
                guard let session = exportSession else {
                    return
                }

                switch session.status {
                case .unknown:
                    break
                case .waiting:
                    break
                case .exporting:
                    break
                case .completed:
                    self.videoURL = compressedURL
                case .failed:
                    break
                case .cancelled:
                    break
                }
            }
        }else{
            showAlertWithTitle(title: "Alert!", message: "Video Length cannot be more that 30Sec to upload!")
        }

    }
    picker.dismiss(animated: true, completion: nil);
}

func compressVideo(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
        let urlAsset = AVURLAsset(url: inputURL, options: nil)
        guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
            handler(nil)
            return
        }

        exportSession.outputURL = outputURL
        exportSession.outputFileType = AVFileType.mov
        exportSession.shouldOptimizeForNetworkUse = true
        exportSession.exportAsynchronously { () -> Void in
            handler(exportSession)
        }
    }

然后按顺序调用以下方法上传视频:

    // video Upload

    func requestAccessToTwitterAccount(videoURL:NSURL,fileSize:UInt32){

        let accountStore = ACAccountStore()
        let twitterAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
        accountStore.requestAccessToAccounts(with: twitterAccountType, options: nil) { (granted, error) in

            if granted {
                let accounts = accountStore.accounts(with: twitterAccountType)
                if (accounts?.count)! > 0 {
                    self.twitterAccount = accounts?.last as! ACAccount
                    self.uploadVideoToTwitter(videoURL: videoURL, fileSize: fileSize)
                }
            else{
                    let error = "Please set your twitter account in Settings."
                    print(error)
                }
            }
        else {
            print("App permissions are disabled in device twitter settings, please enable it.")
        }
    }
}
    func uploadVideoToTwitter(videoURL:NSURL,fileSize: UInt32){
        print(videoURL.path!)
        if let videoData = NSData(contentsOfFile: videoURL.path!){

            self.tweetVideoInit(videoData: videoData, videoSize: Int(fileSize))
        }else{
            print("Something Wrong")
        }
    }

    func tweetVideoInit(videoData:NSData,videoSize:Int) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "INIT"
        params["total_bytes"]  = String(videoData.length)
        params["media_type"]  = "video/m4v"

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if error != nil {
                print(error!)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        if let tweetID = dictionary["media_id_string"] as? String{
                            self.tweetVideoApped(videoData: videoData, videoSize: videoSize, mediaId: tweetID, chunk: 0)
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }



    func tweetVideoApped(videoData:NSData,videoSize:Int ,mediaId:String,chunk:NSInteger) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "APPEND"
        params["media_id"]  = mediaId
        params["segment_index"]  = String(chunk)

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.addMultipartData(videoData as Data!, withName: "media", type: "video/m4v", filename:"mediaFile")

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)

            }else{
                self.tweetVideoFinalize(mediaId: mediaId)
            }
        })
    }

    func tweetVideoFinalize(mediaId:String) {
        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()
        params["command"] = "FINALIZE"
        params["media_id"]  = mediaId

         print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        if self.videoURL != nil{
                            self.postStatusVideo(mediaId: mediaId)
                        }else{
                            print("Image Post Called")
                            if self.arrMediaIdString.count == self.arrImage.count{
                                self.postStatusMultipleImages(arrMediaId: self.arrMediaIdString, statusText: "Demo Multi Images")
                            }
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatusMultipleImages(arrMediaId:[String],statusText:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:Any]()
        params["status"] = statusText
        params["media_ids"]  = arrMediaId

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatusVideo(mediaId:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:String]()
        params["status"] = "Testing Video"
        params["media_ids"]  = mediaId

         print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
           print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

最后像这样使用它:

var fileSizeValue = getVideoSize(contentUrl: videoURL)
requestAccessToTwitterAccount(videoURL: videoURL as NSURL, fileSize: UInt32(fileSizeValue))

以及计算视频大小的功能:

func getVideoSize(contentUrl:URL) -> UInt64{
    do {
        let fileAttribute: [FileAttributeKey : Any] = try FileManager.default.attributesOfItem(atPath: contentUrl.path)
        if let fileNumberSize: NSNumber = fileAttribute[FileAttributeKey.size] as? NSNumber {
            return UInt64(truncating: fileNumberSize)
        }
    } catch {
        print(error.localizedDescription)
    }
   return 0
}

希望这有帮助。