flesh out main page

This commit is contained in:
2026-02-06 05:11:01 -08:00
parent 665eb31775
commit 46783cb924
2 changed files with 105 additions and 10 deletions

View File

@@ -31,6 +31,10 @@ export async function getAnimeList(db: ClientDb, limit = DEFAULT_LIST_LIMIT) {
seasonId: anime.seasonId, seasonId: anime.seasonId,
malId: anime.malId, malId: anime.malId,
aniListId: anime.aniListId, aniListId: anime.aniListId,
opCount: anime.opCount,
edCount: anime.edCount,
insertCount: anime.insertCount,
}) })
.from(anime) .from(anime)
.orderBy(desc(anime.year), desc(anime.seasonId), desc(anime.annId)) .orderBy(desc(anime.year), desc(anime.seasonId), desc(anime.annId))
@@ -62,6 +66,10 @@ export async function searchAnimeByName(
seasonId: anime.seasonId, seasonId: anime.seasonId,
malId: anime.malId, malId: anime.malId,
aniListId: anime.aniListId, aniListId: anime.aniListId,
opCount: anime.opCount,
edCount: anime.edCount,
insertCount: anime.insertCount,
}) })
.from(anime) .from(anime)
.where(like(anime.mainName, pattern)) .where(like(anime.mainName, pattern))

View File

@@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import { ListPlus, SkipForward } from "@lucide/svelte";
import { Debounced } from "runed"; import { Debounced } from "runed";
import { useSearchParams } from "runed/kit"; import { useSearchParams } from "runed/kit";
import { onMount } from "svelte"; import { onMount } from "svelte";
@@ -8,6 +9,8 @@
getClientDb, getClientDb,
searchAnimeByName, searchAnimeByName,
} from "$lib/db/client-db"; } from "$lib/db/client-db";
import { addAllToQueue, playAllNext } from "$lib/player/player.svelte";
import { trackFromSongRow } from "$lib/player/types";
import { AmqBrowseSearchSchema } from "$lib/types/search/amq-browse"; import { AmqBrowseSearchSchema } from "$lib/types/search/amq-browse";
import { seasonName } from "$lib/utils/amq"; import { seasonName } from "$lib/utils/amq";
@@ -49,6 +52,63 @@
return `/anime/${annId}`; return `/anime/${annId}`;
} }
async function queueAllForAnime(a: AnimeItem) {
// NOTE: This expects your list query to include `opCount`, `edCount`, and `insertCount`.
// If the DB query doesn't select those fields yet, TypeScript will complain until you update it.
const { db } = getClientDb();
// Fetch all songs for this anime and add playable ones to the queue.
// We reuse the existing `getAnimeWithSongsByAnnId` helper if it exists in `$lib/db/client-db`.
// If your barrel export doesn't include it, you'll need to export it there (outside this file).
const { getAnimeWithSongsByAnnId } = await import("$lib/db/client-db");
const res = await getAnimeWithSongsByAnnId(db, a.annId);
if (!res) return;
const tracks = res.songs
.map((s) =>
trackFromSongRow({
annSongId: s.annSongId,
animeName: res.anime.mainName,
type: s.type,
number: s.number,
songName: s.songName,
artistName: s.artistName,
fileName: s.fileName ?? null,
}),
)
.filter((t) => t !== null);
addAllToQueue(tracks);
}
async function playAllNextForAnime(a: AnimeItem) {
const { db } = getClientDb();
const { getAnimeWithSongsByAnnId } = await import("$lib/db/client-db");
const res = await getAnimeWithSongsByAnnId(db, a.annId);
if (!res) return;
const tracks = res.songs
.map((s) =>
trackFromSongRow({
annSongId: s.annSongId,
animeName: res.anime.mainName,
type: s.type,
number: s.number,
songName: s.songName,
artistName: s.artistName,
fileName: s.fileName ?? null,
}),
)
.filter((t) => t !== null);
playAllNext(tracks);
}
onMount(() => {
void loadInitial();
});
async function loadInitial() { async function loadInitial() {
status = "loading"; status = "loading";
error = null; error = null;
@@ -63,10 +123,6 @@
} }
} }
onMount(() => {
void loadInitial();
});
// React to debounced query changes (URL updates + user typing) // React to debounced query changes (URL updates + user typing)
$effect(() => { $effect(() => {
if (status !== "ready") return; if (status !== "ready") return;
@@ -117,6 +173,8 @@
<ul class="mt-4 space-y-2"> <ul class="mt-4 space-y-2">
{#each anime as a (a.annId)} {#each anime as a (a.annId)}
<li class="rounded border px-3 py-2"> <li class="rounded border px-3 py-2">
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="min-w-0">
<a class="font-medium hover:underline" href={animeHref(a.annId)}> <a class="font-medium hover:underline" href={animeHref(a.annId)}>
{a.mainName} {a.mainName}
</a> </a>
@@ -124,6 +182,35 @@
{a.year} {a.year}
{seasonName(a.seasonId)} • ANN {a.annId} • MAL {a.malId} {seasonName(a.seasonId)} • ANN {a.annId} • MAL {a.malId}
</div> </div>
<div class="mt-1 text-sm text-muted-foreground">
OP {a.opCount} • ED {a.edCount} • INS {a.insertCount}
</div>
</div>
<div class="flex shrink-0 items-center gap-1">
<button
type="button"
class="btn-icon"
onclick={() => void playAllNextForAnime(a)}
disabled={a.opCount + a.edCount + a.insertCount === 0}
title="Play all next"
aria-label="Play all next"
>
<SkipForward class="icon-btn" />
</button>
<button
type="button"
class="btn-icon"
onclick={() => void queueAllForAnime(a)}
disabled={a.opCount + a.edCount + a.insertCount === 0}
title="Queue all"
aria-label="Queue all"
>
<ListPlus class="icon-btn" />
</button>
</div>
</div>
</li> </li>
{/each} {/each}
</ul> </ul>