Ionică Bizău

Web Developer, Linux geek and Musician

Uploading videos to YouTube using NodeJS

Using different service APIs may be difficult, especially for beginners, but not only. In this post, I will try to make clearer how to upload a video on YouTube, using NodeJS.

Back in 2013 I published my first NPM module: youtube-api–an object-oriented wrapper for the YouTube v3 API. People liked this module and the feedback came. Contributions, bug reports, stars etc. That means people actually used my module which is incredible. :dizzy:

So, let's suppose you have a video file (codename: video.mp4) and you want to upload it on your YouTube account. While there are a couple of authenticating methods (JWT, OAuth2, Server Key etc), to upload videos on YouTube, you need OAuth2 authentication.

The documentation cleary states:

Service accounts do not work for YouTube Data API calls because service accounts require an associated YouTube channel, and you cannot associate new or existing channels with service accounts. If you use a service account to call the YouTube Data API, the API server returns an error with the error type set to unauthorized and the reason set to youtubeSignupRequired.

So, we need OAuth2 authentication. If you are not familiar with OAuth2, you may need to read the docs.

Creating a Google application

Like for other API services, you need to create an application which will be the bridge between you and the API service. To access the YouTube resources, you need to create a Google application.

  1. Open your Google console and create the project by clicking the Create Project button.

  2. Set the project name in the popup that was opened.

  3. After the application is created, go to APIs & auth and click the APIs menu item.

  4. Here you have to enable the YouTube Data API. For that, click the YouTube Data API link and then click the Enable API button.

  5. Before getting the credentials, you have to set the Consent screen information (the product name is mandatory):

  6. Now it's the time to get the application credentials. But there are no credentials yet. You have to create the OAuth2 Client ID. To do that, go to Credentials page and click Create new Client ID. A popup will be opened.

  7. Set the Authorized JavaScript origins–just put http://localhost:5000 because there will run our local server (you may add other origins like development and production urls). The callback url is http://localhost:5000/oauth2callback–after allowing the application to access your account (YouTube resources in this case), you will be redirected there.

  8. After clicking the Create Client ID button, you will get your credentials.

  9. Now click the Download JSON button to download the credentials in JSON format.

Since you have the credentials on your computer, we can now start coding our script. :grinning:

Using youtube-api to upload the video

We will set up a lien server which will handle the OAuth2 callback url.

See the inline comments. It's easier to understand the things.

// YouTube will handle the YouTube API requests
var Youtube = require("youtube-api")

    // We will use `fs` to read the video file
  , Fs = require("fs")

    // `r-json` will read the JSON file (credentials)
  , ReadJson = require("r-json")

    // `lien` handles the server requests (localhost:5000)
  , Lien = require("lien")

    // Logging things
  , Logger = require("bug-killer")

    // Open in the default browser
  , Opn = require("opn")
  ;

// Copy the downloaded JSON file in `credentials.json`
const CREDENTIALS = ReadJson("./credentials.json")
      // Set the video path (it can be any video file)
    , VIDEO_PATH = "video.mp4"
    ;

// Init the lien server
var server = new Lien({
    host: "localhost"
  , port: 5000
});

// Create the stdin interface (prompts)
var stdIn = ReadLine.createInterface({
    input: process.stdin
  , output: process.stdout
});

// Authenticate using the credentials
var oauth = Youtube.authenticate({
    type: "oauth"
  , client_id: CREDENTIALS.web.client_id
  , client_secret: CREDENTIALS.web.client_secret
  , redirect_url: CREDENTIALS.web.redirect_uris[0]
});

// Open the authentication url in the default browser
Opn(oauth.generateAuthUrl({
    access_type: "offline"
  , scope: ["https://www.googleapis.com/auth/youtube.upload"]
}));

// Here we're waiting for the OAuth2 redirect containing the auth code
server.page.add("/oauth2callback", function (lien) {
    Logger.log("Trying to get the token using the following code: " + lien.search.code);

    // Get the access token
    oauth.getToken(lien.search.code, function(err, tokens) {
        if (err) { lien.end(err, 400); return Logger.log(err); }

        // Set the credentials
        oauth.setCredentials(tokens);

        // And finally upload the video! Yay!
        Youtube.videos.insert({
            resource: {
                // Video title and description
                snippet: {
                    title: "Testing YoutTube API NodeJS module"
                  , description: "Test video upload via YouTube API"
                }
                // I don't want to spam my subscribers
              , status: {
                    privacyStatus: "private"
                }
            }
            // This is for the callback function
          , part: "snippet,status"

            // Create the readable stream to upload the video
          , media: {
                body: Fs.createReadStream(VIDEO_PATH)
            }
        }, function (err, data) {
            if (err) { return lien.end(err, 400); }
            lien.end(data);
        });
    });
});

Before running the script, we have to install some dependencies:

$ npm i r-json lien opn bug-killer youtube-api

Then just run the script node your-script.js. You will have to allow your Google application to access your YouTube account and be patient until your video is uploaded. :tada:

Results

If everything runs smoothly, you will see your video in your YouTube account. If you want to play with other YouTube resources check out this playground application.

If you have any questions, ideas or anything, check out the youtube-api package on GitHub and open an issue if the things are still unclear to you.

Happy uploading! :smile:

Read more »

Increasing productivity using Blah 2.0.0

Few months ago I was introducing Blah–one of nicest tools I ever used in module/project development. It helped me a lot. Literally. More than 80% of my projects documentation was generated by this tool.

Recently I started building some new features, working on the 2.0.0 milestone of this project and finally, the 2.0.0 branch was merged. 97 commits, 34 files changed, and 1.659 lines changed (1,197 additions, 462 deletions). Cool, right? Let's see what's hiding behind these numbers.

