From 89f526e9d9303ffb9f1815fd7a72cc1ff80fb6fe Mon Sep 17 00:00:00 2001 From: Chris Kruining Date: Thu, 3 Apr 2025 17:27:35 +0200 Subject: [PATCH] lovely. got a couple of partial implementations.... --- app.config.ts | 32 +++--- src/api/stream/video.ts | 20 ---- src/features/content/data.ts | 33 +++--- src/features/content/index.ts | 2 +- src/features/content/service.ts | 6 +- src/features/content/types.ts | 2 +- src/features/overview/list-item.tsx | 7 +- src/features/overview/overview.tsx | 10 -- src/features/player/player.tsx | 100 ++++++------------ src/routes/(shell)/watch/[item].tsx | 17 --- src/routes/(shell)/watch/[slug].tsx | 41 +++++++ .../api/stream/SampleVideo_1280x720_10mb.mp4 | Bin 0 -> 10498677 bytes src/routes/api/stream/video.ts | 49 +++++++++ src/utilities.ts | 15 +++ 14 files changed, 180 insertions(+), 154 deletions(-) delete mode 100644 src/api/stream/video.ts delete mode 100644 src/routes/(shell)/watch/[item].tsx create mode 100644 src/routes/(shell)/watch/[slug].tsx create mode 100644 src/routes/api/stream/SampleVideo_1280x720_10mb.mp4 create mode 100644 src/routes/api/stream/video.ts create mode 100644 src/utilities.ts diff --git a/app.config.ts b/app.config.ts index cf234d6..d74b729 100644 --- a/app.config.ts +++ b/app.config.ts @@ -6,22 +6,22 @@ import devtools from 'solid-devtools/vite'; export default defineConfig({ vite: { - css: { - transformer: 'lightningcss', - lightningcss: { - targets: browserslistToTargets(browserslist('>= .25%')), - include: Features.Nesting | Features.LightDark | Features.Colors, - customAtRules: { - property: { - prelude: '', - body: 'style-block', - }, - }, - }, - }, - build: { - cssMinify: 'lightningcss', - }, + // css: { + // transformer: 'lightningcss', + // lightningcss: { + // targets: browserslistToTargets(browserslist('>= .25%')), + // include: Features.Nesting | Features.LightDark | Features.Colors, + // customAtRules: { + // property: { + // prelude: '', + // body: 'style-block', + // }, + // }, + // }, + // }, + // build: { + // cssMinify: 'lightningcss', + // }, plugins: [ devtools({ autoname: true, diff --git a/src/api/stream/video.ts b/src/api/stream/video.ts deleted file mode 100644 index c9b98ae..0000000 --- a/src/api/stream/video.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { json } from "@solidjs/router"; -import vid from "../../../public/videos/bbb_sunflower_2160p_60fps_normal.mp4"; -import { APIEvent } from "@solidjs/start/server"; - -export const GET = async (event: APIEvent) => { - "use server"; - - console.log(event); - - // async function* packetGenerator() { - // for (let i = 0; i < 10; i++) { - // yield `packet ${i}`; - // await new Promise((res) => setTimeout(res, 1000)); - // } - // } - - // console.log(vid); - - return "OK"; -}; diff --git a/src/features/content/data.ts b/src/features/content/data.ts index f25b04f..1d93b83 100644 --- a/src/features/content/data.ts +++ b/src/features/content/data.ts @@ -1,20 +1,21 @@ +import { toSlug } from "~/utilities"; import type { Entry } from "./types"; -export const entries = new Map([ - { id: 1, title: 'Realtime with Bill Maher', thumbnail: 'https://www.themoviedb.org/t/p/w342/pbpoLLp4kvnYVfnEGiEhagpJuVZ.jpg' }, - { id: 2, title: 'Binnelanders', thumbnail: 'https://www.themoviedb.org/t/p/w342/v9nGSRx5lFz6KEgfmgHJMSgaARC.jpg' }, - { id: 3, title: 'Family guy', thumbnail: 'https://www.themoviedb.org/t/p/w342/y0HUz4eUNUe3TeEd8fQWYazPaC7.jpg' }, - { id: 4, title: 'The Simpsons', thumbnail: 'https://www.themoviedb.org/t/p/w342/vHqeLzYl3dEAutojCO26g0LIkom.jpg' }, - { id: 5, title: 'Breaking Bad', thumbnail: 'https://www.themoviedb.org/t/p/w342/ztkUQFLlC19CCMYHW9o1zWhJRNq.jpg' }, - { id: 6, title: 'Loki', thumbnail: 'https://www.themoviedb.org/t/p/w342/oJdVHUYrjdS2IqiNztVIP4GPB1p.jpg' }, - { id: 7, title: 'Dark desire', thumbnail: 'https://www.themoviedb.org/t/p/w342/uxFNAo2A6ZRcgNASLk02hJUbybn.jpg' }, - { id: 8, title: 'Bridgerton', thumbnail: 'https://www.themoviedb.org/t/p/w342/luoKpgVwi1E5nQsi7W0UuKHu2Rq.jpg' }, - { id: 9, title: 'Naruto', thumbnail: 'https://www.themoviedb.org/t/p/w342/xppeysfvDKVx775MFuH8Z9BlpMk.jpg' }, - { id: 11, title: 'Teenwolf', thumbnail: 'https://www.themoviedb.org/t/p/w342/fmlMmxSBgPEunHS5gjokIej048g.jpg' }, - { id: 12, title: 'Record of Ragnarok', thumbnail: 'https://www.themoviedb.org/t/p/w342/kTs2WNZOukpWdNhoRlH94pSJ3xf.jpg' }, - { id: 13, title: 'The Mandalorian', thumbnail: 'https://www.themoviedb.org/t/p/w342/eU1i6eHXlzMOlEq0ku1Rzq7Y4wA.jpg' }, +export const entries = new Map([ + { id: '1', title: 'Realtime with Bill Maher', thumbnail: 'https://www.themoviedb.org/t/p/w342/pbpoLLp4kvnYVfnEGiEhagpJuVZ.jpg' }, + { id: '2', title: 'Binnelanders', thumbnail: 'https://www.themoviedb.org/t/p/w342/v9nGSRx5lFz6KEgfmgHJMSgaARC.jpg' }, + { id: '3', title: 'Family guy', thumbnail: 'https://www.themoviedb.org/t/p/w342/y0HUz4eUNUe3TeEd8fQWYazPaC7.jpg' }, + { id: '4', title: 'The Simpsons', thumbnail: 'https://www.themoviedb.org/t/p/w342/vHqeLzYl3dEAutojCO26g0LIkom.jpg' }, + { id: '5', title: 'Breaking Bad', thumbnail: 'https://www.themoviedb.org/t/p/w342/ztkUQFLlC19CCMYHW9o1zWhJRNq.jpg' }, + { id: '6', title: 'Loki', thumbnail: 'https://www.themoviedb.org/t/p/w342/oJdVHUYrjdS2IqiNztVIP4GPB1p.jpg' }, + { id: '7', title: 'Dark desire', thumbnail: 'https://www.themoviedb.org/t/p/w342/uxFNAo2A6ZRcgNASLk02hJUbybn.jpg' }, + { id: '8', title: 'Bridgerton', thumbnail: 'https://www.themoviedb.org/t/p/w342/luoKpgVwi1E5nQsi7W0UuKHu2Rq.jpg' }, + { id: '9', title: 'Naruto', thumbnail: 'https://www.themoviedb.org/t/p/w342/xppeysfvDKVx775MFuH8Z9BlpMk.jpg' }, + { id: '11', title: 'Teenwolf', thumbnail: 'https://www.themoviedb.org/t/p/w342/fmlMmxSBgPEunHS5gjokIej048g.jpg' }, + { id: '12', title: 'Record of Ragnarok', thumbnail: 'https://www.themoviedb.org/t/p/w342/kTs2WNZOukpWdNhoRlH94pSJ3xf.jpg' }, + { id: '13', title: 'The Mandalorian', thumbnail: 'https://www.themoviedb.org/t/p/w342/eU1i6eHXlzMOlEq0ku1Rzq7Y4wA.jpg' }, { - id: 14, + id: '14', title: 'Wednesday', thumbnail: 'https://www.themoviedb.org/t/p/w342/9PFonBhy4cQy7Jz20NpMygczOkv.jpg', image: 'https://www.themoviedb.org/t/p/original/iHSwvRVsRyxpX7FE7GbviaDvgGZ.jpg', @@ -27,4 +28,6 @@ export const entries = new Map([ ].map((entry) => [entry.id, entry])); -export const emptyEntry = Object.freeze({ id: 0, title: '' }); +export const emptyEntry = Object.freeze({ id: '0', title: '' }); + +export const createSlug = (entry: Entry) => toSlug(`${entry.title}-${entry.id}`); diff --git a/src/features/content/index.ts b/src/features/content/index.ts index 0e9bdd2..0f3311f 100644 --- a/src/features/content/index.ts +++ b/src/features/content/index.ts @@ -1,4 +1,4 @@ export type * from './types'; -export { emptyEntry } from './data'; +export { emptyEntry, createSlug } from './data'; export * from './service'; diff --git a/src/features/content/service.ts b/src/features/content/service.ts index 447c1c5..3a6ee82 100644 --- a/src/features/content/service.ts +++ b/src/features/content/service.ts @@ -1,8 +1,8 @@ import type { Category, Entry } from './types'; -import { cache } from "@solidjs/router"; +import { query } from "@solidjs/router"; import { entries } from './data'; -export const listCategories = cache(async (): Promise => { +export const listCategories = query(async (): Promise => { "use server"; return [ @@ -25,7 +25,7 @@ export const listCategories = cache(async (): Promise => { ]; }, 'series.categories.list'); -export const getEntry = cache(async (id: Entry['id']): Promise => { +export const getEntry = query(async (id: Entry['id']): Promise => { "use server"; return entries.get(id); diff --git a/src/features/content/types.ts b/src/features/content/types.ts index 0ae11bd..d1314b2 100644 --- a/src/features/content/types.ts +++ b/src/features/content/types.ts @@ -5,7 +5,7 @@ export interface Category { } export interface Entry { - id: number; + id: string; title: string; summary?: string; releaseDate?: string; diff --git a/src/features/overview/list-item.tsx b/src/features/overview/list-item.tsx index 8c196b8..5c73a9e 100644 --- a/src/features/overview/list-item.tsx +++ b/src/features/overview/list-item.tsx @@ -1,8 +1,11 @@ import type { Entry } from "../content"; -import { Component } from "solid-js"; +import { createSlug } from "../content"; +import { Component, createMemo } from "solid-js"; import css from "./list-item.module.css"; export const ListItem: Component<{ entry: Entry }> = (props) => { + const slug = createMemo(() => createSlug(props.entry)); + return (
@@ -10,7 +13,7 @@ export const ListItem: Component<{ entry: Entry }> = (props) => {
{props.entry.title} - Watch now + Watch now
); diff --git a/src/features/overview/overview.tsx b/src/features/overview/overview.tsx index dd05c24..572d7ba 100644 --- a/src/features/overview/overview.tsx +++ b/src/features/overview/overview.tsx @@ -19,16 +19,6 @@ type OverviewProps = { export const Overview: Component = (props) => { const [container, setContainer] = createSignal(); - onMount(() => { - new MutationObserver(() => { - container() - ?.querySelector( - `.${css.list} > ul > div:nth-child(4) > main > a`, - ) - ?.focus({ preventScroll: true }); - }).observe(document.body, { subtree: true, childList: true }); - }); - return (
diff --git a/src/features/player/player.tsx b/src/features/player/player.tsx index 23c3d14..93b5558 100644 --- a/src/features/player/player.tsx +++ b/src/features/player/player.tsx @@ -1,86 +1,44 @@ import { createEventListenerMap, - makeEventListener, - makeEventListenerStack, + createEventSignal, } from "@solid-primitives/event-listener"; -import { createAsync, json, query } from "@solidjs/router"; +import { query } from "@solidjs/router"; import { Component, createEffect, createMemo, - createResource, createSignal, + For, onMount, + untrack, } from "solid-js"; -import { isServer } from "solid-js/web"; - -const streamKaas = query(async () => { - "use server"; - - const stream = new WritableStream(); - - async function* packetGenerator() { - for (let i = 0; i < 10; i++) { - yield `packet ${i}`; - await new Promise((res) => setTimeout(res, 1000)); - } - } - - (async () => { - const writer = stream.getWriter(); - - try { - await writer.ready; - - for await (const packet of packetGenerator()) { - writer.write(packet); - } - } finally { - writer.releaseLock(); - } - // response.body.wr - })(); - - return new Response(packetGenerator()); -}, "kaas"); interface PlayerProps { id: string; } export const Player: Component = (props) => { - const [video, setVideo] = createSignal(); - const stream = createAsync(async () => { - const res = await streamKaas(); + const [video, setVideo] = createSignal(undefined as unknown as HTMLVideoElement); - console.log(res); + const onDurationChange = createEventSignal(video, 'durationchange'); + const onTimeUpdate = createEventSignal(video, 'timeupdate'); - return ""; + const duration = createMemo(() => { + onDurationChange(); + onTimeUpdate(); + + return video()?.duration ?? 100; }); - // const [kaas, { refetch }] = createResource(async () => { - // if (isServer) { - // return ""; - // } - // const response = await fetch("http://localhost:3000/api/stream/video", { - // method: "GET", - // }); - // console.log(response.body); + const currentTime = createMemo(() => { + onTimeUpdate(); - // for await (const packet of response.body) { - // console.log(new TextDecoder().decode(packet)); - // } + return video()?.currentTime ?? 0; + }); - // return ""; - // }); - - // onMount(() => refetch()); - - // createEffect(() => console.log(stream())); - - // const progress = createMemo(() => { - // const - // }); + createEffect(() => { + console.log(duration(), currentTime()); + }); createEventListenerMap(() => video()!, { durationchange(e) { @@ -102,12 +60,15 @@ export const Player: Component = (props) => { console.log("seeking", e); }, stalled(e) { - console.log("stalled", e); + console.log("stalled (meaning downloading data failed)", e, video()!.error); }, play(e) { console.log("play", e); }, + canplay(e) { + console.log("canplay", e); + }, playing(e) { console.log("playing", e); }, @@ -130,9 +91,9 @@ export const Player: Component = (props) => { console.log(e); }, - timeupdate(e) { - console.log("timeupdate", e); - }, + // timeupdate(e) { + // console.log("timeupdate", e); + // }, }); const toggle = () => { @@ -149,13 +110,14 @@ export const Player: Component = (props) => { <>

{props.id}

- +