14

I would upload a video using the Youtube API v3 with curl in PHP, as described here: https://developers.google.com/youtube/v3/docs/videos/insert

I've this function

function uploadVideo($file, $title, $description, $tags, $categoryId, $privacy)
{
    $token = getToken(); // Tested function to retrieve the correct AuthToken

    $video->snippet['title']         = $title;
    $video->snippet['description']   = $description;
    $video->snippet['categoryId']    = $categoryId;
    $video->snippet['tags']          = $tags; // array
    $video->snippet['privacyStatus'] = $privacy;
    $res = json_encode($video);

    $parms = array(
        'part'  => 'snippet',
        'file'  => '@'.$_SERVER['DOCUMENT_ROOT'].'/complete/path/to/'.$file
        'video' => $res
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://www.googleapis.com/upload/youtube/v3/videos');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $parms);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer '.$token['access_token']));
    $return = json_decode(curl_exec($ch));
    curl_close($ch);

    return $return;
}

But it returns this

stdClass Object
(
    [error] => stdClass Object
        (
            [errors] => Array
                (
                    [0] => stdClass Object
                        (
                            [domain] => global
                            [reason] => badContent
                            [message] => Unsupported content with type: application/octet-stream
                        )

                )

            [code] => 400
            [message] => Unsupported content with type: application/octet-stream
        )

)

The file is an MP4.

Anyone can help?

genna
  • 461
  • 1
  • 6
  • 17

4 Answers4

26

Updated version: Now with custom upload url and sending of metadata with the upload process. The entire process requires 2 requests:

  1. Get a custom upload location

    First, make a POST request for an upload url to:

    "https://www.googleapis.com/upload/youtube/v3/videos"
    

    You will need to send 2 headers:

    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}"
    "Content-type": "application/json"
    

    You need to send 3 parameters:

    "uploadType": "resumable"
    "part": "snippet, status"
    "key": {YOUR_API_KEY}
    

    And you will need to send the metadata for the video in the request body:

        {
            "snippet": {
                "title": {VIDEO TITLE},
                "description": {VIDEO DESCRIPTION},
                "tags": [{TAGS LIST}],
                "categoryId": {YOUTUBE CATEGORY ID}
            },
            "status": {
                "privacyStatus": {"public", "unlisted" OR "private"}
            }
        }
    

    From this request you should get a response with a "location" field in the headers.

  2. POST to custom location to send file.

    For the upload you need 1 header:

    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}"
    

    And send the file as your data/body.

If you read through how their client works you will see they recommend retrying if you are returned errors of code 500, 502, 503, or 504. Clearly you will want to have a wait period between retries and a max number of retries. It works in my system every time, though I am using python & urllib2 instead of cURL.

Also, because of the custom upload location this version is upload resumable capable, though I have yet to need that.

