Uploading Video File on Google Drive to YouTube with Resumable Upload using Google Apps Script

Gists

Uploading Video File on Google Drive to YouTube with Resumable Upload using Google Apps Script

This is a simple sample script for uploading a video file on Google Drive to YouTube with the resumable upload using Google Apps Script.

When you want to upload a video file to YouTube using Google Apps Script, when YouTube API of Advanced Google services is used, the maximum file size is 5 MB, because, in this case, the video file is uploaded with multipart/form-data. When you want to use a video file with more file size using Google Apps Script, a resumable upload is required to be used. But, unfortunately, in the current stage, the methods of Google Apps Script for uploading large video files are not prepared. And also, when I saw the document of resumable upload on YouTube in the official document, I thought that it might be a bit complicated for understanding the resumable upload process. Ref So, in this post, I would like to introduce a simple sample script for uploading video data of more than 5 MB with the resumable upload using Google Apps Script. In this case, the video file is existing in Google Drive. The video file on Google Drive is uploaded to YouTube using Google Apps Script. When this sample script will help you understand the resumable upload of YouTube, I’m glad.

I have uploaded a file to Google Drive using the resumable upload with Drive API. This experience helped me understand the resumable upload of video data to YouTube.

Usage

1. Upload a video file to Google Drive.

Please upload a sample video file to your Google Drive. In this sample script, the video data of the video file on Google Drive is uploaded to YouTube using Google Apps Script.

2. Create a Google Apps Script project.

Please create a Google Apps Script project. In this case, you can use both the standalone type and the container-bound script type.

3. Enable APIs.

This sample script used Drive API and YouTube API. So, please enable them at Advanced Google services.

4. Sample script.

Please copy and paste the following sample script to the script editor of Google Apps Script.

function myFunction() {
  // Please set the file ID of video file and the metadata for uploading it to YouTube.
  const fileId = "###";
  const metadata = {
    snippet: { description: "Upload sample.", title: "Sample uploaded video." },
    status: { privacyStatus: "private" },
  };

  // 1. Retrieve location.
  const headers = { authorization: "Bearer " + ScriptApp.getOAuthToken() };
  const url1 = encodeURI(
    "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status"
  );
  const res1 = UrlFetchApp.fetch(url1, {
    headers,
    payload: JSON.stringify(metadata),
    contentType: "application/json",
    muteHttpExceptions: true,
  });
  if (res1.getResponseCode() != 200) {
    console.log(res1.getContentText());
    return;
  }
  const location = res1.getAllHeaders()["Location"];
  console.log("Got Location.");

  // 2. Calculate chunks.
  const chunkSize = 20971520; // 20 MB
  const { fileSize } = Drive.Files.get(fileId, {
    supportsAllDrives: true,
    fields: "fileSize",
  });
  const chunks = [...Array(Math.ceil(fileSize / chunkSize))].map((_, i, a) => [
    i * chunkSize,
    i == a.length - 1 ? fileSize - 1 : (i + 1) * chunkSize - 1,
  ]);
  console.log("Calculated chunk data.");

  // 3. Retrieve chunks from Google Drive with the partial download and uploading chunks to YouTube with the resumable upload.
  const url2 = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media&supportsAllDrives=true`;
  let res2;
  const len = chunks.length;
  chunks.forEach((e, i) => {
    console.log(`Now... ${i + 1}/${len}`);
    const params2 = {
      headers: {
        authorization: headers.authorization,
        range: `bytes=${e[0]}-${e[1]}`,
      },
    };
    res2 = UrlFetchApp.fetch(url2, params2).getContent();
    const params3 = {
      headers: { "Content-Range": `bytes ${e[0]}-${e[1]}/${fileSize}` },
      payload: res2,
      muteHttpExceptions: true,
    };
    console.log("Downloaded a chunk, and upload a chunk.");
    const res3 = UrlFetchApp.fetch(location, params3);
    const statusCode = res3.getResponseCode();
    if (statusCode == 200) {
      console.log("Done.");
      console.log(res3.getContentText());
    } else if (statusCode == 308) {
      console.log("Upload the next chunk.");
      res2.splice(0, res2.length);
    } else {
      throw new Error(res3.getContentText());
    }
  });

  // Please don't remove the following comment line. This comment line is important for running this script.
  // YouTube.Videos.insert(); // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/youtube" with the script editor.
}

5. Testing

When this script is run, you can see the following process in the log.

Got Location.
Calculated chunk data.
Now... 1/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 2/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 3/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 4/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 5/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 6/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 7/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 8/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 9/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 10/10
Downloaded a chunk, and upload a chunk.
Done.
{
  "kind": "youtube#video",
  "etag": "###",
  "id": "###",
  "snippet": {,,,},
  "status": {,,,}
}

IMPORTANT

References

Testing

 Share!