Skip to content

Clearing a video player's src leaves the previous film playing #7465

Closed

Description

@AksharP5

Describe the bug

Clearing src on a mounted <hyperframes-player type="video/mp4"> leaves the previous film playing. A host that clears its selected video still shows and plays that video, while ready and duration keep describing it. Setting src="" has the same effect.

Reproduced in Chrome at 4b3f70fb1b202a1422a199e8b7440a388d0b5a20, Player 0.9.26. The Player/core source is unchanged on latest main, 7bf19ab5f9d1690d596334822f251dece3921e1a, where both regression cases were rechecked and fail.

Minimal reproduction

Build the pinned source and generate a public synthetic clip:

git clone https://github.com/heygen-com/hyperframes.git hf-player-clear-src
cd hf-player-clear-src
git checkout 7bf19ab5f9d1690d596334822f251dece3921e1a
PUPPETEER_SKIP_DOWNLOAD=1 bun install --frozen-lockfile
bun run build
mkdir repro-player
cp packages/player/dist/hyperframes-player.global.js repro-player/
ffmpeg -f lavfi -i color=c=royalblue:s=320x180:r=30 -t 4 -c:v libx264 -pix_fmt yuv420p repro-player/film.mp4

Save this as repro-player/repro.html:

<!doctype html>
<script src="./hyperframes-player.global.js"></script>
<hyperframes-player type="video/mp4" src="./film.mp4" muted controls
  style="width:320px;height:180px"></hyperframes-player>
<script>
  const player = document.querySelector('hyperframes-player');
  player.addEventListener('ready', () => {
    player.play();
    setTimeout(() => {
      player.removeAttribute('src');
      // Replacing the line above with player.setAttribute('src', '') has the same bug.
      setTimeout(() => console.log({
        src: player.getAttribute('src'),
        paused: player.paused,
        ready: player.ready,
        duration: player.duration,
        currentTime: player.currentTime,
        videoSrc: player.shadowRoot.querySelector('video').getAttribute('src'),
        videoPaused: player.shadowRoot.querySelector('video').paused,
      }), 250);
    }, 250);
  }, { once: true });
</script>

Save this as repro-player/serve.mjs:

import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
const files = {
  '/': ['repro.html', 'text/html'],
  '/hyperframes-player.global.js': ['hyperframes-player.global.js', 'text/javascript'],
  '/film.mp4': ['film.mp4', 'video/mp4'],
};
createServer(async (req, res) => {
  const file = files[req.url];
  if (!file) { res.writeHead(404).end(); return; }
  res.setHeader('Content-Type', file[1]);
  res.end(await readFile(new URL(file[0], import.meta.url)));
}).listen(8080, '127.0.0.1');

Steps to reproduce

  1. Run node repro-player/serve.mjs and open http://127.0.0.1:8080/ in Chrome.
  2. The muted film starts at ready. After 250 ms the example removes src and then prints state 250 ms later.
  3. Observe the blue film and Pause button remain on screen. Repeat with player.setAttribute('src', '') instead of removeAttribute.

Expected behavior

The previous video is unloaded, playback is paused, ready becomes false, and the controls reset to 0:00 / 0:00. A new src can load another video.

Actual behavior

The player has no src but its inner video still has src="./film.mp4" and keeps playing. paused is false, ready is true, duration is 4, and currentTime continues advancing. The source attribute callback ignores both null and the empty string.

Environment

Linux arm64, Node 24.22.1, Bun 1.4.4, headless Chrome 153.0.8010.36 with audio muted. Local bundled Player built from the pinned commit above. No custom plugins, extensions, network media or private inputs. Safari and Firefox were not exercised.

Additional context

The existing video source reset already handles readiness, clocks and controls. The missing path is clearing the host's src, followed by unloading the inner video's source without assigning an empty URL.

Activity

  1. added a commit that references this issue on Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions