All Projects → LuanRT → YouTube.js

LuanRT / YouTube.js

Licence: MIT license
🎥 full-featured wrapper around YouTube's private API — reverse engineering InnerTube

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to YouTube.js

Igbot
🐙 Free scripts, bots and Python API wrapper. Get free followers with our auto like, auto follow and other scripts!
Stars: ✭ 4,094 (+83.42%)
Mutual labels:  like, comment
InstaBot
Simple and friendly Bot for Instagram, using Selenium and Scrapy with Python.
Stars: ✭ 32 (-98.57%)
Mutual labels:  like, comment
MiXLab
MiXLab is a mix of multiple amazing Colab Notebooks found on the internet such as rcloneLab, RLabClone, Torrent to Google Drive Downloader and some more.
Stars: ✭ 143 (-93.59%)
Mutual labels:  youtube-dl
Facebook-Auto-Liker
Simple, hacky python script which uses pyautogui to like images on FB.
Stars: ✭ 26 (-98.84%)
Mutual labels:  like
action-create-comment
💬 GitHub Action to create a comment
Stars: ✭ 30 (-98.66%)
Mutual labels:  comment
droidovpn
An unofficial VPN Gate client for Android.
Stars: ✭ 65 (-97.09%)
Mutual labels:  unofficial
JHLikeButton
❤️点赞动画,点赞星星,点赞爱心,抖音点赞 ❤️
Stars: ✭ 41 (-98.16%)
Mutual labels:  like
Erasure
Chrome extension for deleting your YouTube comment history.
Stars: ✭ 48 (-97.85%)
Mutual labels:  youtube-comments
youtube extract
Extract metadata for all videos of a youtube channel.
Stars: ✭ 19 (-99.15%)
Mutual labels:  youtube-dl
comment-box.nvim
✨ Clarify and beautify your comments using boxes and lines.
Stars: ✭ 91 (-95.92%)
Mutual labels:  comment
like-mysql
Simple and intuitive ORM for MySQL
Stars: ✭ 24 (-98.92%)
Mutual labels:  like
Grabber
A wrapper for Youtube-dl for Windows.
Stars: ✭ 22 (-99.01%)
Mutual labels:  youtube-dl
odio
A Simple Utility to Download Music (.m4a) From Youtube Links Using Only Clipboard/PasteBoard
Stars: ✭ 32 (-98.57%)
Mutual labels:  youtube-dl
like
Let your users like your Craft website's entries, assets and any other element.
Stars: ✭ 44 (-98.03%)
Mutual labels:  like
metube
youtube-dl web UI
Stars: ✭ 1,014 (-54.57%)
Mutual labels:  youtube-dl
android-youtube-dl
The android library that wraps Python 2.7 and youtube-dl python scripts
Stars: ✭ 35 (-98.43%)
Mutual labels:  youtube-dl
yt2audiobot
Telegram bot for converting YouTube videos to mp3
Stars: ✭ 26 (-98.84%)
Mutual labels:  youtube-dl
teams-api
Unofficial Microsoft Teams Library
Stars: ✭ 92 (-95.88%)
Mutual labels:  unofficial
RevealLayout
揭示效果布局,可以指定2个子布局,以圆形揭示效果切换选中状态
Stars: ✭ 118 (-94.71%)
Mutual labels:  like
comment
Online Generator for Kary Foundation Comment System (KFCS) http://comment.kary.us
Stars: ✭ 20 (-99.1%)
Mutual labels:  comment

YouTube.js

A full-featured wrapper around the Innertube API, which is what YouTube itself uses.

Report Bug · Request Feature

Tests Latest version Codefactor Monthly downloads Say thanks Discord

Note:

We're currently in the process of rewriting some parts of the library to improve performance, maintainability and quality. While this might take a little while, most of this documentation will no longer be valid after v2 (see #65).


Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Contributing
  5. License
  6. Contact
  7. Disclaimer

About

Innertube is an API used across all YouTube clients, it was created to simplify the internal structure of the platform in a way that updates, tweaks, and experiments can be easily made. This library handles all the low-level communication with Innertube, providing a simple, fast, and efficient way to interact with YouTube programmatically.

And huge thanks to @gatecrasher777 for his research on the workings of the Innertube API!

If you have any questions or need help, feel free to contact us on our chat server here.

Features

  • Search videos, playlists, music, albums, artists, etc.
  • Subscribe, unsubscribe, like, dislike, post comments, replies, and etc.
  • Get subscriptions/home feed, notifications, watch history, and more.
  • Easily sign in to any Google Account.
  • Fetch live chat & live stats.
  • Manage account settings.
  • Manage playlists.
  • Download videos.

