diff options
| author | metamuffin <metamuffin@disroot.org> | 2024-01-28 01:08:49 +0100 | 
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2024-01-28 01:08:49 +0100 | 
| commit | b514ec8cea2c2143e0bd7a0eb377c96a6f091d0d (patch) | |
| tree | 25b3f8c80e1754b3e9e5d5419d5be276f940b1c1 /web/script/player/track/vtt.ts | |
| parent | 59ef86b0a637ec3ce44ca495c6d22ddf61649134 (diff) | |
| download | jellything-b514ec8cea2c2143e0bd7a0eb377c96a6f091d0d.tar jellything-b514ec8cea2c2143e0bd7a0eb377c96a6f091d0d.tar.bz2 jellything-b514ec8cea2c2143e0bd7a0eb377c96a6f091d0d.tar.zst | |
add broken positioning code für vtt
Diffstat (limited to 'web/script/player/track/vtt.ts')
| -rw-r--r-- | web/script/player/track/vtt.ts | 80 | 
1 files changed, 80 insertions, 0 deletions
| diff --git a/web/script/player/track/vtt.ts b/web/script/player/track/vtt.ts new file mode 100644 index 0000000..c426fa1 --- /dev/null +++ b/web/script/player/track/vtt.ts @@ -0,0 +1,80 @@ +import { SourceTrack, JvttCue } from "../jhls.d.ts"; +import { Player } from "../player.ts"; +import { PlayerTrack } from "./mod.ts"; + +export async function create_vtt_track(player: Player, node_id: string, track_index: number, metadata: SourceTrack): Promise<VttPlayerTrack | undefined> { +  let index: JvttCue[]; +  try { +    const res = await fetch(`/n/${encodeURIComponent(player.node_id)}/stream?format=jvtt&tracks=${track_index}`, { headers: { "Accept": "application/json" } }); +    if (!res.ok) return player.error.value = "Cannot download index.", undefined; +    let ai!: JvttCue[] & { error: string; }; +    try { ai = await res.json(); } +    catch (_) { player.set_pers("Error: Failed to fetch node"); } +    if (ai.error) return player.set_pers("server error: " + ai.error), undefined; +    index = ai; +  } catch (e) { +    if (e instanceof TypeError) { +      player.set_pers("Cannot download subtitles: Network Error"); +      return undefined +    } else throw e; +  } +  const t = new VttPlayerTrack(player, node_id, track_index, metadata, index); +  return t; +} + +export class VttPlayerTrack extends PlayerTrack { +  private track: TextTrack; + +  constructor( +    private player: Player, +    private node_id: string, +    track_index: number, +    private metadata: SourceTrack, +    public cues: JvttCue[] +  ) { +    super(track_index); +    this.track = this.player.video.addTextTrack("subtitles", metadata.name, metadata.language); +    for (const cue of cues) { +      this.track.addCue(create_cue(cue)); +    } +    this.track.mode = "showing"; +    this.abort.signal.addEventListener("abort", () => { +      // TODO disable subtitles properly +      this.track.mode = "hidden"; +    }); +  } +} + +function create_cue(cue: JvttCue): VTTCue { +  const c = new VTTCue(cue.start, cue.end, cue.content); +  const props = parse_layout_properties(cue.content.split("\n")[0]) +  if (props) { +    c.text = cue.content.split("\n").slice(1).join("\n") +    // TODO this does not work at all... +    const region = new VTTRegion() +    if ("position" in props && props.position.endsWith("%")) +      region.regionAnchorX = parseFloat(props.position.replace("%", "")) +    if ("line" in props && props.line.endsWith("%")) +      region.regionAnchorY = parseFloat(props.line.replace("%", "")) +    if ("align" in props) +      c.align = props.align as AlignSetting +    c.region = region +  } else { +    c.line = -2; +  } +  return c +} + +function parse_layout_properties(s: string): undefined | Record<string, string> { +  const o: Record<string, string> = {} +  for (const tok of s.split(" ")) { +    const [k, v, ...rest] = tok.split(":") +    if (!v || rest.length) return undefined +    o[k] = v +  } +  // some common keys to prevent false positives +  if ("position" in o) return o +  if ("align" in o) return o +  if ("line" in o) return o +  return undefined +} | 
