feat: playback position persistence for all players and grid indicators

This commit is contained in:
4gray committed 2026-01-18 11:40:27 +01:00
1 parent d218dc0ad2
commit adb89145a3
46 files changed
+2310 -146

No files matched your search

@@ -1,11 +1,13 @@
import {
Component,
ElementRef,
EventEmitter,
inject,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
} from '@angular/core';
import Artplayer from 'artplayer';
@@ -36,6 +38,11 @@ export class ArtPlayerComponent implements OnInit, OnDestroy, OnChanges {
@Input() channel!: Channel;
@Input() volume = 1;
@Input() showCaptions = false;
@Input() startTime = 0;
@Output() timeUpdate = new EventEmitter<{
currentTime: number;
duration: number;
}>();
private player!: Artplayer;
private hls: Hls | null = null;
@@ -121,6 +128,19 @@ export class ArtPlayerComponent implements OnInit, OnDestroy, OnChanges {
},
},
});
if (this.startTime > 0) {
this.player.on('ready', () => {
this.player.seek = this.startTime;
});
}
this.player.on('video:timeupdate', () => {
this.timeUpdate.emit({
currentTime: this.player.currentTime,
duration: this.player.duration,
});
});
}
private getVideoType(url: string): string {
@@ -1,11 +1,13 @@
import {
Component,
ElementRef,
EventEmitter,
inject,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild,
} from '@angular/core';
@@ -27,6 +29,11 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
/** Channel to play */
@Input() channel!: Channel;
@Input() volume = 1;
@Input() startTime = 0;
@Output() timeUpdate = new EventEmitter<{
currentTime: number;
duration: number;
}>();
private readonly dataService = inject(DataService);
@@ -44,6 +51,19 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
this.videoPlayer.nativeElement.addEventListener('volumechange', () => {
this.onVolumeChange();
});
this.videoPlayer.nativeElement.addEventListener('loadedmetadata', () => {
if (this.startTime > 0) {
this.videoPlayer.nativeElement.currentTime = this.startTime;
}
});
this.videoPlayer.nativeElement.addEventListener('timeupdate', () => {
this.timeUpdate.emit({
currentTime: this.videoPlayer.nativeElement.currentTime,
duration: this.videoPlayer.nativeElement.duration,
});
});
}
/**
@@ -1,10 +1,12 @@
import {
Component,
ElementRef,
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation,
@@ -32,6 +34,11 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
/** VideoJs object */
player!: any;
@Input() volume = 1;
@Input() startTime = 0;
@Output() timeUpdate = new EventEmitter<{
currentTime: number;
duration: number;
}>();
/**
* Instantiate Video.js on component init
@@ -50,10 +57,23 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
);
this.player.volume(this.volume);
this.player.on('loadedmetadata', () => {
if (this.startTime > 0) {
this.player.currentTime(this.startTime);
}
});
this.player.on('volumechange', () => {
const currentVolume = this.player.volume();
localStorage.setItem('volume', currentVolume.toString());
});
this.player.on('timeupdate', () => {
this.timeUpdate.emit({
currentTime: this.player.currentTime(),
duration: this.player.duration(),
});
});
}
);
try {