1import { useSearchParams } from "@solidjs/router";
2import { parseResponse } from "hono/client";
3import { createSignal, Show } from "solid-js";
4import { api, queries, reason } from "../api.ts";
5import { Explorer } from "../components/Explorer.tsx";
6import { ListPage } from "../components/ListPage.tsx";
7import { lastGood } from "../components/Loaded.tsx";
8import { OpenApp } from "../components/OpenApp.tsx";
9import { toast } from "../components/Toast.tsx";
10
11export function Media() {
12 const [params] = useSearchParams<{ path?: string }>();
13 const here = () => params.path ?? "";
14 const apps = lastGood(queries.launcher.use()[0]);
15 /** Jellyfin has no page per folder, so a show, movie or artist folder opens a search for its title. */
16 const jellyfin = () => {
17 const found = apps()?.find((app) => app.id === "jellyfin");
18 const [top, , title] = here().split("/");
19 if (!found) return null;
20 return {
21 ...found,
22 href: top === "jellyfin" && title
23 ? `${found.url}/web/#/search?query=${encodeURIComponent(title.replace(/ \(\d{4}\)$/, ""))}`
24 : `${found.url}/web/`,
25 };
26 };
27 const [refreshing, setRefreshing] = createSignal(false);
28 const refresh = async () => {
29 setRefreshing(true);
30 try {
31 await parseResponse(api.media.refresh.$post());
32 toast("Jellyfin started scanning all libraries.");
33 } catch (failure) {
34 toast(reason(failure));
35 } finally {
36 setRefreshing(false);
37 }
38 };
39
40 return (
41 <ListPage id="media" flush head={
42 <div class="page-head">
43 <h1>media</h1>
44 <Show when={jellyfin()}>{(link) => <OpenApp app={link()} href={link().href} />}</Show>
45 <span class="spacer" />
46 <button class="button" disabled={refreshing()} aria-busy={refreshing()} onClick={refresh}
47 data-tip="scans all Jellyfin libraries">scan jellyfin</button>
48 </div>
49 }>
50 <Explorer id="media" client={api.media} root="library" />
51 </ListPage>
52 );
53}