Chad Befus
  • 1,918
  • 1
  • 18
  • 18
  • 1
    I also had problem to set parameters with POST upload request, did you still use 2 requests to upload and update meta data ? – hsafarya Jun 19 '13 at 18:06
  • I don't anymore. I have changed my method for this to something much more stable and I will edit my answer to the new method. – Chad Befus Jun 26 '13 at 23:07
  • @ChadBefus Are the three parameters part of the header or the body or are they part of the URL as queries? – Supertecnoboff May 30 '14 at 11:24
  • @ChadBefus I just get the response "Not found". Do you know whats wrong? – Supertecnoboff May 30 '14 at 13:42
  • 1
    @ChadBefus I'd just like tho thank you sir. I have been following this post as a guide for a video POST request to YouTube from my iOS Application and it works an absolute treat. Thank you :) – Supertecnoboff May 30 '14 at 15:42
  • I had to set the Content-Type to video/* to get this to work as it kicks up an error otherwise. – daamsie Apr 20 '16 at 04:35
  • The second request uses PUT, not POST. All the information about resumable uploads are explained here: https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol – Pierre Mar 14 '19 at 13:39
  • Just a small note that in the first request the URL returned is in the Header, not body. Look for 'x-guploader-uploadid' in the header – Brett Mar 10 '23 at 02:15
1

Unfortunately, we don't have a specific example of YouTube API v3 uploads from PHP available yet, but my general advice is:

  • Use the PHP client library instead of cURL.
  • Base your code on this example written for the Drive API. Because the YouTube API v3 shares a common API infrastructure with other Google APIs, examples for doing things like uploading files should be very similar across different services.
  • Take a look at the Python example for the specific metadata that needs to be set in a YouTube v3 upload.

In general, there are a lot of things incorrect with your cURL code, and I can't walk through all the steps it would take to fix it, as I think using the PHP client library is a much better option. If you are convinced you want to use cURL then I'll defer to someone else to provide specific guidance.

Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167
  • Thanks! My attempt was to make something lighter, but I'll try the official Google library – genna Nov 08 '12 at 09:05
  • In the Google_YoutubeService.php I can't find a function to call the insert method I need for. All methods are for listing ( channels, playlists, videos .. ) I have to wait for a newer version of the library? – genna Nov 08 '12 at 10:43
  • I've decided to use the Zend_Gdata_YouTube and the 2nd version of the API, due to the lack of the methods I need for – genna Nov 08 '12 at 15:09
  • You can use the Zend client library and v2 of the API if you'd like, sure. Here's the method to use with v3 of the API, though: https://code.google.com/p/google-api-php-client/source/browse/trunk/src/contrib/Google_YoutubeService.php#257 – Jeff Posnick Nov 08 '12 at 16:39
0

a python script:

# categoryId is '1' for Film & Animation
# to fetch all categories: https://www.googleapis.com/youtube/v3/videoCategories?part=snippet&regionCode={2 chars region code}&key={app key}
meta =  {'snippet': {'categoryId': '1',
  'description': description,
  'tags': ['any tag'],
  'title': your_title},
  'status': {'privacyStatus': 'private' if private else 'public'}}

param = {'key': {GOOGLE_API_KEY},
         'part': 'snippet,status',
         'uploadType': 'resumable'}

headers =  {'Authorization': 'Bearer {}'.format(token),
           'Content-type': 'application/json'}

#get location url
retries = 0
retries_count = 1
while retries <= retries_count: 
    requset = requests.request('POST', 'https://www.googleapis.com/upload/youtube/v3/videos',headers=headers,params=param,data=json.dumps(meta))
    if requset.status_code in [500,503]:
        retries += 1
    break

if requset.status_code != 200:
    #do something

location = requset.headers['location']

file_data = open(file_name, 'rb').read()

headers =  {'Authorization': 'Bearer {}'.format(token)}

#upload your video
retries = 0
retries_count = 1
while retries <= retries_count:
    requset = requests.request('POST', location,headers=headers,data=file_data)
    if requset.status_code in [500,503]:
        retries += 1
    break

if requset.status_code != 200:
    #do something

# get youtube id
cont = json.loads(requset.content)            
youtube_id = cont['id']
Eyal Ch
  • 9,552
  • 5
  • 44
  • 54
0

I have been able to upload a video to my channel on YouTube using the following shell script.

#!/bin/sh

# Upload the given video file to your YouTube channel.

cid_base_url="apps.googleusercontent.com"
client_id="<YOUR_CLIENT_ID>.$cid_base_url"
client_secret="<YOUR_CLIENT_SECRET>"
refresh_token="<YOUR_REFRESH_TOKEN>"
token_url="https://accounts.google.com/o/oauth2/token"
api_base_url="https://www.googleapis.com/upload/youtube/v3"
api_url="$api_base_url/videos?uploadType=resumable&part=snippet"

access_token=$(curl -H "Content-Type: application/x-www-form-urlencoded" -d refresh_token="$refresh_token" -d client_id="$client_id" -d client_secret="$client_secret" -d grant_type="refresh_token" $token_url|awk -F '"' '/access/{print $4}')

auth_header="Authorization: Bearer $access_token"
upload_url=$(curl -I -X POST -H "$auth_header" "$api_url"|awk -F ' |\r'  '/loc/{print $2}'); curl -v -X POST --data-binary "@$1" -H "$auth_header" "$upload_url"

Refer to the this similar question for how to get your custom variable values.

dardo82
  • 77
  • 1
  • 6