A YouTube Cast Receiver for Node.
When your start the receiver, your device becomes discoverable and can be selected through the Cast button in the YouTube mobile app or website. When connected, the app or website acts as a remote control and issues commands to the receiver for controlling playback of videos (like Chromecast).
Not all browsers support casting from the YouTube website. This module has been tested to work with the Chrome and Edge desktop browsers.
The receiver itself does not include a player. It is intended to be integrated into your application where you implement the player yourself. When the receiver receives a playback command from the YouTube mobile app or website (such as play, pause and seek), it will pass this command to your player. It is up to you to decide how you would handle these commands.
This project uses a forked version of peer-dial for DIAL server implementation and is heavily based on TubeCast.
npm i yt-cast-receiver --save
const ytcr = require('yt-cast-receiver');
// Your player implementation
const player = new MyPlayer();
// Create receiver instance with your player
const receiver = ytcr.instance(player);
// When a client connects
receiver.on('connected', client => {
console.log(`Connected to ${client.name}`);
});
// When client disconnects
receiver.on('disconnected', client => {
console.log(`Disconnected from ${client.name}`);
});
// Start the receiver
receiver.start();
// Your player implementation extends the Player class
class MyPlayer extends ytcr.Player {
async play(videoId, position) {
...
this.notifyPlayed();
}
async resume() {
...
this.notifyResumed();
}
...
}
Creates a receiver instance.
player
: Your player implementationoptions
:- port: port on which to accept client requests (default: 3000)
- corsAllowOrigins:
true
orfalse
(default:false
- no origin allowed) - prefix: access path (default: '/ytcr')
- bindToInterfaces: Array (default:
undefined
- bind to all network interfaces) - bindToAddresses: Array (default:
undefined
- bind to all network addresses) - screenName
- screenApp
- defaultAutoplay:
true
orfalse
. On connected, whether to enable autoplay if supported (default:true
) - autoplayLoader: specify your own loader to retrieve the next video Id for autoplay
- friendlyName: friendly name of the cast receiver
- manufacturer: manufacturer of the cast receiver
- modelName: model name of the cast receiver
- debug:
true
orfalse
. Whether to output debug messages (default:false
)
Starts the receiver.
Stops the receiver.
Fires listener
on event
.
Event | Description | Data passed to listener |
---|---|---|
started |
Receiver is started | |
stopped |
Receiver is stopped | |
connected |
Client is connected | Client info |
disconnected |
Client is disconnected | Client info |
Detaches listener
from event
.
Sets the defaultAutoplay
option at runtime.
Sets the autoplayLoader
option at runtime.
Sets the debug
option at runtime.
Refer to the FakePlayer example, which uses a timer to simulate playback.
To begin with, create your player class by extending ytcr.Player
:
const ytcr = require('yt-cast-receiver');
class MyPlayer extends ytcr.Player {
...
}
Then override the following functions:
// Play videoId starting at position
async play(videoId, position) {
...
// When playback started
await this.notifyPlayed();
}
// Resume paused playback
async resume() {
...
// When playback resumed
await this.notifyResumed();
}
// Pause playback
async pause() {
...
// When playback paused
await this.notifyPaused();
}
// Stop playback
async stop() {
...
// When playback stopped
await this.notifyStopped();
}
// Seek to position
async seek(position, statusBeforeSeek) {
...
// After seeking
await this.notifySeeked(statusBeforeSeek);
}
// Set volume
async setVolume(volume) {
...
// After setting volume
await this.notifyVolumeChanged();
}
// Get current volume
async getVolume() {
...
}
// Get current playback position
async getPosition() {
...
}
// Get duration of current playback
async getDuration() {
...
}
The notify...
functions tell the receiver that it should update the client status following a change in the player state.
Playing the next video It is the player's responsibility to tell the receiver to move on to the next video in the queue when the current video has finished playing:
...
// When current video has finished playing
await this.requestPlayNext();
The receiver will then tell the player to play the next video in the queue or, if there isn't any, the 'up next' video if autoplay is enabled.
You can also tell the receiver to play the previous video in the list by calling
this.requestPlayPrevious()
The default autoplay loader retrieves the 'up next' video Id through the following sources:
- Mixes
- Related videos, if mixes are not available
You can provide your own loader with the autoplayLoader
option in instance()
or call setAutoplayLoader(loader)
. When implementing your own loader, you must provide the following function:
async function getUpNextVideoId(videoId, currentVideoIds)
videoId
: the video Id for which the 'up next' video Id is to be returned.currentVideoIds
: an array of video Ids currently in the playlist / queue. Your implementation must ensure that the 'up next' video Id it returns is not among those in this list.
- This module is work-in-progress and may not be reliable enough for production use
- The YouTube website is less featured than the YouTube mobile app as far as casting is concerned:
- Autoplay is not supported
- The receiver is not notified when videos are added to the queue. Hence, they will not be played even though they appear in the queue on the website.
0.1.1-b
- [Changed] More robust fetching of mix playlists for 'Up Next' videos
0.1.0b
- [Fixed] Connection issue with YouTube mobile app version 16.22.35 and later
0.1.0a
- Initial release