~ And more!

Getting Started

Prerequisites

  • NodeJS v14 or greater

    To verify things are set up properly, run this:

    node --version

Installation

  • NPM:
    npm install youtubei.js@latest
  • Yarn:
    yarn add youtubei.js@latest
  • Git (bleeding-edge version):
    npm install git+https://github.com/LuanRT/YouTube.js.git

Usage

Create an Innertube instance (or session):

// const Innertube = require('youtubei.js'); 
import Innertube from 'youtubei.js';
const youtube = await new Innertube({ gl: 'US' });

Search:

Options:

  • client: YOUTUBE | YTMUSIC

  • filters (WIP, youtube only):

    • upload_date: any | last_hour | today | this_week | this_month | this_year

    • type: any | video | channel | playlist | movie

    • duration: any | short | medium | long

    • sort_by: relevance | rating | upload_date | view_count

const search = await youtube.search('QUERY', { client: 'YOUTUBE' });
YouTube Output

{
  query: string,
  corrected_query: string,
  estimated_results: number,
  videos: [
    {
      id: string,
      url: string,
      title: string,
      description: string,
      metadata: {
        view_count: string,
        short_view_count_text: {
          simple_text: string,
          accessibility_label: string
        },
        thumbnails: object[],
        duration: {
          seconds: number,
          simple_text: string,
          accessibility_label: string
        },
        published: string,
        badges: string[],
        owner_badges: string[]
      }
    }
  ]
}

YTMusic Output

{
  query: string,
  corrected_query: string,
  results: {
    top_result: object[],  // <- Can be anything; video, playlist, artist etc..
    songs: [
      {
        id: string,
        title: string,
        artist: string,
        album: string,
        duration: string,
        thumbnails: object[]
      }
    ],
    videos: [
      {
        id: string,
        title: string,
        author: string,
        views: string,
        duration: string,
        thumbnails: object[]
      }
    ],
    albums: [
      {
        id: string,
        title: string,
        author: string,
        year: string,
        thumbnails: object[]
      }
    ],
    featured_playlists: [
      {
        id: string,
        title: string,
        author: string,
        channel_id: string,
        total_items:number
      }
    ],
    community_playlists: [
      {
        id: string,
        title: string,
        author: string,
        channel_id: string,
        total_items: number
      }
    ],
    artists: [
      {
        id: string,
        name: string,
        subscribers: string,
        thumbnails: object[]
      }
    ]
  }
}


Search suggestions:

const suggestions = await youtube.getSearchSuggestions('QUERY', { client: 'YOUTUBE' })
Output

{
  query: string,
  results: string[]
}

Video info:

const video = await youtube.getDetails('VIDEO_ID');
Output

{
  title: string,
  description: string,
  thumbnail: {
    url: string,
    width: number,
    height: number
  },
  metadata: {
    embed: {
      iframeUrl: string,
      flashUrl: string,
      width: number,
      height: number,
      flashSecureUrl: string
    },
    likes: {
      count: number, 
      short_count_text: string
    },
    view_count: number,
    average_rating: number,
    length_seconds: number,
    channel_id: string,
    channel_url: string,
    external_channel_id: string,
    allow_ratings: boolean,
    is_live_content: boolean,
    is_family_safe: boolean,
    is_unlisted: boolean,
    is_private: boolean,
    is_liked: boolean,
    is_disliked: boolean,
    is_subscribed: boolean,
    subscriber_count: string,
    current_notification_preference: string,
    publish_date_text: string,
    has_ypc_metadata: boolean,
    category: string,
    channel_name: string,
    publish_date: string,
    upload_date: string,
    keywords: string[]
  }
}

Comments:

Sorting options: TOP_COMMENTS | NEWEST_FIRST

const comments = await youtube.getComments('VIDEO_ID', 'TOP_COMMENTS');

Alternatively, you can use:

const video = await youtube.getDetails('VIDEO_ID');
const comments = await video.getComments(); 
Output

{
  page_count: number,
  comment_count: number,
  items: [
    {
      text: string,
      author: {
        name: string,
        thumbnails: [
          {
            url: string,
            width: number,
            height: number
          }
        ],
        channel_id: string
      },
      metadata: {
        published: string,
        is_liked: boolean,
        is_disliked: boolean,
        is_pinned: boolean,
        is_channel_owner: boolean,
        is_reply: boolean,
        like_count: number,
        reply_count: number,
        id: string
      }
    }
  ]
}

