chore: update Angular cache and TypeScript build info
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild, input } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild, input, OnDestroy, AfterViewInit } from '@angular/core';
|
||||
import { HistoryService } from '../../services/history.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-video-player',
|
||||
@@ -6,8 +7,12 @@ import { ChangeDetectionStrategy, Component, ElementRef, ViewChild, input } from
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class VideoPlayerComponent {
|
||||
export class VideoPlayerComponent implements AfterViewInit, OnDestroy {
|
||||
videoSource = input.required<string>();
|
||||
// Optional resume position (in seconds)
|
||||
startPositionSeconds = input<number | null>(null);
|
||||
// Watch history id to update progress
|
||||
watchHistoryId = input<string | null>(null);
|
||||
|
||||
@ViewChild('player', { static: false }) playerRef?: ElementRef<HTMLVideoElement>;
|
||||
|
||||
@@ -15,6 +20,90 @@ export class VideoPlayerComponent {
|
||||
return this.playerRef?.nativeElement ?? null;
|
||||
}
|
||||
|
||||
private progressTimer: any = null;
|
||||
private lastSent = 0;
|
||||
|
||||
constructor(private history: HistoryService) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
const v = this.el; if (!v) return;
|
||||
// Seek to saved position when metadata is ready
|
||||
v.addEventListener('loadedmetadata', () => {
|
||||
const pos = this.startPositionSeconds();
|
||||
if (typeof pos === 'number' && pos > 0 && isFinite(pos)) {
|
||||
try { v.currentTime = Math.min(Math.max(pos, 0), v.duration || pos); } catch {}
|
||||
}
|
||||
});
|
||||
|
||||
// Start periodic progress updates when playing
|
||||
v.addEventListener('play', () => {
|
||||
// Ensure we seek on first play if metadata event already fired
|
||||
const pos = this.startPositionSeconds();
|
||||
if (typeof pos === 'number' && pos > 0 && isFinite(pos)) {
|
||||
try {
|
||||
if (!isNaN(v.currentTime) && v.currentTime < Math.max(0, pos - 1)) v.currentTime = pos;
|
||||
} catch {}
|
||||
}
|
||||
this.startProgressLoop();
|
||||
});
|
||||
v.addEventListener('pause', () => this.sendProgressOnce());
|
||||
v.addEventListener('ended', () => { this.sendProgressOnce(true); this.stopProgressLoop(); });
|
||||
|
||||
// As a safeguard, send progress on visibility change/unload
|
||||
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
||||
window.addEventListener('beforeunload', this.onBeforeUnload);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.stopProgressLoop();
|
||||
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
||||
window.removeEventListener('beforeunload', this.onBeforeUnload);
|
||||
}
|
||||
|
||||
private onVisibilityChange = () => {
|
||||
if (document.hidden) this.sendProgressOnce();
|
||||
};
|
||||
|
||||
private onBeforeUnload = () => {
|
||||
this.sendProgressOnce();
|
||||
};
|
||||
|
||||
private startProgressLoop(): void {
|
||||
this.stopProgressLoop();
|
||||
this.progressTimer = setInterval(() => this.sendProgressDebounced(), 4000);
|
||||
}
|
||||
|
||||
private stopProgressLoop(): void {
|
||||
if (this.progressTimer) {
|
||||
clearInterval(this.progressTimer);
|
||||
this.progressTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private currentPos(): number {
|
||||
const v = this.el; if (!v) return 0;
|
||||
try { return Math.max(0, Math.floor(v.currentTime || 0)); } catch { return 0; }
|
||||
}
|
||||
|
||||
private sendProgressDebounced(): void {
|
||||
const now = Date.now();
|
||||
if (now - this.lastSent < 3500) return;
|
||||
this.lastSent = now;
|
||||
this.sendProgress(false);
|
||||
}
|
||||
|
||||
private sendProgressOnce(final: boolean = false): void {
|
||||
this.sendProgress(final);
|
||||
}
|
||||
|
||||
private sendProgress(final: boolean): void {
|
||||
const id = this.watchHistoryId();
|
||||
if (!id) return;
|
||||
const pos = this.currentPos();
|
||||
this.history.updateWatchProgress(id, pos, pos).subscribe({ next: () => {}, error: () => {} });
|
||||
if (final) this.lastSent = Date.now();
|
||||
}
|
||||
|
||||
togglePlayPause(): void {
|
||||
const v = this.el; if (!v) return;
|
||||
if (v.paused) v.play(); else v.pause();
|
||||
|
||||
Reference in New Issue
Block a user