Search code examples
javascriptgoogle-chrome-extensionhtml5-video

Set videoElement.currentTime in Hulu video player doesn't work, and breaks the player


I have a Chrome extension in which I'm trying to jump forward or backward (based on a user command) to a specific time in the video by setting the currentTime property of the video object. Before trying to set currentTime, a variety of operations work just fine. For example:

document.getElementsByTagName("video")[1].play(); // works fine
document.getElementsByTagName("video")[1].pause(); // works fine
document.getElementsByTagName("video")[1].muted = true; // works fine
document.getElementsByTagName("video")[1].muted = false; // works fine

BUT as soon as I try to jump to a specific point in the video by doing something like this:

document.getElementsByTagName("video")[1].currentTime = 500; // doesn't work

No errors are thrown, the video pauses, and any attempted actions after this point do nothing. So the items shown above (play/pause/mute/unmute) no longer work after attempting to set currentTime. If I read the value of currentTime after setting it, it correctly displays the new time that I just set it to. Yet nothing I do will make it play, and in fact even trying to make the video play by clicking the built-in toolbar no longer works. So, apparently setting currentTime wreaks all kinds of havoc in the video player. Yet if I reload the video, all works as before as long as I don't try to set currentTime.

I can easily jump to various times (backward or forward) by sliding the slider on the toolbar, so there must be some way internally to do that. Is there some way I can discover what code does a successful time jump? Because it's a Chrome extension I can inject custom js into the executing Hulu js, but I don't know what command I would send.

Any ideas?


Solution

  • Okay I fiddled around with it for a little while to see how I could reproduce the click event on the player and came up with the following solution:

    handleViewer = function(){
        var thumbnailMarker = $('.thumbnail-marker'),
            progressBarTotal = thumbnailMarker.parent(),
            controlsBar = $('.controls-bar'),
            videoPlayer = $('#content-video-player');
    
        var init = function(){
                thumbnailMarker = $('.thumbnail-marker');
                progressBarTotal = thumbnailMarker.parent();
                controlsBar = $('.controls-bar');
                videoPlayer = $('#content-video-player');
        },
        check = function(){
            if(!thumbnailMarker || !thumbnailMarker.length){
                init();
            }
        },
        show = function(){
                thumbnailMarker.show();
                progressBarTotal.show();
                controlsBar.show();
        },
        hide = function(){
            controlsBar.hide();
        },
        getProgressBarWidth = function(){
            return progressBarTotal[0].offsetWidth;
        };
    
        return {
            goToTime: function(time){
                var seekPercentage, 
                duration;
                check();
                duration = videoPlayer[0].duration;
                if(time > 0 && time < duration){
                    seekPercentage = time/duration;
                    this.jumpToPercentage(seekPercentage);
                }
    
            },
            jumpToPercentage: function(percentage){
                check();
                if(percentage >= 1 && percentage <= 100){
                    percentage = percentage/100;
                }
                if(percentage >= 0 && percentage < 1){
                    show();
                    thumbnailMarker[0].style.left = (getProgressBarWidth()*percentage)+"px";
                    thumbnailMarker[0].click();
                    hide();
                }
            }
        }
    }();
    

    Once that code is initialized you can do the following:

    handleViewer.goToTime(500);
    

    Alternatively

    handleViewer.jumpToPercentage(50);
    

    I've tested this in chrome on a MacBook pro. Let me know if you run into any issues.