Reply to, like/dislike, translate and report a comment:

const top_comment = comments.items[0];

await top_comment.like();
await top_comment.dislike();
await top_comment.report();
await top_comment.reply('Nice comment!'); 

// Note: only ISO language codes are accepted
await top_comment.translate('ru');  

Comment replies:

const replies = await top_comment.getReplies();

Comments/replies continuation:

const continuation = await comments.getContinuation();
const replies_continuation = await replies.getContinuation();

Home feed:

const homefeed = await youtube.getHomeFeed();
Output

{
  videos: [
    {
      id: string,
      title: string,
      description: string,
      channel: {
        id: string,
        name: string,
        url: string
      },
      metadata: {
        view_count: string,
        short_view_count_text: {
          simple_text: string,
          accessibility_label: string
        },
        thumbnail: {
          url: string,
          width: number,
          height: number
        },
        moving_thumbnail: {
          url: string,
          width: number,
          height: number
        },
        published: string,
        badges: string[],
        owner_badges: string[]
      }
    }
  ]
}

Continuation:

const continuation = await homefeed.getContinuation();

Watch history:

const history = await youtube.getHistory();
Output

{
  items: [
    {
      date: string,
      videos: [
        {
          id: string,
          title: string,
          description: string,
          channel: {
            id: string,
            name: string,
            url: string
          },
          metadata: {
            view_count: string,
            short_view_count_text: {
              simple_text: string,
              accessibility_label: string
            },
            thumbnail: {
              url: string,
              width: number,
              height: number
            },
            moving_thumbnail: {
              url: string,
              width: number,
              height: number
            },
            published: string,
            badges: string[],
            owner_badges: string[]
          }
        }
      ]
    }
  ]
}

Continuation:

const continuation = await history.getContinuation();

Subscriptions feed:

const mysubsfeed = await youtube.getSubscriptionsFeed();
Output

{
  items: [
    {
      date: string,
      videos: [
        {
          id: string,
          title: string,
          description: string,
          channel: {
            id: string,
            name: string,
            url: string
          },
          metadata: {
            view_count: string,
            short_view_count_text: {
              simple_text: string,
              accessibility_label: string
            },
            thumbnail: {
              url: string,
              width: number,
              height: number
            },
            moving_thumbnail: {
              url: string,
              width: number,
              height: number
            },
            published: string,
            badges: string[],
            owner_badges: string[]
          }
        }
      ]
    }
  ]
}

Continuation:

const continuation = await mysubsfeed.getContinuation();

Trending content:

const trending = await youtube.getTrending();
Output

{
  now: {
    content: [
      {
        title: string,
        videos: object[]
      }
    ]
  },
  // Other categories require an additional call to fetch videos
  music: { getVideos: Promise.<Array.<object>> },
  gaming: { getVideos: Promise.<Array.<object>> },
  movies: { getVideos: Promise.<Array.<object>> }
}

Song lyrics:

const search = await youtube.search('Never give you up', { client: 'YTMUSIC' });
const lyrics = await youtube.getLyrics(search.results.songs[0].id); 

Notifications:

const notifications = await youtube.getNotifications();
Output

{
  items: [
    {
      title: string,
      sent_time: string,
      channel_name: string,
      channel_thumbnail: {
         url: string,
         width: number,
         height: number
      },
      video_thumbnail: { 
         url: string,
         width: number,
         height: number
      },
      video_url: string,
      read: boolean,
      notification_id: string
    }
  ]
}

Continuation:

const continuation = await notifications.getContinuation();

Unseen notifications count:

const unread_notis_count = await youtube.getUnseenNotificationsCount();

Get playlist:

Client: YOUTUBE | YTMUSIC

const playlist = await youtube.getPlaylist('PLAYLIST_ID', { client: 'YOUTUBE' });
YouTube Output

{
  title: string,
  description: string,
  total_items: string,
  last_updated: string,
  views: string,
  items: [
    {
      id: string,
      title: string,
      author: string,
      duration: {
        seconds: number,
        simple_text: string,
        accessibility_label: string
      },
      thumbnails: object[]
    }
  ]
}

YouTube Music Output

{
  title: string,
  description: string,
  total_items: number,
  duration: string,
  year: string,
  items: [
    {
      id: string,
      title: string,
      author: string,
      duration: {
        seconds: number,
        simple_text: string
      },
      thumbnails: object[]
    }
  ]
}

Interactions:


Don't forget that you must be signed in to use some of the following features!

  • Subscribe/Unsubscribe:

    await youtube.interact.subscribe('CHANNEL_ID');
    await youtube.interact.unsubscribe('CHANNEL_ID');
  • Like/Dislike:

    await youtube.interact.like('VIDEO_ID');
    await youtube.interact.dislike('VIDEO_ID');
    await youtube.interact.removeLike('VIDEO_ID');
  • Comment:

    await youtube.interact.comment('VIDEO_ID', 'Haha, nice video!');
  • Playlists:

    const videos = [
      'VIDEO_ID1',
      'VIDEO_ID2',
      'VIDEO_ID3'
      //...
    ];
    
    // Create and delete a playlist:
    await youtube.playlist.create('My Awesome Playlist', videos);
    await youtube.playlist.delete('PLAYLIST_ID');
     
    // Add and remove videos from a playlist:
    await youtube.playlist.addVideos('PLAYLIST_ID', videos);
    await youtube.playlist.removeVideos('PLAYLIST_ID', videos);
  • Translate (does not require sign in)

    await youtube.interact.translate('Hi mom!', 'ru');
  • Change notification preferences:

    Options: ALL | NONE | PERSONALIZED

    await youtube.interact.setNotificationPreferences('CHANNEL_ID', 'ALL'); 

Response schema:

{
  success: boolean, 
  status_code: number, 
  playlist_id?: string,
  translated_content?: string,
  data?: object
}

Account


  • Get account info:

    await youtube.account.getInfo();
    Output

    {
      name: string,
      email: string,
      channel_id: string,
      subscriber_count: string,
      photo: object[]
    }


  • Get basic channel analytics:

    await youtube.account.getAnalytics();
    Output

    {
      metrics: [
        {
          title: string,
          subtitle: string,
          metric_value: string,
          comparison_indicator: object,
          series_configuration: object
        }
      ],
      top_content: [
        {
          views: string,
          published: string,
          thumbnails: object[],
          duration: string,
          is_short: boolean
        }
      ]
    }


  • Get Time Watched stats:

    await session.account.getTimeWatched();
    Output

    [
      {
        title: string,
        time: string
      }
    ]


Channel:

  • Edit channel name:

    await youtube.account.channel.editName('My new awesome name');
  • Edit channel description:

    await youtube.account.channel.editDescription('An awesome description');

Notification settings:

Options: ON | OFF

  • Subscription notifications:

    await youtube.account.settings.notifications.setSubscriptions('ON'); 
  • Recommended content notifications:

    await youtube.account.settings.notifications.setRecommendedVideos('ON'); 
  • Channel activity notifications:

    await youtube.account.settings.notifications.setChannelActivity('ON'); 
  • Comment replies notifications:

    await youtube.account.settings.notifications.setCommentReplies('ON'); 
  • Channel mention notifications:

    await youtube.account.settings.notifications.setSharedContent('ON'); 

Privacy settings:

Options: ON | OFF

  • Subscriptions privacy:

    await youtube.account.settings.privacy.setSubscriptionsPrivate('ON'); 
  • Saved playlists privacy:

    await youtube.account.settings.privacy.setSavedPlaylistsPrivate('ON'); 

Live chats:


Currently, the library can retrieve the live chat, stats, and send messages.

Example:

import Innertube from 'youtubei.js';

const youtube = await new Innertube();

const search = await youtube.search('Lofi girl live');
const video = await youtube.getDetails(search.videos[0].id);
  
const livechat = video.getLivechat();

// Updated stats about the livestream
livechat.on('update-metadata', (data) => {
  console.info('Info:', data);
});
   
// Fired whenever there is a new message or other chat events
livechat.on('chat-update', (message) => {
  console.info(`- ${message.author.name}\n${message.text}\n\n`);
    
  if(message.text == '!info') {
    livechat.sendMessage('Hello! This message was sent from YouTube.js');
  }
});

Stop fetching the live chat:

livechat.stop();

Delete a message:

const msg = await livechat.sendMessage('Nice livestream!');
await msg.deleteMessage();

Downloading videos:


const options = {
  format?: string,
  quality?: string,
  type?: string,
  range?: { start: number, end: number }
};

const stream = youtube.download('VIDEO_ID', options);

Options:

  • format: mp4 | webm etc.. (note: only formats provided by YouTube are available)

  • quality: 144p, 240p, 360p, 480p, 720p, 1080p etc..

  • type: video | audio | videoandaudio

  • range: indicates which bytes should be downloaded

    • start: an integer indicating the beginning of the range
    • end: an integer indicating the end of the range

