Skip to content

Instantly share code, notes, and snippets.

@soygul
Last active October 16, 2024 18:16
Show Gist options
  • Save soygul/42677432fa89df7fd783e0232a43a8cf to your computer and use it in GitHub Desktop.
Save soygul/42677432fa89df7fd783e0232a43a8cf to your computer and use it in GitHub Desktop.
YouTube video uploader using JavaScript and Node.js
// YouTube API video uploader using JavaScript/Node.js
// You can find the full visual guide at: https://www.youtube.com/watch?v=gncPwSEzq1s
// You can find the brief written guide at: https://quanticdev.com/articles/automating-my-youtube-uploads-using-nodejs
//
// Upload code is adapted from: https://developers.google.com/youtube/v3/quickstart/nodejs
const fs = require('fs');
const readline = require('readline');
const assert = require('assert')
const {google} = require('googleapis');
const OAuth2 = google.auth.OAuth2;
// video category IDs for YouTube:
const categoryIds = {
Entertainment: 24,
Education: 27,
ScienceTechnology: 28
}
// If modifying these scopes, delete your previously saved credentials in client_oauth_token.json
const SCOPES = ['https://www.googleapis.com/auth/youtube.upload'];
const TOKEN_PATH = '../' + 'client_oauth_token.json';
const videoFilePath = '../vid.mp4'
const thumbFilePath = '../thumb.png'
exports.uploadVideo = (title, description, tags) => {
assert(fs.existsSync(videoFilePath))
assert(fs.existsSync(thumbFilePath))
// Load client secrets from a local file.
fs.readFile('../client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the YouTube API.
authorize(JSON.parse(content), (auth) => uploadVideo(auth, title, description, tags));
});
}
/**
* Upload the video file.
*
* @param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function uploadVideo(auth, title, description, tags) {
const service = google.youtube('v3')
service.videos.insert({
auth: auth,
part: 'snippet,status',
requestBody: {
snippet: {
title,
description,
tags,
categoryId: categoryIds.ScienceTechnology,
defaultLanguage: 'en',
defaultAudioLanguage: 'en'
},
status: {
privacyStatus: "private"
},
},
media: {
body: fs.createReadStream(videoFilePath),
},
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
console.log(response.data)
console.log('Video uploaded. Uploading the thumbnail now.')
service.thumbnails.set({
auth: auth,
videoId: response.data.id,
media: {
body: fs.createReadStream(thumbFilePath)
},
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
console.log(response.data)
})
});
}
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
const clientSecret = credentials.installed.client_secret;
const clientId = credentials.installed.client_id;
const redirectUrl = credentials.installed.redirect_uris[0];
const oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* @param {Object} token The token to store to disk.
*/
function storeToken(token) {
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) throw err;
console.log('Token stored to ' + TOKEN_PATH);
});
}
@soygul
Copy link
Author

soygul commented Jul 15, 2021

It works fine for me as of today.

@rzfzr
Copy link

rzfzr commented Jul 15, 2021

Thanks for the reply, interesting as I've reverted back to your code and still had the same issue, I'll try a different account.
Thanks again

@BenceBakos
Copy link

BenceBakos commented Dec 7, 2022

I'm getting Authorize this app by visiting this url:...

And when I try to autorize, it's

Access blocked: test has not completed the Google verification process

Clearly, I miss something on console.cloud.google.com/apis/credentials, but what's that?


Solution:
https://www.youtube.com/watch?v=bkZns_VOB6I

I had to add a test email on Oauth consent screen. (I tought I alreday added one)

@soygul
Copy link
Author

soygul commented Dec 14, 2022

You need to do the authorization using the project owner's account. Or else, you can add a test user and test things that way as you did.

@jivanmainali
Copy link

If you are using oauth2 and already handling token creation part then here is a working snippet for uploading videos to youtube

const fs = require('fs');
const { google } = require('googleapis');

const categoryIds = {
Entertainment: 24,
Education: 27,
ScienceTechnology: 28
}
const videoFilePath = './videoplayback.mp4'
const thumbFilePath = '../thumb.png'

