sampotts / plyr

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

Auto pause other media players on the same page #144

Open ghost opened 8 years ago

ghost commented 8 years ago

Hi, I love this player, but I'm running into an issue when I have multiple media players on a page. It does not appear that plyr stops one before starting another, and so I end up with multiple audio files playing at once. Am I missing something in the docs?

gurupras commented 8 years ago

I've never had issues with multiple plyr objects on the same page. Could you throw up some code on jsfiddle or something and share it? Might be able to better help you that way.

sampotts commented 8 years ago

I think what he's suggesting is that we have an option to pause other instances on play of a particular player? We could certainly add this as an option.

espellcaste commented 8 years ago

Hi, I was testing Plyr just now and this improvement would be great. If one has audio and videos instances in the same page, it doesn't stop one before playing.

unwork commented 8 years ago

I second this request. I have 2 plyr instances on the same page and I need to automatically stop playing one video when the user starts playing the other one otherwise they both play at the same time.

I'll dive into the code and see if I can implement a method to accomplish this.

sampotts commented 8 years ago

It would need to sit behind a setting/option ideally as not everyone may want the behaviour but sure go ahead.

unwork commented 8 years ago

Indeed, that's the approach I have in mind, otherwise we'll be modifying the current behavior and that should't be necessary.

At first try I thought you had already implemented this but it was just being tricked by iOS' native behavior of playing one media file at a time, automatically stopping any previously media being played when playing a new video.

sampotts commented 8 years ago

Hey,

In the latest version you can get the instance reference to all players on a page using plyr.get(). This will return an array of instances so you could do something like:

plyr.get().forEach(function(instance) { 
    instance.pause();
});

That's going to pause all players of course though. I'll still look into the unique option though.

unwork commented 8 years ago

Thanks for the update Sam. I still don't have enough time to properly build and share my solution to this but I did came up with a quick workaround, which you can see active here: http://www.unwork.nu/#/records/nuv7/

There are better ways of accomplishing this but I thought I'd post my example in case it helps anyone.

thomaskieslich commented 8 years ago

Adding a id to each instance(would be nice to have this as default ;-) Identify the new played Player. Adopted from mediaelement.js. Works great with all types of player.

var instances = plyr.setup({
        enabled: true,
        debug: false
    });

    var i = 1;
    instances.forEach(function (instance) {
        instance.on('ready', function (event) {
            instance.getContainer().setAttribute('id', 'plyId-' + i);
            instance.plyId = 'plyr-' + i;
            // console.log(instance.pid);
            i++;
        });
        instance.on('play', function (event) {
            var currentPid = instance.plyId;
            instances.forEach(function (instance) {
                if (currentPid != instance.plyId) {
                    instance.pause();
                }
            });
        });
    });
lmfmaier commented 6 years ago

When looping through the instances to pause them, I check the source to determine if it's the current player. It's a bit hacky as it assumes that no two instances have the same source, which isn't the case in my app. myplayer.on('playing', function(event) { plyr.get().forEach(function(instance) { if(instance.source()!=event.detail.plyr.source()) instance.pause(); }); });

ZilMehta commented 6 years ago

Hi, I initialized multiple video players on a page by :

const players = Array.from(document.querySelectorAll('.js-player')).map(player => new Plyr(player)); players.forEach(function(instance) { });

How m i supposed to pause all other players when one player gets played.

friday commented 6 years ago

How m i supposed to pause all other players when one player gets played.

Use Array.filter to filter out the current player from the array, then pause every instance in the filtered array.

ZilMehta commented 6 years ago

Thank you! It worked by the following code :

const players = Array.from(document.querySelectorAll('.js-player')).map(player => new Plyr(player));
 players.forEach(function(instance,index) {
            instance.on('play',function(){
                players.forEach(function(instance1,index1){
                    if(instance != instance1){
                        instance1.pause();
                    }
                });
            });
        });

But if there are already some players on the page, and some of the players are added dynamically after a timeout, how will it work ? Do I need to initialize all the players again and write the same code as mentioned above ?

weavermedia commented 6 years ago

Simplest solution I found so far, merging answers from @ZilMehta and @friday

var players = plyr.setup();

players.forEach(function(player) {
  player.on('play',function(){
    var others = players.filter(other => other != player)
    others.forEach(function(other) {
      other.pause();
    })
  });
});

But I'd love to see this officially supported. Agree with @sampotts that it would be better as a config option, something like a stopOthers or solo boolean.

sampotts commented 6 years ago

The thing is Plyr is a 1-to-1 constructor in v3+ so it has no knowledge of the other players.

Your snippet is for pre v3 by the looks of it as there's no setup method anymore.

weavermedia commented 6 years ago

@sampotts Yep, sorry should've mentioned that. I'm not ready for all the breaking changes in v3 yet so I haven't updated. I prefer the ease and facility that setup() in v2 offers.

sampotts commented 6 years ago

@weavermedia It might be something I could port over as a static method that sets up multiple players. Will have a think.

weavermedia commented 6 years ago

@sampotts That would be very handy indeed. Didn't mean to diminish all the hard work that went into v3. It's highly appreciated (on that topic, please consider a Patreon for Plyr) - I just haven't had the time to figure out how the changes will affect my use.

CindyMarieSilva commented 6 years ago

I have multiple players on the same page like this:

            <audio id="player" controls>
              <source src="http://motherdev.rankubator.com/faq/audio/mp3/101_Narcissist_Monet.mp3" type="audio/mp3">
              <source src="http://motherdev.rankubator.com/faq/audio/ogg/101_Narcissist_Monet.ogg" type="audio/ogg">
            </audio>

            <audio id="player" controls>
              <source src="http://motherdev.rankubator.com/faq/audio/mp3/101_Narcissist_David.mp3" type="audio/mp3">
              <source src="http://motherdev.rankubator.com/faq/audio/ogg/101_Narcissist_David.ogg" type="audio/ogg">
            </audio>

How can I pause one audio file when the other audio file is played?

ghost commented 6 years ago

Just use this simple Jquery script :)

$('audio').bind('play', function() { activated = this; $('audio').each(function() { if(this != activated) this.pause(); }); });

MichaGue commented 6 years ago

@remiburett

Your solution works fine for me. But one question. I have a page with several videos, there I use your code. But one video is a simple animation which should run endless. With your code it also gets stopped. How can I prevent it from stopping while another video plays?

Thanks.

ghost commented 6 years ago

Because I used an audio or video selector you need to be more specific and replace the $('audio') with a class or ID so your video that should run endless will not be stopped by the script ;)

bigbangbaznga commented 5 years ago

How do I write this code for pause on other videos when I init one player at a time - on each click. My code goes like this:

$('somebutton').on('click', function(){
    // stuff happens here, defere video src

    // then init player on wanted video
    const player = new Plyr(id);
    player.on('ready', function() {
        player.play();
    });

    // other stuff happens there
});
sistematico commented 4 years ago
const players = Array.from(document.querySelectorAll('audio')).map(p => new Plyr(p, {
    controls: ['play', 'mute', 'volume']
}));

players.forEach(player => {
    player.on('ready', event => {
        console.info(player.id + event.target.id);
        event.target.setAttribute('data-id' , player.id);
    });

    player.on('play', ev => {
        playerPrincipal.pause();
        var Id = ev.target.dataset.id;
        players.forEach(pl => {
            if (Id != pl.id) {
                pl.pause();
            }
        });
    });
});
ableslayer commented 4 years ago
const players = Array.from(document.querySelectorAll('audio')).map(p => new Plyr(p, {
    controls: ['play', 'mute', 'volume']
}));

players.forEach(player => {
    player.on('ready', event => {
        console.info(player.id + event.target.id);
        event.target.setAttribute('data-id' , player.id);
    });

    player.on('play', ev => {
        playerPrincipal.pause();
        var Id = ev.target.dataset.id;
        players.forEach(pl => {
            if (Id != pl.id) {
                pl.pause();
            }
        });
    });
});

This code doesn't work for me. The first audio still plays when I hit the 2nd audio player. Here's a codepen: https://codepen.io/ableslayer/pen/zYYjNZV

AhmadrezaHK commented 4 years ago

i use plyr for my react app and i handle this by the following code

document.getElementById('container').addEventListener('play', (event)=>{ let temp = document.getElementsByTagName('audio') for(let i=0; i<temp.length; i++){ if(temp[i]!==event.target){ temp[i].pause() } } })

ralyodio commented 4 years ago

I need this feature too. Has anything been done?

scottatmonk commented 4 years ago

This feature would be very helpful. Is this still something being considered?

Lefthandmedia commented 3 years ago

me too

matestaker commented 3 years ago

Plyr instance already has an id, so you don't have to create one yourself.

instances.forEach(function (instance) {
    instance.on('play', function (event) {
        var currentPid = instance.id;
        instances.forEach(function (instance) {
            if (currentPid != instance.id) {
                instance.pause();
            }
        });
    });
});
lindsay-xd commented 3 years ago

Thanks for this thread - I am quite new but trying hard at this -- wondering if anyone can lend some insight.

I have a codepen where i've got the jQuery function working, but when I implement in a page locally (I'm using brackets editor) the 'pause when another audio element plays' is not working. anyone know why?

Codepen: https://codepen.io/xxsoundgirlxx/pen/WNGONYQ

HTML (i have put the js in the html so it can all be opened in one file - I have attached it here as a txt file)

index.txt

InputOutputZ commented 3 years ago

In case any one didn't find how to achieve pausing other playing instances, here is how I've implemented it.

currentPlyr = Plyr.setup(selector, plyrParams);
if(typeof currentPlyr == 'object') {
    currentPlyr.forEach(function(p) {
        p.on('playing', event => {
            appNS.pauseOtherPlyrs(event.detail.plyr.id, currentPlyr);
        });
    });
}

appNS.pauseOtherPlyrs = function(excluded_id, plyrs) {
    plyrs.forEach(function(p) {
        if(excluded_id != p.id && p.playing) {
            p.pause();
        }
    });
}
saulamsal commented 1 year ago

To manage playback across multiple Plyr instances, you can utilize a global array. This is great when you have 100s of videos (think of infinite scroll).

Here's a quick snippet to implement this:


// Global array to hold all Plyr instances
window.players = window.players || [];

// Initialization of Plyr
var player = new Plyr('#player');
window.players.push(player);

// On 'play' event, pause all other players
player.on('play', function() {
    window.players.forEach(p => {
        if (p !== player && !p.paused) p.pause();
    });
});