aboutsummaryrefslogtreecommitdiff
path: root/web/script
diff options
context:
space:
mode:
Diffstat (limited to 'web/script')
-rw-r--r--web/script/player/mediacaps.ts3
-rw-r--r--web/script/player/mod.ts40
-rw-r--r--web/script/player/player.ts2
-rw-r--r--web/script/player/popup.ts58
-rw-r--r--web/script/player/track.ts6
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)