Skip to content

fix: add media listeners immediately when using bind:paused #13502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-items-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: add media listeners immediately when using `bind:paused`
54 changes: 13 additions & 41 deletions packages/svelte/src/internal/client/dom/elements/bindings/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,56 +138,28 @@ export function bind_playback_rate(media, get, set = get) {
* @param {(paused: boolean) => void} set
*/
export function bind_paused(media, get, set = get) {
var mounted = hydrating;
var paused = get();

var callback = () => {
var update = () => {
if (paused !== media.paused) {
paused = media.paused;
set((paused = media.paused));
}
};

if (paused == null) {
callback();
}

// Defer listening if not mounted yet so that the first canplay event doesn't cause a potentially wrong update
if (mounted) {
// If someone switches the src while media is playing, the player will pause.
// Listen to the canplay event to get notified of this situation.
listen(media, ['play', 'pause', 'canplay'], callback, false);
}
// If someone switches the src while media is playing, the player will pause.
// Listen to the canplay event to get notified of this situation.
Copy link
Contributor

listen(media, ['play', 'pause', 'canplay'], update, paused == null);

render_effect(() => {
paused = !!get();

if (paused !== media.paused) {
var toggle = () => {
mounted = true;
if (paused) {
media.pause();
} else {
media.play().catch(() => {
set((paused = true));
});
}
};

if (mounted) {
toggle();
// Needs to be an effect to ensure media element is mounted: else, if paused is `false` (i.e. should play right away)
// a "The play() request was interrupted by a new load request" error would be thrown because the resource isn't loaded yet.
effect(() => {
if ((paused = !!get()) !== media.paused) {
if (paused) {
media.pause();
} else {
// If this is the first invocation in dom mode, the media element isn't mounted yet,
// and therefore its resource isn't loaded yet. We need to wait for the canplay event
// in this case or else we'll get a "The play() request was interrupted by a new load request" error.
media.addEventListener(
'canplay',
() => {
listen(media, ['play', 'pause', 'canplay'], callback, false);
toggle();
},
{ once: true }
);
media.play().catch(() => {
set((paused = true));
});
}
}
});
Expand Down