Mercurial > code > home > repos > video
view src/VideoPage.ts @ 36:ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
author | drewp@bigasterisk.com |
---|---|
date | Tue, 03 Dec 2024 00:08:22 -0800 |
parents | 9edb3df3cdb3 |
children | 7cacfae58430 |
line wrap: on
line source
import { LitElement, PropertyValues, css, html, unsafeCSS } from "lit"; import { customElement, property } from "lit/decorators.js"; import { PagePlayer, ShakaVideoElement } from "./PagePlayer"; import maincss from "./main.css?inline"; export { SlProgressBar } from "@shoelace-style/shoelace"; export { PagePlayer } from "./PagePlayer"; export { VideoSection } from "./VideoSection"; interface VideoFile { webRelPath: string; label: string; thumbRelPath: string; webDataPath: string; } interface Subdir { label: string; path: string; } function subdirQuery(subdir: string): string { return "subdir=" + encodeURIComponent(subdir); } @customElement("video-page") export class VideoPage extends LitElement { videos: VideoFile[]; subdirs: Subdir[]; @property() pathSegs: { label: string; subdir: string }[]; constructor() { super(); this.videos = []; this.subdirs = []; this.pathSegs = []; this.loadVideos(); } protected firstUpdated(_changedProperties: PropertyValues): void { document.addEventListener("keydown", (e) => { if (e.key == "Escape") { this.closePlayer(); } }); } updatePathSegs(subdir: string) { this.pathSegs = [{ label: "TOP", subdir: "/" }]; if (subdir != "/") { let acc = ""; const segs = subdir.split("/"); segs.splice(0, 1); // the root for (let seg of segs) { acc += "/" + seg; this.pathSegs.push({ label: seg, subdir: acc }); } } } async loadVideos() { const u = new URL(location.href); const subdir = u.searchParams.get("subdir") || "/"; this.updatePathSegs(subdir); const resp = await (await fetch("api/videos?" + subdirQuery(subdir))).json(); this.videos = resp.videos as VideoFile[]; this.subdirs = resp.subdirs as Subdir[]; this.requestUpdate(); } static styles = [ unsafeCSS(maincss), css` .listing a { font-size: 20px; text-transform: uppercase; text-underline-offset: 10px; } .subdir { vertical-align: top; color: white; padding: 11px; display: inline-block; width: 300px; background: #4ea1bd21; margin: 5px; border-bottom-right-radius: 29px; } #scrim { position: fixed; background: #000000b5; inset: 0; display: none; } `, ]; render() { return html` <sl-breadcrumb> ${this.pathSegs.map( (seg, i) => html`<sl-breadcrumb-item> <a href="./?${subdirQuery(seg.subdir)}"> ${i == 0 ? html`<sl-icon name="house"></sl-icon>`:''} ${seg.label} </a></sl-breadcrumb-item>`)} </sl-breadcrumb> <div class="listing"> ${this.subdirs.map((s) => html`<div class="subdir"><a href="${"./?" + subdirQuery(s.path)}">${s.label}</a></div>`)} ${this.videos.map( (v) => html`<video-section @playVideo=${this.playVideo} thumbRelPath="${v.thumbRelPath}" title="${v.label}" manifest="/video/files/${v.webDataPath}"></video-section>` )} </div> <p><a href="ingest/">Add new videos...</a></p> <div id="scrim" @click=${this.closePlayer}></div> <page-player manifest=""></page-player> `; } escapeALittle(fileUri: string) : string { return fileUri.replace('#', encodeURIComponent('#')); } playVideo(ev: CustomEvent) { const player = this.shadowRoot!.querySelector("page-player")! as PagePlayer; player.manifest = this.escapeALittle(ev.detail.manifest); const sv = player.shadowRoot!.querySelector("shaka-video")! as ShakaVideoElement; sv.src = player.manifest; sv.autoplay = true; player.size = "big"; this.shadowRoot!.querySelector("#scrim")!.style.display = "block"; } closePlayer() { const player = this.shadowRoot!.querySelector("page-player")! as PagePlayer; player.size = "hidden"; this.shadowRoot!.querySelector("#scrim")!.style.display = "none"; } }