function uploadVideo(auth, title, description, tags) {
let oauth2Client = new google.auth.OAuth2("158953543582-aikird8t9gm85t1mlg972204l0rhdnlj.apps.googleusercontent.com", "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", "localhost");
oauth2Client.setCredentials({ access_token: "ya29.a0AfB_byDv8Y6KR9mN1MO-ZggytPWRaJpR5Doj_WlqaeCmaH39ZbHeFpKWxo4zX36NpoWfYdYaupo1qhzO119foe-e9_Gm0Fz9ctUZ9l9H3Y3fllyuIb1j8sJPWgWMYXWAUNXaKuiMn0nTBzfWjvz4MMtN24isM3V1OZvfaCgYKAZESARASFQHGX2MimMwiIh_IYu8cvcAEQs9GLg0171" });

const service = google.youtube({
    version: 'v3',
    auth: oauth2Client
});
// const oauth2Client = new OAuth2("158953543582-aikird8t9gm85t1mlg972204l0rhdnlj.apps.googleusercontent.com", "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", "localhost");

// oauth2Client.setCredentials({
//     access_token: "ya29.a0AfB_byBlkvayDllVA0bwvqiDj_TLfGJskEcqpYEGwWgDxTp54XdPdU35CUek7cSo5J3V5XAcxS4bL7DPXG4wCM-fNFzNEdy4nrGp5nXYyQMCaOZ6ID-F9aFW2QkkFkc8WbhPlfpQBULDwZwooaqkuFt3NJ2lB7Fi-OCRaCgYKASoSARASFQHGX2Mi6zCK61ySM_w9KpCuLJRsPg0171"
// })

service.videos.insert({
    auth: oauth2Client,
    // auth: {
    //     access_token: "ya29.a0AfB_byBlkvayDllVA0bwvqiDj_TLfGJskEcqpYEGwWgDxTp54XdPdU35CUek7cSo5J3V5XAcxS4bL7DPXG4wCM-fNFzNEdy4nrGp5nXYyQMCaOZ6ID-F9aFW2QkkFkc8WbhPlfpQBULDwZwooaqkuFt3NJ2lB7Fi-OCRaCgYKASoSARASFQHGX2Mi6zCK61ySM_w9KpCuLJRsPg0171"
    // },
    // auth: "ya29.a0AfB_byBlkvayDllVA0bwvqiDj_TLfGJskEcqpYEGwWgDxTp54XdPdU35CUek7cSo5J3V5XAcxS4bL7DPXG4wCM-fNFzNEdy4nrGp5nXYyQMCaOZ6ID-F9aFW2QkkFkc8WbhPlfpQBULDwZwooaqkuFt3NJ2lB7Fi-OCRaCgYKASoSARASFQHGX2Mi6zCK61ySM_w9KpCuLJRsPg0171",
    part: 'snippet,status',
    requestBody: {
        snippet: {
            title,
            description,
            tags,
            categoryId: categoryIds.ScienceTechnology,
            defaultLanguage: 'en',
            defaultAudioLanguage: 'en'
        },
        status: {
            privacyStatus: "private"
        },
    },
    media: {
        body: fs.createReadStream(videoFilePath),
    },
}, function (err, response) {
    if (err) {
        console.log('The API returned an error: ' + err);
        return;
    }
    console.log(response.data)

    console.log('Video uploaded. Uploading the thumbnail now.')
    service.thumbnails.set({
        auth: auth,
        videoId: response.data.id,
        media: {
            body: fs.createReadStream(thumbFilePath)
        },
    }, function (err, response) {
        if (err) {
            console.log('The API returned an error: ' + err);
            return;
        }
        console.log(response.data)
    })
});

}

uploadVideo("", "title num1", "desc denge abhi", "hashta chalega")

@Shujaagideon
Copy link

After following the provided url to login and performing all the steps , I get redirected to a localhost page but it just says " this site can't be reached" please help

@yachinyou
Copy link

@Shujaagideon I ran into the same problem too. "this site can't be reached" page is meant to be that way. Look into the URL that says "http://localhost/?code=**ThisIsTheCode**&scope=https://www.googleapis.com/auth/youtube.upload" copy the code portion and paste into the command line to proceed. It took me a while to realize that's what they wanted. Hope this helps!

@IbrahimMarzaq
Copy link

It doesn't work for me
any help pleaze.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment