aboutsummaryrefslogtreecommitdiff
path: root/web/script/player/mod.ts
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-04-16 20:06:01 +0200
committermetamuffin <metamuffin@disroot.org>2025-04-16 20:06:01 +0200
commitd26849375c70c795fdf664f9dfea68c273b6d483 (patch)
tree53ad4f0eff3604e80b27ff0abf0438ea6c69d432 /web/script/player/mod.ts
parent1cd966f7454f052fda6c6c9ae1597479f05e23d9 (diff)
parentcdf95d7b80bd2b78895671da8f462145bb5db522 (diff)
downloadjellything-d26849375c70c795fdf664f9dfea68c273b6d483.tar
jellything-d26849375c70c795fdf664f9dfea68c273b6d483.tar.bz2
jellything-d26849375c70c795fdf664f9dfea68c273b6d483.tar.zst
Merge branch 'rewrite-stream'
Diffstat (limited to 'web/script/player/mod.ts')
-rw-r--r--web/script/player/mod.ts99
1 files changed, 59 insertions, 40 deletions
diff --git a/web/script/player/mod.ts b/web/script/player/mod.ts
index 53f13bd..e8cde94 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,10 +36,24 @@ 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(node_id: string): HTMLElement {
const logger = new Logger<string>(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<Playersync | undefined>(undefined)
@@ -50,11 +64,11 @@ function initialize_player(node_id: string): HTMLElement {
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.
}
@@ -70,13 +84,13 @@ function initialize_player(node_id: string): HTMLElement {
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)
}
@@ -90,7 +104,7 @@ function initialize_player(node_id: string): HTMLElement {
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",
@@ -103,7 +117,7 @@ function initialize_player(node_id: string): HTMLElement {
} 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)
}
@@ -136,7 +150,7 @@ function initialize_player(node_id: string): HTMLElement {
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 => {
@@ -182,15 +196,16 @@ function initialize_player(node_id: string): HTMLElement {
),
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(
@@ -263,8 +278,8 @@ function initialize_player(node_id: string): HTMLElement {
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
@@ -272,8 +287,8 @@ function initialize_player(node_id: string): HTMLElement {
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()
})
@@ -338,25 +353,29 @@ function mouse_idle(e: HTMLElement, timeout: number): OVar<boolean> {
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 {
+ 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)}%`
}
-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 }
+// }