Blah Help


The new big feature is templates. There are three levels of Blah templates:

  • project templates
  • user templates (located in ~/.blah-templates)
  • default templates (located in the Blah core)

You can read the pull request description if you want to find more technical details. Next, I will present a simple example how to use Blah 2.0.0 or how to automagically not waste your precious time for writing docs.

Installation

Thanks to npm, the installation is easy:

$ npm i -g blah

If this command requires root access, make sure you configured NPM correctly. Using sudo npm i -g blah is not a big issue, anyway.

Creating a project

When starting a project, I create the file structure which looks like below:

$ tree
.
├── example
│   └── index.js
├── lib
│   └── index.js
└── test
    └── index.js

3 directories, 3 files

To create such a thing, do:

$ mkdir hello-blah && cd hello-blah
$ mkdir example lib test
$ touch example/index.js lib/index.js test/index.js
$ git init # if you want to have it as git repo

Starting writing code

I always like to start by writing the example. In this case, let's make a library to display Hello World!

So, I do:

// Require the library file
var HelloBlah = require("../lib");

// Call the function exported by library
HelloBlah();
HelloBlah("Blah");

Obviously, node example/ will fail, because object is not a function–in other words, we didn't export anything in the library file (lib/index.js).

Now we have to write the library file:

/**
* HelloBlah
* Displays and returns a *Hello <world>!* message.
*
* @name HelloBlah
* @function
* @param {String} world The world you want to say *Hello* to (default: `"World"`).
* @return {String} The *Hello <world>!* message.
*/
function HelloBlah(world) {
    world = world || "World";
    var message = "Hello " + world + "!";
    console.log(message);
    return message;
}

module.exports = HelloBlah;

I used jsDoc comments that will help when generating documentation.

Now, since we exported the library function, our tiny example works fine:

$ node example/
Hello World!
Hello Blah!

There is one step before generating the documentation using Blah. Having a package.json file (which is used to publish the library on npm registry) helps Blah:

{
  "name": "blah-test",
  "version": "1.0.0",
  "description": "Testing the new version of blah.",
  "main": "lib/index.js",
  "directories": {
    "example": "example",
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Ionică Bizău <bizauionica@gmail.com> (http://ionicabizau.net)",
  "license": "KINDLY"
}
`

This can be generated using npm init. As you probably noticed, I don't have time to write the tests for this library since it's not the main point of this article.

Using Blah to generate the docs

And now the most exciting part! You have a working library–small, cute, but not awesome enough without documentation. Blah does that for you.

Just run the following command and let the magic happen.

$ blah -c -g -r -l kindly -d lib/index.js

And now what? Blah generated the following files:

  • CONTRIBUTING.md (blah -c or blah --contributing)
  • .gitignore (blah -g or blah --gitignore)
  • README.md (blah -r or blah --readme)
  • LICENSE (blah -l <license-name>)
  • DOCUMENTATION.md (`blah -d path/to/file.js)

And one more point: because it is smart enough, it put your information in the LICENSE file.

Using Blah templates

Most probably Blah used the default templates, in your case. The default templates are a set of defaults that (hopefully) everyone can agree on. Well, I don't. Since I maintain a bunch of projects, I want to have my own documentation format, adding some custom stuff to the default templates.

The Blah templates are written in EJS. Since it EJS lets us to run custom JavaScript code, it's very easy to write our custom stuff. For example I extended the package.json file with the following fields:

{
    "blah": {
        "h_img": "http://example.com/heading-image",
        "ex_img": "http://example.com/example-image"
    }
}

I don't always use it, but sometimes I do. That's why I copied the default template into ~/.blah-templates/README.ejs and added at the top of the file the following snippet:

<% if (_.pack.blah.h_img) { %>
![<%- _.pack.name %>](<%- _.pack.blah.h_img %>)
<% } %>

That means: if there is a heading image render it, otherwise do nothing.

If you want to see my customized templates, check out my dotfiles.

I published this example of using Blah here.

Project templates

But sometimes these user-level templates are not enough–maybe you want to have some custom stuff inside of your project and not pollute your other projects with that.

Well, you need project-level templates. Blah does that for you. Run blah -i to initialize the .blah directory in your project. If you have user-level templates, they will be copied in the .blah directory, otherwise the defaults will be copied.

Then, next time when you generate documentation with Blah, these templates will be used.


Finally, keep this in mind: generate documentation. It's easier, faster, better, cooler. Let Blah do that for you. Don't waste your time.

Like always, don't forget to check out the Blah project repository and open issues for anything (questions, bugs, features, discussions etc). Contributions are also welcome!

Happy Blahing!

Read more »

Reserving packages on NPM

Sometimes I have ideas about interesting tools to develop but I don't have time to build them. Since I use Node.JS and NPM (Node Package Manager) I created npmreserve – a tool for reserving package names on NPM. :bulb:

Installation

Supposing NodeJS and NPM are already installed on your machine, npmreserve can be installed running:

$ npm i -g npmreserve

Usage

The command line tool usage is simple. Let's say you want to reserve the foo package. For that you need to run:

$ npmreserve -n foo

This will create a package containing the README.md and package.json files. While the description is not mandatory, you can provide it:

$ npmreserve -n foo -d 'some description'

Also, you can pass other package.json fields:

$ npmreserve -n foo -d 'some description' -o '{"author": "Alice"}'

In short, this is how to use npmreserve. For detailed information run npmreserve -h.

This can be used as library as well. Check out the repository on GitHub and as always I accept contributions! :sparkles:

So, happy NPM package reserving!

Read more »