From c59abb792391e2f7540a80bb8d989021fe0a5b80 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 15 Apr 2025 13:54:52 +0200 Subject: refactor jsp, part 1 --- web/script/player/mod.ts | 88 ++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 36 deletions(-) (limited to 'web/script/player/mod.ts') diff --git a/web/script/player/mod.ts b/web/script/player/mod.ts index 15c37da..82ee287 100644 --- a/web/script/player/mod.ts +++ b/web/script/player/mod.ts @@ -7,11 +7,11 @@ 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, get_track_kind } from "./mediacaps.ts"; import { Player } from "./player.ts"; import { Popup } from "./popup.ts"; import { Playersync, playersync_controls } from "./sync.ts" +import { WatchedState } from "./types_node.ts"; +import { FormatInfo, TrackKind } from "./types_stream.ts"; globalThis.addEventListener("DOMContentLoaded", () => { if (document.body.classList.contains("player")) { @@ -36,12 +36,26 @@ function toggle_fullscreen() { else document.documentElement.requestFullscreen() } +function get_continue_time(w: WatchedState): number { + if (typeof w == "string") return 0 + else return w.progress +} + +function get_query_start_time() { + const u = new URL(globalThis.location.href) + const p = u.searchParams.get("t") + if (!p) return + const x = parseFloat(p) + if (Number.isNaN(x)) return + return x +} function initialize_player(el: HTMLElement, node_id: string) { el.innerHTML = "" // clear the body const logger = new Logger(s => e("p", s)) - const player = new Player(node_id, logger) + const start_time = get_query_start_time() ?? 0 // TODO get_continue_time(ndata.userdata.watched); + const player = new Player(`/n/${encodeURIComponent(node_id)}/stream`, `/n/${encodeURIComponent(node_id)}/poster`, start_time, logger) const show_stats = new OVar(false); const idle_inhibit = new OVar(false) const sync_state = new OVar(undefined) @@ -72,13 +86,13 @@ function initialize_player(el: HTMLElement, node_id: string) { const step_track_kind = (kind: TrackKind) => { // TODO cycle through all of them const active = player.active_tracks.value.filter( - ts => get_track_kind(player.tracks![ts.track_index].kind) == kind) + ts => player.tracks![ts.track_index].kind == kind) if (active.length > 0) { for (const t of active) player.set_track_enabled(t.track_index, false) } else { const all_kind = (player.tracks ?? []) .map((track, index) => ({ index, track })) - .filter(({ track }) => get_track_kind(track.kind) == kind) + .filter(({ track }) => track.kind == kind) if (all_kind.length < 1) return logger.log(`No ${kind} tracks available`) player.set_track_enabled(all_kind[0].index, true) } @@ -92,7 +106,7 @@ function initialize_player(el: HTMLElement, node_id: string) { const track_select = (kind: TrackKind) => { const button = e("div", player.active_tracks.map(_ => { const active = player.active_tracks.value.filter( - ts => get_track_kind(player.tracks![ts.track_index].kind) == kind) + ts => player.tracks![ts.track_index].kind == kind) const enabled = active.length > 0 return e("button", MEDIA_KIND_ICONS[kind][+enabled], { class: "icon", @@ -105,7 +119,7 @@ function initialize_player(el: HTMLElement, node_id: string) { } else { const all_kind = (player.tracks ?? []) .map((track, index) => ({ index, track })) - .filter(({ track }) => get_track_kind(track.kind) == kind) + .filter(({ track }) => track.kind == kind) if (all_kind.length < 1) return player.set_track_enabled(all_kind[0].index, true) } @@ -138,7 +152,7 @@ function initialize_player(el: HTMLElement, node_id: string) { player.active_tracks.map(_ => { const tracks_avail = (player.tracks ?? []) .map((track, index) => ({ index, track })) - .filter(({ track }) => get_track_kind(track.kind) == kind); + .filter(({ track }) => track.kind == kind); if (!tracks_avail.length) return e("p", `No ${kind} tracks available.`) as HTMLElement; return e("ul", { class: "jsp-track-list" }, ...tracks_avail .map(({ track, index }): HTMLElement => { @@ -184,15 +198,16 @@ function initialize_player(el: HTMLElement, node_id: string) { ), pri = e("div", { class: "jsp-pri" }, pri_current = e("div", { class: "jsp-pri-current" }), - player.chapters.map( - chapters => e("div", ...chapters.map(chap => e("div", { - class: "jsp-chapter", - style: { - left: pri_map(chap.time_start ?? 0), - width: pri_map((chap.time_end ?? player.duration.value) - (chap.time_start ?? 0)) - } - }, e("p", chap.labels[0][1])))) - ), + // TODO + // player.chapters.map( + // chapters => e("div", ...chapters.map(chap => e("div", { + // class: "jsp-chapter", + // style: { + // left: pri_map(chap.time_start ?? 0), + // width: pri_map((chap.time_end ?? player.duration.value) - (chap.time_start ?? 0)) + // } + // }, e("p", chap.labels[0][1])))) + // ), player.active_tracks.map( tracks => e("div", ...tracks.map((t, i) => t.buffered.map( ranges => e("div", ...ranges.map( @@ -275,8 +290,8 @@ function initialize_player(el: HTMLElement, node_id: string) { else if (k.code == "ArrowRight") player.seek(player.position.value + 5) else if (k.code == "ArrowUp") player.seek(player.position.value - 60) else if (k.code == "ArrowDown") player.seek(player.position.value + 60) - else if (k.code == "PageUp") player.seek(find_closest_chaps(player).prev?.time_start ?? 0) - else if (k.code == "PageDown") player.seek(find_closest_chaps(player).next?.time_start ?? player.duration.value) + // else if (k.code == "PageUp") player.seek(find_closest_chaps(player).prev?.time_start ?? 0) + // else if (k.code == "PageDown") player.seek(find_closest_chaps(player).next?.time_start ?? player.duration.value) else return; k.preventDefault() }) @@ -339,25 +354,26 @@ function mouse_idle(e: HTMLElement, timeout: number): OVar { return idle } -export function show_profile(profile: EncodingProfile): string { - if (profile.audio) return `codec=${profile.audio.codec} br=${show.metric(profile.audio.bitrate, "b/s")}${profile.audio.sample_rate ? ` sr=${show.metric(profile.audio.sample_rate, "Hz")}` : ""}` - if (profile.video) return `codec=${profile.video.codec} br=${show.metric(profile.video.bitrate, "b/s")} w=${profile.video.width} preset=${profile.video.preset}` - if (profile.subtitles) return `codec=${profile.subtitles.codec}` - return `???` +export function show_format(format: FormatInfo): string { + // if (format.audio) return `codec=${format.audio.codec} br=${show.metric(format.audio.bitrate, "b/s")}${format.audio.sample_rate ? ` sr=${show.metric(format.audio.sample_rate, "Hz")}` : ""}` + // if (format.video) return `codec=${format.video.codec} br=${show.metric(format.video.bitrate, "b/s")} w=${format.video.width} preset=${format.video.preset}` + // if (format.subtitles) return `codec=${format.subtitles.codec}` + return `TODO` } export function show_volume(v: number): string { return `${v == 0 ? "-∞" : (Math.log10(v) * 10).toFixed(2)}dB | ${(v * 100).toFixed(2)}%` } -function find_closest_chaps(player: Player) { - const now = player.position.value - const chaps = player.chapters.value - let prev, next; - for (const c of chaps) { - const t_start = (c.time_start ?? 0) - next = c; - if (t_start > now) break - prev = c; - } - return { next, prev } -} +// TODO +// function find_closest_chaps(player: Player) { +// const now = player.position.value +// const chaps = player.chapters.value +// let prev, next; +// for (const c of chaps) { +// const t_start = (c.time_start ?? 0) +// next = c; +// if (t_start > now) break +// prev = c; +// } +// return { next, prev } +// } -- cgit v1.2.3-70-g09d2 From ad8016d8014af1e8dfb267fcdb51da63ab8ca4a9 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 16 Apr 2025 17:23:55 +0200 Subject: better debug info and loggin --- web/script/player/mod.ts | 19 +++++++++++-------- web/script/player/track/mse.ts | 7 +++++-- web/style/js-player.css | 2 ++ 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'web/script/player/mod.ts') diff --git a/web/script/player/mod.ts b/web/script/player/mod.ts index 82ee287..af62cde 100644 --- a/web/script/player/mod.ts +++ b/web/script/player/mod.ts @@ -66,11 +66,11 @@ function initialize_player(el: HTMLElement, node_id: string) { let mute_saved_volume = 1; const toggle_mute = () => { if (player.volume.value == 0) { - logger.log("Unmuted."); + logger.log("Unmuted.", "volume"); player.volume.value = mute_saved_volume } else { - logger.log("Muted."); + logger.log("Muted.", "volume"); mute_saved_volume = player.volume.value player.volume.value = 0. } @@ -281,8 +281,8 @@ function initialize_player(el: HTMLElement, node_id: string) { else if (k.code == "KeyS") screenshot_video(player.video) else if (k.code == "KeyJ") step_track_kind("subtitles") else if (k.code == "KeyM") toggle_mute() - else if (k.code == "Digit9") (player.volume.value /= 1.2), logger.log(`Volume decreased to ${show_volume(player.volume.value)}`) - else if (k.code == "Digit0") (player.volume.value *= 1.2), logger.log(`Volume increased to ${show_volume(player.volume.value)}`) + else if (k.code == "Digit9") (player.volume.value /= 1.2), logger.log(`Volume decreased to ${show_volume(player.volume.value)}`, "volume") + else if (k.code == "Digit0") (player.volume.value *= 1.2), logger.log(`Volume increased to ${show_volume(player.volume.value)}`, "volume") else if (k.key == "#") step_track_kind("audio") else if (k.key == "_") step_track_kind("video") else if (k.code == "KeyV") show_stats.value = !show_stats.value @@ -355,10 +355,13 @@ function mouse_idle(e: HTMLElement, timeout: number): OVar { } export function show_format(format: FormatInfo): string { - // if (format.audio) return `codec=${format.audio.codec} br=${show.metric(format.audio.bitrate, "b/s")}${format.audio.sample_rate ? ` sr=${show.metric(format.audio.sample_rate, "Hz")}` : ""}` - // if (format.video) return `codec=${format.video.codec} br=${show.metric(format.video.bitrate, "b/s")} w=${format.video.width} preset=${format.video.preset}` - // if (format.subtitles) return `codec=${format.subtitles.codec}` - return `TODO` + let o = `${format.codec} br=${show.metric(format.bitrate, "b/s")} ac=${format.containers.join(",")}` + if (format.width) o += ` w=${format.width}` + if (format.height) o += ` h=${format.height}` + if (format.samplerate) o += ` ar=${show.metric(format.samplerate, "Hz")}` + if (format.channels) o += ` ac=${format.channels}` + if (format.bit_depth) o += ` bits=${format.bit_depth}` + return o } export function show_volume(v: number): string { return `${v == 0 ? "-∞" : (Math.log10(v) * 10).toFixed(2)}dB | ${(v * 100).toFixed(2)}%` diff --git a/web/script/player/track/mse.ts b/web/script/player/track/mse.ts index 5565a6b..237b6f6 100644 --- a/web/script/player/track/mse.ts +++ b/web/script/player/track/mse.ts @@ -9,6 +9,7 @@ import { BufferRange, Player } from "../player.ts"; import { PlayerTrack, AppendRange, TARGET_BUFFER_DURATION, MIN_BUFFER_DURATION } from "./mod.ts"; import { e } from "../../jshelper/src/element.ts"; import { FormatInfo, FragmentIndex, StreamContainer, TrackInfo } from "../types_stream.ts"; +import { show_format } from "../mod.ts"; interface UsableFormat { format_index: number, usable_index: number, format: FormatInfo, container: StreamContainer } @@ -154,8 +155,9 @@ export class MSEPlayerTrack extends PlayerTrack { this.current_load = frag; // TODO why is appending so unreliable?! sometimes it does not add it this.source_buffer.changeType(track_to_content_type(this.active_format.value!.format, this.active_format.value!.container)); + this.source_buffer.timestampOffset = this.active_format.value?.container == "mpeg4" ? frag.start : 0 // this.source_buffer.timestampOffset = this.active_format.value?.format.remux ? 0 : frag.start - this.source_buffer.timestampOffset = 0 + // this.source_buffer.timestampOffset = 0 this.source_buffer.appendBuffer(frag.buf); } } @@ -170,7 +172,8 @@ export class MSEPlayerTrack extends PlayerTrack { e("pre", p ? `mse track ${this.track_index}: format ${p.format_index} (${p.format.remux ? "remux" : "transcode"})` - + `\n\ttype: ${track_to_content_type(p.format, p.container)} br=${p.format.bitrate}` + + `\n\tformat: ${show_format(p.format)}` + + `\n\tbuffer type: ${track_to_content_type(p.format, p.container)}` + `\n\tbuffered: ${rtype("buffered", b)} / queued: ${rtype("queued", b)} / loading: ${rtype("loading", b)}` : "" ) as HTMLElement diff --git a/web/style/js-player.css b/web/style/js-player.css index c9a48e9..33669a5 100644 --- a/web/style/js-player.css +++ b/web/style/js-player.css @@ -112,6 +112,8 @@ padding: 0.15em; margin: 0px; font-size: large; +} +.jsp .jsh-log-line-appear { animation-name: appear; animation-timing-function: linear; animation-duration: 0.5s; -- cgit v1.2.3-70-g09d2