Home > Software design >  How can I get who paused the video in Youtube API? (with Socket.io)
How can I get who paused the video in Youtube API? (with Socket.io)

Time:02-01

Basically, I'm challenging myself to build something similar to watch2gether, where you can watch youtube videos simultaneously through the Youtube API and Socket.io.

My problem is that there's no way to check if the video has been paused other than utilizing the 'onStateChange' event of the Youtube API.

But since I cannot listen to the CLICK itself rather than the actual pause EVENT, when I emit a pause command and broadcast it via socket, when the player pauses in other sockets, it will fire the event again, and thus I'm not able to track who clicked pause first NOR prevent the pauses from looping.

This is what I currently have:

// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
    if(event.data == YT.PlayerState.PAUSED) {
        socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
    }
    // (...) other states
}

// SERVER SIDE
socket.on('pausevideo', user => {
    io.emit('smsg', `${user} paused the video`)
    socket.broadcast.emit('pausevideo'); // Here I'm using broadcast to send the pause to all sockets beside the one who first clicked pause, since it already paused from interacting with the iframe
});

// CLIENT SIDE
socket.on('pausevideo', () => {
    ytplayer.pauseVideo(); // The problem here is, once it pauses the video, onStateChange obviously fires again and results in an infinite ammount of pauses (as long as theres more than one user in the room)
});

The only possible solution I've thought of is to use a different PLAY/PAUSE button other than the actual Youtube player on the iframe to catch the click events and from there pause the player, but I know countless websites that uses the plain iframe and catch these kind of events, but I couldn't find a way to do it with my current knowledge.

CodePudding user response:

If the goal here is to be able to ignore a YT.PlayerState.PAUSED event when it is specifically caused by you earlier calling ytplayer.pauseVideo(), then you can do that by recording a timestamp when you call ytplayer.pauseVideo() and then checking that timestamp when you get a YT.PlayerState.PAUSED event to see if that paused event was occurring because you just called ytplayer.pauseVideo().

The general concept is like this:

let pauseTime = 0;
const kPauseIgnoreTime = 250;    // experiment with what this value should be

// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
    if(event.data == YT.PlayerState.PAUSED) {
        // only send pausevideo message if this pause wasn't caused by
        // our own call to .pauseVideo()
        if (Date.now() - pauseTime > kPauseIgnoreTime) {
            socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
        }
    }
    // (...) other states
}

// CLIENT SIDE
socket.on('pausevideo', () => {
    pauseTime = Date.now();
    ytplayer.pauseVideo();
});

If you have more than one of these in your page, then (rather than a variable like this) you can store the pauseTime on a relevant DOM element related to which player the event is associated with.

You can do some experimentation to see what value is best for kPauseIgnoreTime. It needs to be large enough so that any YT.PlayerState.PAUSED event cause by you specifically calling ytplayer.pauseVideo() is detected, but not so long that it catches a case where someone might be pausing, then unpausing relatively soon after.

CodePudding user response:

I actually found a solution while working around what that guy answered, I'm gonna be posting it in here in case anyone gets stuck with the same problem and ends up here.

Since socket.broadcast.emit doesn't emit to itself, I created a bool ignorePause and made it to be true only when the client received the pause request.

Then I only emit the socket if the pause request wasn't already broadcasted and thus received, and if so, the emit is ignored and the bool is set to false again in case this client/socket pauses the video afterwards.

  • Related