ytsync is just a quick proof of concept/demo of syncing YouTube video playback between multiple browsers/tabs.
ytsync utilizes the following tools:
- YouTube Player API
- Node.js - Application Server
- Express.js - Node.js Web Framework
- Socket.io - Realtime Application Framework
To run and test this locally, first install Node.js then:
$ git clone git@github.com:davbai/ytsync-demo.git
$ cd ytsync-demo
$ npm install
$ node server.js
You can hit the app http://localhost:3000.
After a YouTube url
is entered, it is parsed and the client will emit a video-loaded
message passing along the videoId
as data.
// client.js
// "video-loaded" message is emitted from the client
socket.emit("video-loaded", {
videoId: videoId
});
When the server receives the video-loaded
message, it then broadcasts a load-video
message to all connect clients, also passing videoId
so the clients listening will know what video to load.
// server.js
// on receiving a "video-loaded" message, emit "load-video" to all clients
socket.on("video-loaded", function(data) {
socket.broadcast.emit("load-video", {
videoId: data.videoId
});
});
If the client on the receiving end has already an instance of YT.Player
(from a previous video being loaded) then that player
will cue the new video, otherwise a new YT.Player
will be created with the specified videoId
.
// client.js
// if the client does not yet have a player created
function createVideoPlayer(videoId) {
player = new YT.Player("player", {
height: "390",
width: "640",
videoId: videoId,
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
}
// a player has already been created earlier
function cueVideoPlayer(videoId) {
player.cueVideoById(videoId);
}
For other events such as playing, and pausing the video, the same flow occurs with their own respective messages that send when an event is trigger (when the video player changes state).
// client.js
// this function is called by the YouTube API when the state of the player changes
function onPlayerStateChange(event) {
var player = event.target;
switch(event.data) {
case YT.PlayerState.PLAYING:
socket.emit("video-playing", {
videoId: getVideoIdFromUrl(player.getVideoUrl()),
currentTime: player.getCurrentTime()
});
break;
case YT.PlayerState.PAUSED:
socket.emit("video-paused");
break;
}
}
MIT License