bigskysoftware / htmx

</> htmx - high power tools for HTML
https://htmx.org
Other
38.2k stars 1.3k forks source link

Video from previous page autoplays when going back #2856

Open ColonelThirtyTwo opened 2 months ago

ColonelThirtyTwo commented 2 months ago

When visiting a page with a video element with the autoplay element via a boosted link, then navigating back, the video's audio will autoplay on the "old" page, even though the video isn't anywhere in the DOM.

Fiddle: https://jsfiddle.net/st0oLudr/

<script src="https://demo.htmx.org"></script>

<main hx-boost="true">
  <a href="/video">Click me to see a video!</a>
</main>

<template url="/video">
  <video src="https://storage.googleapis.com/downloads.webmproject.org/media/video/webmproject.org/big_buck_bunny_trailer_480p_logo.webm" autoplay></video>
</template>

Click the link, then click the browser back button.

No idea how this works. Is the video is still playing outside of the DOM somehow?

ColonelThirtyTwo commented 2 months ago

Workaround:

document.addEventListener("htmx:beforeHistorySave", () => {
    for(const el of document.body.querySelectorAll("video[autoplay]")) {
        el.setAttribute("data-saved-src", el.getAttribute("src"));
        el.removeAttribute("src");
    }
});
document.addEventListener("htmx:historyRestore", () => {
    for(const el of document.body.querySelectorAll("video[autoplay]")) {
        el.setAttribute("src", el.getAttribute("data-saved-src"));
        el.removeAttribute("data-saved-src");
    }
});
MichaelWest22 commented 2 months ago

yeah it is really interesting that the browser keeps playing the video even though the element has been removed from the DOM! from my quick testing this did not happen when I changed the a records to do hx-get's instead of using boost but i'm not sure what is causing this issue sorry.

testing your workaround I found it often could run more than once which broke as if it runs twice on restore it sets src=null as data-saved-src was then missing. rewriting your workaround slightly fixed this for me and now it only changes attributes that exist:

document.addEventListener("htmx:beforeHistorySave", () => {
  for(const el of document.body.querySelectorAll("video[src]")) {
    el.setAttribute("data-saved-src", el.getAttribute("src"));
    el.removeAttribute("src");
  }
});
document.addEventListener("htmx:historyRestore", () => {
  for(const el of document.body.querySelectorAll("video[data-saved-src]")) {
    el.setAttribute("src", el.getAttribute("data-saved-src"));
    el.removeAttribute("data-saved-src");
  }
});
MichaelWest22 commented 2 months ago

https://stackoverflow.com/questions/3258587/how-to-properly-unload-destroy-a-video-element seems this is a known issue with browsers not handling removing playing video well leading to memory leaks and problems with the video still playing. your fix of removing the src seems to be the best solution listed

patriksh commented 1 month ago

I can't seem to get the mentioned workaround to do the job for me. The video still autoplays in the background - with sound.

What (most of the times) worked for me was this:

htmx.on('htmx:beforeRequest', function(event) {
    document.querySelectorAll('video').forEach((video) => {
        video.remove();
    });
});