From 3bb695aaf03fad9ad3318a5feaec30d8743b25e2 Mon Sep 17 00:00:00 2001 From: WakelessSloth56 Date: Mon, 26 Aug 2024 20:51:24 +0800 Subject: [PATCH] refactor(player): media resources field --- src/core/data.ts | 32 ++++++++++++++++---------------- src/core/player.ts | 41 +++++++++++++++++++++++++---------------- src/core/utils.ts | 2 +- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/core/data.ts b/src/core/data.ts index 117b234..06fcc6d 100644 --- a/src/core/data.ts +++ b/src/core/data.ts @@ -27,7 +27,7 @@ import { import { EDC, PlayerMetadata } from './metadata'; import Player from './player'; import { - fTime, + formatTime, opacityInvisible, opacityVisible, randomStr, @@ -134,7 +134,7 @@ function initDanmaku(stage: HTMLElement, url: string, onload: () => void) { } function hasDanmaku(p: Player) { - return p.danmakuUrl ? true : false; + return p.resources.danmaku ? true : false; } function initSubtitle( @@ -155,7 +155,7 @@ function initSubtitle( } function hasSubtitle(p: Player) { - return p.subtitleUrl ? true : false; + return p.resources.subtitle ? true : false; } // ====================================================================== // @@ -226,7 +226,7 @@ const progressBar = new EDC('input', 'progress') P.data.progressInputting = true; const value = E.valueAsNumber; const popup = P.elements.progressPopup; - popup.textContent = fTime(P.video.duration * value); + popup.textContent = formatTime(P.video.duration * value); popup.style.left = `calc(${value * 100}% + (${ 8 - value * 100 * 0.15 }px))`; @@ -255,25 +255,25 @@ const timeInput = new EDC('input', 'timeInput') if (E.validity.valid) { P.seek(timeToSeconds(E.value)); } else { - E.value = fTime(P.video.currentTime, true); + E.value = formatTime(P.video.currentTime, true); } }, }) .videoEvents({ canplay: (P, E, V) => { - E.value = P.fCurrentTime(true); - E.max = fTime(V.duration, true); + E.value = P.currentTime(true); + E.max = formatTime(V.duration, true); }, timeupdate: (P, E, V) => { - E.value = P.fCurrentTime(true); + E.value = P.currentTime(true); }, }); const timeCurrent = new EDC('span', 'timeCurrent') // .html('--:--') .videoEvents({ - canplay: (P, E, V) => (E.textContent = P.fCurrentTime()), - timeupdate: (P, E, V) => (E.textContent = P.fCurrentTime()), + canplay: (P, E, V) => (E.textContent = P.currentTime()), + timeupdate: (P, E, V) => (E.textContent = P.currentTime()), }); const timeTotal = new EDC('span') @@ -283,7 +283,7 @@ const timeTotal = new EDC('span') toggleDisplay(P.elements.timeInput, P.elements.timeCurrent), }) .videoEvents({ - canplay: (_, E, V) => (E.textContent = fTime(V.duration)), + canplay: (_, E, V) => (E.textContent = formatTime(V.duration)), }); const playbackRate = new EDC('select', 'playbackRate') // @@ -409,7 +409,7 @@ const danmakuList = new EDC('div', 'danmakuList') let html = ''; for (const data of timeline) { html += // for performance, do not use document.createElement - `
  • ${fTime( + `
  • ${formatTime( data.stime / 1e3, overHour )}` + @@ -425,7 +425,7 @@ const subtitleStage = new EDC('div', 'subtitleStage') .condition(hasSubtitle) .selfEvents({ create: (P, E) => { - P.subtitleManager = initSubtitle(E, P.video, P.subtitleUrl); + P.subtitleManager = initSubtitle(E, P.video, P.resources.subtitle); P.firePlayerEvent('subtitleload'); P.data.subtitleOn = true; P.setData('subtitleOn', true); @@ -440,7 +440,7 @@ const danmakuStage = new EDC('div', 'danmakuStage') .condition(hasDanmaku) .selfEvents({ create: (P, E) => { - P.commentManager = initDanmaku(E, P.danmakuUrl, () => + P.commentManager = initDanmaku(E, P.resources.danmaku, () => P.firePlayerEvent('danmakuload') ); if (P.options.danmakuSizeOffset) { @@ -526,7 +526,7 @@ const hotkeys = (P: Player, T: KeyboardEvent) => { ], [ 'Time', - `${P.fCurrentTime()} / ${fTime( + `${P.currentTime()} / ${formatTime( P.video.duration )} (${P.video.playbackRate.toFixed(2)}x)`, ], @@ -540,7 +540,7 @@ const hotkeys = (P: Player, T: KeyboardEvent) => { break; case 81: // Q console.log(P.video.currentTime); - P.toast(`Time: ${P.fCurrentTime()} (${P.video.currentTime})`); + P.toast(`Time: ${P.currentTime()} (${P.video.currentTime})`); break; default: break; diff --git a/src/core/player.ts b/src/core/player.ts index aa07796..4c24d9c 100644 --- a/src/core/player.ts +++ b/src/core/player.ts @@ -24,7 +24,7 @@ import { bindMetaEvent, PlayerMetadata } from './metadata'; import { appendChild, clamp, - fTime, + formatTime, StrAnyKV, StrGenKV, toggleClass, @@ -41,20 +41,24 @@ interface PlayerData extends StrAnyKV { fullscreen?: boolean; } +interface MediaResources { + video: string; + danmaku?: string; + subtitle?: string; +} + export default class Player { - options: PlayerOptions; + readonly options: PlayerOptions; readonly #metadata: PlayerMetadata; readonly title: string; - readonly videoUrl: string; + readonly resources: Readonly; readonly video: HTMLVideoElement; readonly style: HTMLStyleElement; readonly container: HTMLDivElement; - readonly danmakuUrl: string; + readonly elements: StrGenKV = {}; + readonly data: PlayerData = {}; commentManager: CommentManager; - readonly subtitleUrl: string; subtitleManager: ASS; - elements: StrGenKV = {}; - data: PlayerData = {}; constructor( container: HTMLDivElement, @@ -69,9 +73,9 @@ export default class Player { this.options = options; container.classList.add('player'); container.tabIndex = 10; + this.container = container; + this.title = title; { - this.title = title; - this.videoUrl = videoUrl; const video = document.createElement('video'); container.appendChild(video); video.src = videoUrl; @@ -82,9 +86,11 @@ export default class Player { this.style = style; container.appendChild(style); } - this.container = container; - this.danmakuUrl = danmakuUrl; - this.subtitleUrl = subtitleUrl; + this.resources = { + video: videoUrl, + danmaku: danmakuUrl, + subtitle: subtitleUrl, + }; this.#bindElements(); this.#bindEvents(); { @@ -154,7 +160,7 @@ export default class Player { } /** - * Sets both `Player.data` and `HTMLElement.dataset` + * Note: Sets both `Player.data` and `HTMLElement.dataset` */ setData(key: string, value: any) { this.container.dataset[key] = value; @@ -179,8 +185,11 @@ export default class Player { this.firePlayerEvent('toast', { content: html }); } - fCurrentTime(alwaysHour?: boolean) { - return fTime( + /** + * @returns formatted current playback position + */ + currentTime(alwaysHour?: boolean) { + return formatTime( this.video.currentTime, alwaysHour === undefined ? this.data.overHour : alwaysHour ); @@ -189,7 +198,7 @@ export default class Player { seek(time: number) { const fixedTime = clamp(time, 0, this.video.duration); this.toast( - `Seek: ${fTime(fixedTime, this.data.overHour)} / ${fTime( + `Seek: ${formatTime(fixedTime, this.data.overHour)} / ${formatTime( this.video.duration )}` ); diff --git a/src/core/utils.ts b/src/core/utils.ts index 35c0a45..0cb0c1b 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -136,7 +136,7 @@ export function opacityInvisible(element: HTMLElement) { addClass(element, 'invisible'); } -export function fTime(seconds: number, alwaysHour?: boolean) { +export function formatTime(seconds: number, alwaysHour?: boolean) { const h = Math.floor(seconds / 3600); const m = Math.floor(seconds / 60) % 60; const s = Math.floor(seconds % 60);