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

5

9

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?

Pennsylvanian answered 23/4, 2017 at 5:37 Comment(16)
document.getElementsByTagName("video")[1] suggests you have more than 1 video element ?Gruber
Yes. I believe the other elements are for commercials. I have confirmed that video element [1] is the correct one because I can play/pause/mute/unmute that one, and it's the real TV show video.Pennsylvanian
What happens when you try currentTime = 2500 ?Gruber
As mentioned in original post, no errors are thrown, but the video doesn't move to that spot, and any attempts interact with the player after that doesn't work. The time I try to set it to doesn't matter, it can be 500, 2500, 20, whatever. All same result. I have tried various different times.Pennsylvanian
Any chance you can use JQuery in your javascript?Gruber
Sure...but how would jQuery make a difference?Pennsylvanian
I have a hunch video[1].currentTime causes the issue. Try changing it to $('#myVideo') with an explicit ID, let me know the outcome.Gruber
I just tried that, it makes no difference at all, as expected. This has nothing to do with javascript vs jquery - it's something in the html5 video implementation.Pennsylvanian
Are you getting any errors or warning in the browser's dev console?Gruber
No errors or warnings, but there is some kind of unfulfilled promise when I call play() after setting currentTime(). I only explicitly call play() because it's paused and will not resume after setting currentTime.Pennsylvanian
Is this page live? Something I can see?Gruber
Yes, go to hulu.com and play any video. In the Chrome developer console try document.getElementsByTagName("video")[1].currentTime = 500;Pennsylvanian
How can I watch a video there? There's no option and the login requires payment.Gruber
You can create a free 30 day account. They require a payment instrument, but you can easily cancel before that and pay nothing.Pennsylvanian
I'll give this a shot tomorrow.Mature
have you tested your solution in other websites ? or maybe in test page you write ? also are you sure you're setting currentTime to a value less than video.duration ?Chromophore
M
3

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.

Mature answered 4/5, 2017 at 7:4 Comment(0)
G
2

Rather than try to find the javascript responsible for changing the time, why not try to simulate the user events that cause the time to change?

Figure out the exact sequence of mouse events that trigger the time change. This is probably some combination of mouseover, mousedown, mouseup, and click.

Then recreate those events synthetically and dispatch them to the appropriate elements.

This is the approach taken by extensions like Stream Keys and Vimium.

Genethlialogy answered 29/4, 2017 at 0:25 Comment(1)
Eejdoowad, that's a good approach, and I have tried looking into that, but have been unable to discover what those user events are. If you provide a code sample that works, I'll accept your answer. Anyone can get 1 month free on Hulu even though they make you enter a credit card or paypal account - but cancel in less than a month and you pay nothing.Pennsylvanian
T
1

The video should be ready to play before setting the currentTime.

Try adding this line before setting currentTime?

document.getElementsByTagName("video")[1].play(); document.getElementsByTagName("video")[1].currentTime = 500;

Thorin answered 4/5, 2017 at 3:36 Comment(0)
S
0

Looks like it works if you first pause, then set currentTime, then play again.

document.getElementsByTagName("video")[1].pause()
document.getElementsByTagName("video")[1].currentTime = 800.000000
document.getElementsByTagName("video")[1].play()

Probably would need to hook into some event like onseeked to put in the play command to make it more robust.

Sibby answered 11/5, 2018 at 21:24 Comment(0)
C
0

you can try it, i tried it and it works fine

                var sliderContainer = document.querySelector('.Timeline__slider');
                var maxTime = parseInt(sliderContainer.getAttribute('aria-valuemax'));
                var targetTime = " + value + ";
                var targetPosition = (targetTime / maxTime) * 100;
                var sliderWidth = sliderContainer.offsetWidth;
                var sliderLeft = sliderContainer.getBoundingClientRect().left;
                var mouseX = sliderLeft + (sliderWidth * targetPosition / 100);
                var pointerDownEvent = new MouseEvent('pointerdown', {
                  bubbles: true,
                  cancelable: true,
                  view: window,
                  clientX: mouseX
                });
                sliderContainer.dispatchEvent(pointerDownEvent);
                var pointerUpEvent = new MouseEvent('pointerup', {
                  bubbles: true,
                  cancelable: true,
                  view: window,
                  clientX: mouseX
                });
                sliderContainer.dispatchEvent(pointerUpEvent);
Clarisaclarise answered 2/5, 2024 at 8:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.