fix(core): a clip that has fully downloaded stays loaded and plays on time

This commit is contained in:
Miguel Angel Simon Sierra
2026-10-30 00:28:56 -04:00
parent c0bfb064db
commit 331cbab330
2 changed files with 45 additions and 1 deletions
@@ -116,6 +116,36 @@ describe("releasing a clip's download", () => {
expect(video.getAttribute("src")).toBe("a.mp4");
});
it("keeps a clip whose whole file is buffered", () => {
const video = document.createElement("video");
video.setAttribute("src", "a.mp4");
Object.defineProperty(video, "duration", { value: 6.67 });
Object.defineProperty(video, "buffered", {
value: { length: 1, start: () => 0, end: () => 6.67 },
});
video.load = vi.fn();
releaseMedia(video);
expect(video.load).not.toHaveBeenCalled();
expect(video.getAttribute("src")).toBe("a.mp4");
});
it.each([
[0, 15],
[430, 2642],
])("releases a clip with only %s-%s s of a long file buffered", (from, to) => {
const video = document.createElement("video");
video.setAttribute("src", "a.mp4");
Object.defineProperty(video, "duration", { value: 2642 });
Object.defineProperty(video, "buffered", {
value: { length: 1, start: () => from, end: () => to },
});
video.load = vi.fn();
releaseMedia(video);
expect(video.load).toHaveBeenCalledTimes(1);
});
it("leaves a clip on <source> children, their order and its markup untouched", () => {
const video = document.createElement("video");
video.innerHTML =
+15 -1
View File
@@ -5,6 +5,8 @@ import { defersMedia } from "./timedClipHide";
import { swallow } from "./diagnostics";
import { mediaElementTime } from "./mediaClock";
const MEDIA_EDGE_SECONDS = 0.1;
type PreloadableMedia = Pick<
HTMLMediaElement,
"id" | "tagName" | "getAttribute" | "preload" | "readyState" | "networkState" | "load"
@@ -73,8 +75,20 @@ export function stopMediaDownload(media: HTMLMediaElement): void {
media.load();
}
// The whole file in memory: its download is over, so releasing it would free no connection, only drop the data.
function wholeFileBuffered(media: HTMLMediaElement): boolean {
const { buffered, duration } = media;
return (
Number.isFinite(duration) &&
duration > 0 &&
buffered.length === 1 &&
buffered.start(0) <= MEDIA_EDGE_SECONDS &&
buffered.end(0) >= duration - MEDIA_EDGE_SECONDS
);
}
export function releaseMedia(media: HTMLMediaElement): void {
if (media.querySelector("source")) return;
if (media.querySelector("source") || wholeFileBuffered(media)) return;
const src = media.getAttribute("src");
stopMediaDownload(media);
if (src !== null) media.setAttribute("src", src);