diff options
Diffstat (limited to 'web/script/player')
-rw-r--r-- | web/script/player/mediacaps.ts | 3 | ||||
-rw-r--r-- | web/script/player/mod.ts | 40 | ||||
-rw-r--r-- | web/script/player/player.ts | 2 | ||||
-rw-r--r-- | web/script/player/popup.ts | 58 | ||||
-rw-r--r-- | web/script/player/track.ts | 6 |
5 files changed, 103 insertions, 6 deletions
diff --git a/web/script/player/mediacaps.ts b/web/script/player/mediacaps.ts index 7b57302..33682be 100644 --- a/web/script/player/mediacaps.ts +++ b/web/script/player/mediacaps.ts @@ -96,7 +96,8 @@ const FFMPEG_ENCODER_CODEC_MAP: { [key: string]: string } = { "libopus": "A_OPUS", } -export function get_track_kind(track: SourceTrackKind): "audio" | "video" | "subtitles" { +export type TrackKind = "audio" | "video" | "subtitles" +export function get_track_kind(track: SourceTrackKind): TrackKind { if (track.audio) return "audio" if (track.video) return "video" if (track.subtitles) return "subtitles" diff --git a/web/script/player/mod.ts b/web/script/player/mod.ts index ce3c113..11690b6 100644 --- a/web/script/player/mod.ts +++ b/web/script/player/mod.ts @@ -7,7 +7,9 @@ import { OVar, show } from "../jshelper/mod.ts"; import { e } from "../jshelper/mod.ts"; import { Logger } from "../jshelper/src/log.ts"; import { EncodingProfile } from "./jhls.d.ts"; +import { TrackKind } from "./mediacaps.ts"; import { Player } from "./player.ts"; +import { Popup } from "./popup.ts"; globalThis.addEventListener("DOMContentLoaded", () => { if (document.body.classList.contains("player")) { @@ -20,6 +22,12 @@ globalThis.addEventListener("DOMContentLoaded", () => { } }) +const MEDIA_KIND_ICONS: { [key in TrackKind]: [string, string] } = { + video: ["tv_off", "tv"], + audio: ["volume_off", "volume_up"], + subtitles: ["subtitles_off", "subtitles"], +} + function initialize_player(el: HTMLElement, node_id: string) { el.innerHTML = "" // clear the body @@ -32,8 +40,28 @@ function initialize_player(el: HTMLElement, node_id: string) { let pri_current: HTMLElement; let pri: HTMLElement; + + const popups = e("div") + + const track_select = (kind: TrackKind) => { + let enabled = true + const button = e("button", MEDIA_KIND_ICONS[kind][+enabled], { + class: "iicon", + onclick: () => { + enabled = !enabled + button.textContent = MEDIA_KIND_ICONS[kind][+enabled] + } + }) + new Popup(button, popups, () => + e("div", { class: "jsp-track-select-popup" }, "This is some text") + ) + return button + } + const controls = e("div", { class: "jsp-controls" }, - player.playing.map(playing => e("button", playing ? "||" : "|>", { onclick: toggle_playing })), + player.playing.map(playing => + e("button", { class: "iicon" }, playing ? "pause" : "play_arrow", { onclick: toggle_playing }) + ), e("p", { class: "jsp-status" }, player.position.map(v => e("span", show.duration(v))), e("br"), player.position.map(v => e("span", show.duration(v - player.duration.value))) @@ -55,7 +83,13 @@ function initialize_player(el: HTMLElement, node_id: string) { ))) ) ), - e("button", "X", { + e("div", { class: "jsp-track-select" }, + track_select("video"), + track_select("audio"), + track_select("subtitles") + ), + e("button", "fullscreen", { + class: "iicon", onclick() { if (document.fullscreenElement) document.exitFullscreen() else document.documentElement.requestFullscreen() @@ -76,6 +110,7 @@ function initialize_player(el: HTMLElement, node_id: string) { ) ))), logger.element, + popups, controls, ) el.append(pel) @@ -102,7 +137,6 @@ function initialize_player(el: HTMLElement, node_id: string) { else return; k.preventDefault() }) - } function mouse_idle(e: HTMLElement, timeout: number, cb: (b: boolean) => unknown) { diff --git a/web/script/player/player.ts b/web/script/player/player.ts index cc778f0..81a315e 100644 --- a/web/script/player/player.ts +++ b/web/script/player/player.ts @@ -83,7 +83,7 @@ export class Player { this.profile_selector = new ProfileSelector(this, this.downloader.bandwidth, metadata) this.set_pers("Checking codec support...") await this.profile_selector.init() - + this.duration.value = metadata.duration this.video.src = URL.createObjectURL(this.media_source) this.media_source.addEventListener("sourceopen", async () => { diff --git a/web/script/player/popup.ts b/web/script/player/popup.ts new file mode 100644 index 0000000..fb596b0 --- /dev/null +++ b/web/script/player/popup.ts @@ -0,0 +1,58 @@ + +export class Popup { + trigger_hov = false + content_hov = false + content?: HTMLElement + shown = false + + constructor( + public trigger: HTMLElement, + public container: HTMLElement, + public new_content: () => HTMLElement + ) { + trigger.onmouseenter = () => { + this.trigger_hov = true; + this.update_hov() + } + trigger.onmouseleave = () => { + this.trigger_hov = false; + this.update_hov() + } + } + + set_shown(s: boolean) { + if (this.shown == s) return + if (s) { + this.content = this.new_content() + this.content.addEventListener("mouseenter", () => { + this.content_hov = true; + this.update_hov() + }) + this.content.addEventListener("mouseleave", () => { + this.content_hov = false; + this.update_hov() + }) + this.container.append(this.content) + } else { + this.container.removeChild(this.content!) + this.content = undefined + } + this.shown = s + } + + hide_timeout?: number + update_hov() { + if (this.content_hov || this.trigger_hov) { + this.set_shown(true) + if (this.hide_timeout !== undefined) { + clearTimeout(this.hide_timeout) + this.hide_timeout = undefined + } + } else { + if (this.hide_timeout === undefined) this.hide_timeout = setTimeout(() => { + this.set_shown(false) + this.hide_timeout = undefined + }, 100) + } + } +} diff --git a/web/script/player/track.ts b/web/script/player/track.ts index cc21763..c7d90da 100644 --- a/web/script/player/track.ts +++ b/web/script/player/track.ts @@ -32,7 +32,7 @@ export class PlayerTrack { async init() { await this.player.profile_selector.select_optimal_profile(this.track_index, this.profile); const ct = track_to_content_type(this.track_from_profile())! - console.log("source buffer content-type: " + ct); + console.log(`track ${this.track_index} source buffer content-type: ${ct}`); this.source_buffer = this.player.media_source.addSourceBuffer(ct); this.source_buffer.mode = "segments"; this.source_buffer.addEventListener("updateend", () => { @@ -51,6 +51,10 @@ export class PlayerTrack { console.error("sourcebuffer abort", e); }); } + destroy() { + console.log(`destroy source buffer for track ${this.track_index}`); + this.player.media_source.removeSourceBuffer(this.source_buffer) + } track_from_profile(): SourceTrack { if (this.profile.value) return profile_to_partial_track(this.profile.value) |