Mercurial > code > home > repos > video
changeset 45:df51269bcef4
fix back/fwd nav and player loading
author | drewp@bigasterisk.com |
---|---|
date | Fri, 06 Dec 2024 01:02:33 -0800 |
parents | 239a83d46d48 |
children | 882d0bb0f801 |
files | src/VideoPage.ts src/VideoSection.ts |
diffstat | 2 files changed, 89 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/src/VideoPage.ts Fri Dec 06 01:01:05 2024 -0800 +++ b/src/VideoPage.ts Fri Dec 06 01:02:33 2024 -0800 @@ -1,12 +1,13 @@ +import { Router } from "@lit-labs/router"; import { LitElement, PropertyValues, TemplateResult, css, html, unsafeCSS } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, queryAsync } 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 { VBreadcrumbs } from "./VBreadcrumbs"; export { VideoSection } from "./VideoSection"; -import { Routes, Router } from "@lit-labs/router"; -export { VBreadcrumbs } from "./VBreadcrumbs"; + interface VideoFile { webRelPath: string; webDataPath: string; @@ -18,9 +19,12 @@ path: string; } -interface VideoListings { +interface PageData { + webDirRelPath: string; + dirLabel: string; videos: VideoFile[]; subdirs: Subdir[]; + autoplay: VideoFile | null; } function subdirQuery(subdir: string): string { @@ -29,39 +33,24 @@ class route { path = "/video/*"; - videoListings: VideoListings | null = null; - showVid: string | null = null; - dirName?: string; - - link(wrp: string): string { - return "/video/" + wrp; - } + pageData: PageData | null = null; async enter(params: { [key: string]: string | undefined }): Promise<boolean> { - const webRelPath = "/" + params[0]!; - this.dirName = webRelPath.replace(/.*\/([^/]+)/, "$1"); + const webRelPath = "/" + params[0]!; // could be /a/dir/ or /a/video + console.log("enter", webRelPath); const resp = await fetch("/video/api/videos?" + subdirQuery(webRelPath)); if (resp.status == 404) { return false; } - this.videoListings = await resp.json(); - - if (webRelPath.endsWith("/")) { - this.showVid = null; - } else { - this.showVid = webRelPath; - } + this.pageData = await resp.json(); + if (!this.pageData) return false; return true; } render(p: { [key: string]: string | undefined }) { - return html`<video-page2 - .link=${this.link.bind(this)} - .showVid=${this.showVid} - .videoListings=${this.videoListings} - .dirName=${this.dirName} - ></video-page2>`; + console.log("render", this.pageData); + return html`<video-page2 .pageData=${this.pageData}></video-page2>`; } } @@ -70,13 +59,23 @@ static styles = [unsafeCSS(maincss)]; private _router = new Router(this, [new route()], {}); + constructor() { + super(); + window.rr = this._router; + } + render() { - const requestedPath = "/" + this._router.params[0]; - + const pd = (this._router.routes[0] as route).pageData; + if (!pd) { + console.log("no page data", this._router.routes); + return html`loading...`; + throw new Error("no page data"); + } + console.log("yes page data", pd); return html` <header> - <img src=${this._router.link("/video/logo1.png")} title="JelloBello" /> - <v-breadcrumbs .link=${this._router.link} dirPath=${requestedPath}></v-breadcrumbs> + <img src="/video/logo1.png" title="JelloBello" /> + <v-breadcrumbs dirPath=${pd.webDirRelPath}></v-breadcrumbs> </header> <main>${this._router.outlet()}</main> <footer> @@ -89,29 +88,37 @@ @customElement("video-page2") export class VideoPage2 extends LitElement { - @property() showVid?: string; - @property() videoListings?: VideoListings; - @property() link!: (s: string) => string; - @property() dirName?: string; + @property() pageData?: PageData; protected firstUpdated(_changedProperties: PropertyValues): void { document.addEventListener("keydown", (e) => { if (e.key == "Escape") { - this.closePlayer(); + this.gotoDirListingPage(); } }); } - protected update(changedProperties: PropertyValues<this>): void { - const resp = changedProperties.has("videoListings"); - if (resp) { - // if (this.showVid) { - // this.openPlayer(); - // } else { - // this.closePlayer(); - // } + async connectedCallback() { + super.connectedCallback(); + if (this.pageData?.autoplay) { + //this.playVideo({ detail: { manifest: this.pageData.autoplay.webDataPath } } as CustomEvent); + console.log("we're a player page now", this.pageData.autoplay); + this.startPlayer(this.pageData.autoplay); + // this might not autoplay + } else { + this.closePlayer(); } + } + protected update(changedProperties: PropertyValues): void { super.update(changedProperties); + if (changedProperties.has("pageData")) { + if (this.pageData?.autoplay) { + this.startPlayer(this.pageData.autoplay); + } else { + this.closePlayer(); + } + } + console.log("updated", this.pageData?.autoplay); } static styles = [ @@ -149,7 +156,7 @@ display: inline-block; width: 300px; margin: 5px; - border-radius: 2px; + border-radius: 5px; } .subdir:after { @@ -166,37 +173,38 @@ `, ]; - thumbSrc(v: VideoFile) { - return "/video/api/thumbnail?webRelPath=" + encodeURIComponent(v.webRelPath); + thumbSrc(vf: VideoFile) { + return "/video/api/thumbnail?webRelPath=" + encodeURIComponent(vf.webRelPath); } renderSubdir(subdir: Subdir): TemplateResult { - return html`<a href="${this.link(subdir.path) + "/"}"><div class="subdir">${subdir.label}</div></a>`; + return html`<a href="/video${subdir.path}"><div class="subdir">${subdir.label}</div></a>`; } renderVideoListing(video: VideoFile) { return html`<video-section - @playVideo=${this.playVideo} + @playVideo=${this.gotoVideoPlayerPage} + webRelPath=${video.webRelPath} thumbRelPath=${this.thumbSrc(video)} title="${video.label}" - manifest="/video/files/${video.webDataPath}" + manifest="/video/files${video.webDataPath}" ></video-section>`; } render() { - if (this.videoListings == null) { + if (this.pageData == null) { return html`<div>Loading...</div>`; } const listings = [ - html`${this.videoListings.subdirs.map((s) => this.renderSubdir(s))}`, // - html`${this.videoListings.videos.map((v) => this.renderVideoListing(v))}`, + html`${this.pageData.subdirs.map((s) => this.renderSubdir(s))}`, // + html`<div>${this.pageData.videos.map((v) => this.renderVideoListing(v))}</div>`, ]; - const dirTitle = this.dirName ? html`<h2>${this.dirName.slice(0, -1)}</h2>` : html``; + const dirTitle = this.pageData.dirLabel ? html`<h2>${this.pageData.dirLabel}</h2>` : html``; return html` ${dirTitle} <div class="listing">${listings}</div> - <div id="scrim" @click=${this.closePlayer}></div> + <div id="scrim" @click=${this.gotoDirListingPage}></div> <page-player manifest=""></page-player> `; } @@ -204,11 +212,20 @@ escapeALittle(fileUri: string): string { return fileUri.replace("#", encodeURIComponent("#")); } + @queryAsync("page-player") pagePlayer: Promise<PagePlayer>; - playVideo(ev: CustomEvent) { - const player = this.shadowRoot!.querySelector("page-player")! as PagePlayer; - - player.manifest = this.escapeALittle(ev.detail.manifest); + async gotoVideoPlayerPage(ev: CustomEvent) { + const player = await this.pagePlayer; + console.log("playing", player, ev.detail.manifest, ev.detail.webRelPath); + this.goto("/video" + ev.detail.webRelPath); + } + async gotoDirListingPage() { + this.goto("/video" + this.pageData?.webDirRelPath); + } + + async startPlayer(p: VideoFile) { + const player = await this.pagePlayer; + player.manifest = this.escapeALittle("/video/files" + p.webDataPath); const sv = player.shadowRoot!.querySelector("shaka-video")! as ShakaVideoElement; sv.src = player.manifest; @@ -216,8 +233,18 @@ player.size = "big"; this.shadowRoot!.querySelector("#scrim")!.style.display = "block"; } - closePlayer() { - const player = this.shadowRoot!.querySelector("page-player")! as PagePlayer; + goto(url: string) { + window.rr.goto(url); + window.history.pushState({}, "", url); + } + async closePlayer() { + const player = await this.pagePlayer; + if (player.size === "hidden") { + console.log("wasn't playing", player.size); + return; + } + // return; + // this.goto("/video/" + this.pageData?.webDirRelPath); player.size = "hidden"; this.shadowRoot!.querySelector("#scrim")!.style.display = "none";
--- a/src/VideoSection.ts Fri Dec 06 01:01:05 2024 -0800 +++ b/src/VideoSection.ts Fri Dec 06 01:02:33 2024 -0800 @@ -5,6 +5,7 @@ @customElement("video-section") export class VideoSection extends LitElement { @property({ type: String }) manifest: string | undefined; + @property({ type: String }) webRelPath: string | undefined; @property({ type: String }) thumbRelPath: string | undefined; @property({ type: String }) title: string = "(unknown)"; @property({ type: String }) big: boolean = false; @@ -51,6 +52,7 @@ new CustomEvent("playVideo", { detail: { manifest: this.manifest, + webRelPath: this.webRelPath, zoomFrom: "my location", }, })