sampotts / plyr

A simple HTML5, YouTube and Vimeo player
https://plyr.io
MIT License
26.61k stars 2.93k forks source link

Forcing the player to start at a specific position? #208

Open mattmurtaugh opened 8 years ago

mattmurtaugh commented 8 years ago

I'm working on a project that keeps track of how far along a user is on the video, and pushing that information to the database every 5 seconds.

I'm unable to get the seek method to work without input from the user. I am able to have a link that calls the seek method, and that works fine, but when I try to call the seek method when the file loads, nothing happens.

This works:

$('.seek').click(function(e) { e.preventDefault(); var starttime = parseInt($('.plyr').attr('data-start')); player.seek(starttime); });

But when I try to call

var starttime = parseInt($('.plyr').attr('data-start')); player.seek(starttime);

by itself nothing happens.

Am I overlooking a trick to doing this? Or is there an easier way to specify where the video should start playing?

Thanks

mattmurtaugh commented 8 years ago

After playing around with this for a little while I found that if I set a very short delay, I don't have any issues with this at all. It's working like I want it too, but is there a better way to accomplish this than waiting 300 milliseconds before triggering the seek method?

sampotts commented 8 years ago

You might be able to listen to the 'ready' event and then make the call to seek? https://github.com/Selz/plyr#events

epnlespieux commented 8 years ago

@mattmurtaugh i am very interested by this feature : i would like to split a long interview into small pieces with a direct acccess to the particular part as we can do with youtube. Can you show some code for me to begin please ? (sorry for my poor english, french am I)

mattmurtaugh commented 8 years ago

I tried to listen for the 'ready' event, but it doesn't seem to be work how I thought it would when I first tried it. When I'm done with the project, I might revisit this idea.. But for now here is my solution:

setTimeout(function(){ player.seek(starttime); },300);

Replace 'starttime' with a variable that contains your start time or the time itself. You may also need to adjust the 300 milliseconds to something a little higher depending on how long it takes Plyr to load on your server. I found that I could use 250, but I bumped it up a little bit to make sure it loaded.

I'm far from the best programmer, so there is probably another way to accomplish this that is more efficient, but it seems to work for me.

skitterm commented 8 years ago

I was looking for the same functionality. I put the seek call inside the ready event. YouTube works (it pops me to that spot in the video), but Vimeo doesn't (it starts from the beginning). I stuck a setTimeout of 1s and then called seek, and it worked for Vimeo as well... but not for html5 video. Also, I had to click "play" on Vimeo videos a couple of times before I could see both the video playing and the time progress going.

loicjazon commented 8 years ago

Hi all,

Like you @skitterm, Youtube works but not Vimeo. I "solved" the problem with events.

You should use "ready" and "play" event !

My solution : https://jsfiddle.net/nOurs88/fv502bo4/1/ You can follow each step "step 1, step 2 etc.."

Hope you enjoy

TJSoler commented 7 years ago

I'm having the same problem with the audio player.

This doesn't work:

    let player = plyr.setup("#audio-01")[0];
    player.on('ready', (event) => {
        // using store.js to store the previusly played time onto localstorage.
    let startTime = store.get('plyr-time-audio-01'); // returns 30
        if (startTime > 0) player.seek(startTime);
    });

This does work:

    let player = plyr.setup("#audio-01")[0];
    player.on('ready', (event) => {
        setTimeout(() => {
            // using store.js to store the previusly played time onto localstorage.
        let startTime = store.get('plyr-time-audio-01'); // returns 30
            if (startTime > 0) player.seek(startTime);
    }, 200);
    });

Any ideas?

mikemellor11 commented 7 years ago

Seek/Forward don't seem to work if you call them in ready like others have said, i used the following method to seek as soon as possible without a timeout.

var canSeek = false;

player.on('ready', function(e){
    canSeek = true;
});

player.on('playing', function(e){
    if(canSeek){
        player.seek(10);
        canSeek = false;
    }
});

Doing it this way means seek will only be called once per video loaded in.

programmarchy commented 6 years ago

This wasn't working reliably for me. I found that I had to wait until I received a loadeddata event and the time I wanted to seek to was within the duration of the video. I think this is because the video element incrementally loads chunks of data, so if only 20 seconds had loaded, then seeking to 30 seconds wouldn't be possible yet. This is what worked for me:

    player.on('loadeddata', onDataLoaded)
    function onDataLoaded () {
      if (time <= player.duration) {
        player.off('loadeddata', onDataLoaded)
        player.currentTime = time
      }
    }
