RESTful mechanism to upload video (and properties)

2019-08-13 22:10发布

The procedure to upload a video to Vimeo starts out very similarly as the one defined for Youtube, but only up to a point. Below I describe the steps that worked, and outline the last video-upload step which does not:

The Vimeo-upload dance begins when we pass the following parameters to trigger user authentication:

let authPath:String = "\(url_vauth)?response_type=\(response_type)&client_id=\(client_id)&redirect_uri=\(redirect_uri)&state=\(state)&scope=upload"

if let authURL:NSURL = NSURL(string: authPath) {
  let request = NSURLRequest(URL: authURL)
  webView.loadRequest(request)  // opens a webpage in a webUIView

  // once credentials are entered, google redirects back with the above uri + a temporary code
  // we will exchange later for a token

  // within AppDelegate, we have defined a way to handle this uri, which is to call
  // processOAuthStep1Response(url)

Then, we process the returned response to extract an authorization code:

let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: false)
var auth_code:String!
// the block below extracts the text that follows "code" in the return url

if let queryItems = components?.queryItems {
  for queryItem in queryItems { // step through each part of url
    if queryItem.name.lowercaseString == "code" {
      auth_code = queryItem.value
      break
    } //  end of if queryItem.name.lowercaseString
  } // end of for
} // if let queryItems

With this authorization code, we then generate a token:

  let getTokenPath:String = url_token
  let grant_type = "authorization_code"
  let header_plain = "\(client_id):\(client_secret)"
  let string_plain = header_plain.dataUsingEncoding(NSUTF8StringEncoding)
  let string_base64 = (string_plain?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)))! as String
  let headers = ["Authorization": "basic \(string_base64)"]  // note that string_base64 really needs to be in base64!
  //print ("...header is: \(string_base64)")
  let tokenParams = ["grant_type": grant_type, "code": receivedCode, "redirect_uri": redirect_uri, "scope": "public"]
  let request = Alamofire.request(.POST, getTokenPath, parameters: tokenParams, encoding: .URL, headers: headers)

We use this token to generate a ticket:

request(.POST, url_getticket, parameters: ticketParams , encoding: .URL, headers: headers).responseJSON { response  in
  //print(response)
  switch response.result {
  case .Success(let data):
    let json = JSON(data)
    print (json)
    let myticket = json["ticket_id"].stringValue
    //let usage = json[("upload_quota")].stringValue
    let htmlform = json[("form")].stringValue
    let uploadlink = json[("upload_link_secure")].stringValue
    print("......ticket is \(myticket)")
    print("......form is \(htmlform)")
    print("......upload link is \(uploadlink)")
  case .Failure(let error):
    print("Request failed with error: \(error)")
  } // end of switch

Finally (and this is where things stop to a screeching halt) we are supposed to use this ticket to make a POST request to Vimeo. The problem is that this ticket is embedded in an html form that actually makes the upload request to Vimeo...Not very useful for the iOS platform where I'm trying to implement this. Ideally, I'd like implementing with Alamofire via an upload call like so:

  let headers = ["Authorization": "Bearer \(token)"]
  upload(
      .POST,
      "https://1511923767.cloud.vimeo.com/upload?ticket_id=#######&video_file_id=####&signature=####&v6=1&redirect_url=https%3A%2F%2Fvimeo.com%2Fupload%2Fapi%3Fvideo_file_id%3D498216063%26app_id%3D70020%26ticket_id%####%26signature%######", 
      headers: headers,
      multipartFormData: { multipartFormData in
        multipartFormData.appendBodyPart(data: videodata, name: "video", fileName: "bagsy.m4v", mimeType: "application/octet-stream")
      },
      encodingCompletion: { encodingResult in
        switch encodingResult {
        case .Success(let upload, _, _):
          upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
            dispatch_async(dispatch_get_main_queue()) {
              let percent = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
              //progress(percent: percent)
              print ("................\(percent)")
            }
          }
          upload.validate()
          upload.responseJSON { response in
            print(response)
            callback(true)
          }
        case .Failure(_):
          callback(false)
        }

    })

Needless to say, the chunk of code above does not work. Any guidance would be most appreciated.

2条回答
老娘就宠你
2楼-- · 2019-08-13 22:45

The ticket is never manually used in an upload. You should always use the url, or html provided by the API.

If you see HTML, it's because you are not providing the "type" parameter. We default to a simple POST upload system as described here: https://developer.vimeo.com/api/upload/videos#simple-http-post-uploading

If you provide "type=streaming", Vimeo returns a "complete_url", which you must call after performing the streaming upload as described here: https://developer.vimeo.com/api/upload/videos#resumable-http-put-uploads

查看更多
Juvenile、少年°
3楼-- · 2019-08-13 23:03

Consider using the official Vimeo iOS Upload SDK. We made it public about 2 weeks ago. It's a Swift library that handles upload of video files to Vimeo servers. It does so using a background-configured NSURLSession (so uploads continue regardless of whether your app is in the foreground or background). Let us know if you have any questions. Note: I'm one of the authors of the library and I work at Vimeo.

The VimeoUpload README is pretty robust and should communicate all that you need to know. Lettuce know if you have additional questions though, or feel free to make a pull request.

查看更多
登录 后发表回答