Cancel a download:

stream.cancel();

Example:

import fs from 'fs';
import Innertube from 'youtubei.js';

const youtube = await new Innertube();
const search = await youtube.search('Sound Coming From A Massive Black Hole - Anton Petrov');
  
const stream = youtube.download(search.videos[0].id, {
  format: 'mp4', // defaults to mp4
  quality: '720p', // falls back to 360p if a specific quality isn't available
  type: 'videoandaudio' 
});
  
stream.pipe(fs.createWriteStream(`./${search.videos[0].id}.mp4`));
 
stream.on('start', () => {
  console.info('[YOUTUBE.JS]', 'Starting now!');
});
  
stream.on('info', (info) => {
  console.info('[YOUTUBE.JS]', `Downloading ${info.video_details.title} by ${info.video_details.metadata.channel_name}`);
});
  
stream.on('progress', (info) => {
  process.stdout.clearLine();
  process.stdout.cursorTo(0);
  process.stdout.write(`[YOUTUBE.JS] Downloaded ${info.percentage}% (${info.downloaded_size}MB) of ${info.size}MB`);
});
  
stream.on('end', () => {
  process.stdout.clearLine();
  process.stdout.cursorTo(0);
  console.info('[YOUTUBE.JS]', 'Done!');
});
  
stream.on('error', (err) => console.error('[ERROR]', err)); 

Alternatively, you can get the deciphered streaming data and handle the download yourself:

await youtube.getStreamingData('VIDEO_ID', options);
Output

{
  selected_format: {
    itag: number,
    mimeType: string,
    bitrate: number,
    initRange: { start: string, end: string },
    indexRange: { start: string, end: string },
    lastModified: string,
    contentLength: string,
    quality: string,
    projectionType: string,
    averageBitrate: number,
    highReplication: boolean,
    audioQuality: string,
    approxDurationMs: string,
    audioSampleRate: string,
    audioChannels: number,
    loudnessDb: number,
    url: string,
    has_audio: boolean,
    has_video: boolean
  },
  formats: [
    {
      itag: number,
      mimeType: string,
      bitrate: number,
      initRange: { start: string, end: string },
      indexRange: { start: string, end: string },
      lastModified: string,
      contentLength: string,
      quality: string,
      projectionType: string,
      averageBitrate: number,
      highReplication: boolean,
      audioQuality: string,
      approxDurationMs: string,
      audioSampleRate: string,
      audioChannels: number,
      loudnessDb: number,
      url: string,
      has_audio: boolean,
      has_video: boolean
    }
  ]
}
  

Signing in:


When signing in to a Google account, you have two options:

  • OAuth 2.0; easy, simple & reliable.
  • Cookies; usually complicated to extract and unreliable.

OAuth:

import fs from 'fs';
import Innertube from 'youtubei.js';

const youtube = await new Innertube();

const creds_path = './yt_oauth_creds.json'; 
const creds = fs.existsSync(creds_path) ? JSON.parse(fs.readFileSync(creds_path).toString()) : {};

youtube.ev.on('auth', (data) => {
  switch (data.status) {
    case 'AUTHORIZATION_PENDING':
      console.info(`
        Hello! On your phone or computer,
        go to ${data.verification_url} and enter
        the code ${data.code}.
      `);
      break;
    case 'SUCCESS':
      fs.writeFileSync(creds_path, JSON.stringify(data.credentials));
      console.info('Successfully signed in, enjoy!');
      break;
  }
});

youtube.ev.on('update-credentials', (data) => {
  fs.writeFileSync(creds_path, JSON.stringify(data.credentials));
  console.info('Credentials updated!', data);
});
  
await youtube.signIn(creds);
  
//...

Sign out:

const response = await youtube.signOut();
if (response.success) {
  console.log('You have successfully signed out');
}

Cookies:

import Innertube from 'youtubei.js';
const youtube = await new Innertube({ cookie: '...' }); 

Contributing

Contributions, issues and feature requests are welcome. Feel free to check issues page if you want to contribute.

Contributors

Contact

LuanRT - @lrt_nooneknows - [email protected]

Project Link: https://github.com/LuanRT/YouTube.js

Disclaimer

This project is not affiliated with, endorsed, or sponsored by YouTube or any of their affiliates or subsidiaries. All trademarks, logos and brand names are the property of their respective owners, and are used only to directly describe the services being provided, as such, any usage of trademarks to refer to such services is considered nominative use.

Should you have any questions or concerns please contact me directly via email.

License

Distributed under the MIT License.

(back to top)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].