Hanzofm commented 3 years ago

Hi @sampotts @mikemellor11 @programmarchy, In my case, Is normal that I have no seek method? I use to this currentTime setter(v.3.5.6 and v3.6.4).

My Problem is only on ios devices, If I seek on progress bar when the video is stopped, when I click on play button the video starts on position 0.

peterhartree commented 3 years ago

I was having the problem described by others in this thread.

The method shared by @programmarchy works for me.

@sampotts I think it'd be worth adding something to the docs to mention this. "Skip to position immediately after player loads" strikes me as a moderately common use case (e.g. I'm currently making a podcast episode page, where I want people to be able to share links to a particular timestamp in the episode).

banagale commented 3 years ago

This discussion focuses on events for various video types, despite the issue title being more general.

I've been working with HTML5 Audio to play mp3s in webkit, so any browser in iOS since they all are required to use this engine, (mobile safari, firefox and chrome).

The loadedata event does not allow the setting of player.currentTime on iOS 15 / webkit, you must listen for the canplay event.

Use of canplay is mentioned here in #1298.

Using canplay alone does not work on desktop browsers, though. I'm looking at what can reliably be used there, and some conditional logic to belt-and-suspenders setting of player.currentTime.

banagale commented 3 years ago

One more update on this, I tested further and it appears iOS webkit will set player.currentTime correctly if you place it within the loaddeddata or canplay events. I use canplay.

This won't cover desktop browsers (other than safari) but you can get those too by just blindly trying to set player.currentTime before your player.play() event.

So long story short, if you're trying to do some kind of resume behavior on <audio> media like an mp3, be sure to set currentTime within an event and just prior to .play() to cover both all browsers in iOS and desktop.

LiThaM commented 11 months ago

This wasn't working reliably for me. I found that I had to wait until I received a loadeddata event and the time I wanted to seek to was within the duration of the video. I think this is because the video element incrementally loads chunks of data, so if only 20 seconds had loaded, then seeking to 30 seconds wouldn't be possible yet. This is what worked for me:

    player.on('loadeddata', onDataLoaded)
    function onDataLoaded () {
      if (time <= player.duration) {
        player.off('loadeddata', onDataLoaded)
        player.currentTime = time
      }
    }

I'm replicating this code and I can't get it to work.

HTML:

` <video id="myVideo" class="plyr" controls><source src="{{ asset('storage/' . $coursesContent->content_path) }}" type="video/mp4">  Tu navegador no soporta el tag de video.</video>`

JS

` document.addEventListener('DOMContentLoaded', function() {

    const player = new Plyr('#myVideo');
    var alertElement = document.getElementById('savedTimeAlert');
    const contentId = "{{ $coursesContent->id }}";
    const savedTime = parseFloat(getCookie('video_current_time_' + contentId));
    player.on('loadeddata', onDataLoaded)

    function onDataLoaded() {
        if (savedTime <= player.duration) {
            var minutes = Math.floor(savedTime / 60);
            var seconds = savedTime % 60;
            alertElement.innerText = "{{ __('Video in minute') }} " + minutes + ':' + seconds.toFixed() +
                "!";
            player.off('loadeddata', onDataLoaded)
            player.currentTime = savedTime;
        }
    }
    player.on('pause', function() {
        saveVideoTime();
    });

    window.addEventListener('beforeunload', function() {
        saveVideoTime();
    });

    function saveVideoTime() {
        const currentSavedTime = parseFloat(getCookie('video_current_time_' + contentId));
        if (isNaN(currentSavedTime) || player.currentTime > currentSavedTime) {
            setCookie('video_current_time_' + contentId, player.currentTime);
        }
    }

    function getCookie(name) {
        const value = "; " + document.cookie;
        const parts = value.split("; " + name + "=");
        if (parts.length === 2) return parts.pop().split(";").shift();
    }

    function setCookie(name, value) {
        document.cookie = name + "=" + value + "; path=/; SameSite=None; Secure";
    }
});`

Any idea or Solutions, only work for Videos to max time 2 min, with a 50 minute video, I can't get it to work.