Signatur
Beschreibung
Die Schnittstelle TimeRanges steht für eine geordnete Liste von Zeitbereichen einer Medienressource. Sie liefern <audio>- und <video>-Elemente (also HTMLMediaElement) über die Eigenschaften buffered, played und seekable zurück. Außerdem gibt es sie in der Media Source Extensions API unter SourceBuffer.buffered.
Jeder Bereich hat eine Start- und eine Endzeit in Sekunden. Die Bereiche sind aufsteigend sortiert, überlappen sich nicht und grenzen nicht direkt aneinander. Aneinanderstoßende Abschnitte fasst der Browser zu einem Bereich zusammen. Die Anzahl steht in length. Die Grenzen eines Bereichs liest du mit start(index) und end(index).
Typische Einsätze sind:
- Pufferanzeige in eigenen Player-Oberflächen, etwa ein grauer Balken hinter dem Fortschrittsbalken.
- Auswertung, welche Teile eines Videos wirklich angesehen wurden (
played). - Prüfung vor einem Sprung, ob eine Zielzeit überhaupt angesteuert werden kann (
seekable), zum Beispiel bei Livestreams.
Ein TimeRanges-Objekt ist eine Momentaufnahme. Die Liste ist schreibgeschützt, und man kann sie nicht selbst erzeugen: Es gibt keinen öffentlichen Konstruktor. Wer den aktuellen Stand braucht, liest die Eigenschaft erneut aus, zum Beispiel im Ereignis progress oder timeupdate.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $length | number | Schreibgeschützte Eigenschaft: Anzahl der Zeitbereiche in der Liste. Bei 0 gibt es keine Bereiche. |
|
| $start(index) | (index: number) => number | Methode: gibt die Startzeit (in Sekunden) des Bereichs mit dem Index index zurück. Der Index reicht von 0 bis length - 1. |
|
| $end(index) | (index: number) => number | Methode: gibt die Endzeit (in Sekunden) des Bereichs mit dem Index index zurück. Bei Livestreams kann der Wert Infinity sein. |
Rückgabewert
HTMLMediaElement.buffered, .played, .seekable oder SourceBuffer.buffered.Beispiele
Alle gepufferten Bereiche eines Videos ausgeben
const video = document.querySelector('video');
const logRanges = (ranges) => {
for (let i = 0; i < ranges.length; i++) {
console.log(`Bereich ${i}: ${ranges.start(i).toFixed(1)}s – ${ranges.end(i).toFixed(1)}s`);
}
};
video.addEventListener('progress', () => logRanges(video.buffered));
Pufferanzeige für einen eigenen Fortschrittsbalken
const video = document.querySelector('video');
const canvas = document.querySelector('#buffer-bar');
const ctx = canvas.getContext('2d');
const drawBuffer = () => {
const { buffered, duration } = video;
if (!Number.isFinite(duration) || duration === 0) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#bbb';
for (let i = 0; i < buffered.length; i++) {
const x = (buffered.start(i) / duration) * canvas.width;
const w = ((buffered.end(i) - buffered.start(i)) / duration) * canvas.width;
ctx.fillRect(x, 0, w, canvas.height);
}
};
video.addEventListener('progress', drawBuffer);
video.addEventListener('loadedmetadata', drawBuffer);
Prüfen, ob eine Zeitposition gepuffert bzw. suchbar ist
const isInRanges = (ranges, time) => {
for (let i = 0; i < ranges.length; i++) {
if (time >= ranges.start(i) && time <= ranges.end(i)) return true;
}
return false;
};
const video = document.querySelector('video');
const target = 95;
if (isInRanges(video.seekable, target)) {
video.currentTime = target;
console.log('Sofort abspielbar:', isInRanges(video.buffered, target));
} else {
console.log('Zeitpunkt nicht suchbar');
}
Gesamte angesehene Dauer über played berechnen
const video = document.querySelector('video');
video.addEventListener('pause', () => {
const { played } = video;
let watched = 0;
for (let i = 0; i < played.length; i++) {
watched += played.end(i) - played.start(i);
}
const percent = ((watched / video.duration) * 100).toFixed(1);
console.log(`Angesehen: ${watched.toFixed(1)}s (${percent} %)`);
});
// Wichtig · Fallstricke
- Index außerhalb des Bereichs:
start(i)undend(i)werfen eineIndexSizeError-DOMException, wennikleiner als0oder mindestenslengthist. Prüfe deshalb immer zuerstlength. Direkt nach dem Laden ist sie oft0. - Kein Array:
TimeRangesist weder iterierbar noch indexierbar (ranges[0]funktioniert nicht).for…ofundArray.from()helfen daher nicht. Nutze eine klassischefor-Schleife mitstart()undend(). - Momentaufnahme: Das Objekt aktualisiert sich nicht von selbst. Lies
bufferedjedes Mal neu aus, statt eine alte Referenz aufzuheben. - Mehrere Bereiche: Nach Sprüngen im Video können Lücken entstehen. Wer nur
end(0)auswertet, rechnet dann falsch. Suche stattdessen den Bereich, dercurrentTimeenthält. - Livestreams:
seekablekann ein gleitendes Fenster sein, unddurationist dann womöglichInfinity. Prozentrechnungen vorher mitNumber.isFinite()absichern. - Browser-Unterstützung: Seit Jahren in allen modernen Browsern verfügbar. Das Ereignis
progresswird je nach Browser unterschiedlich oft ausgelöst. Für eine flüssige Anzeige kann man zusätzlichtimeupdateabfragen.