flesh out main page
This commit is contained in:
@@ -31,6 +31,10 @@ export async function getAnimeList(db: ClientDb, limit = DEFAULT_LIST_LIMIT) {
|
||||
seasonId: anime.seasonId,
|
||||
malId: anime.malId,
|
||||
aniListId: anime.aniListId,
|
||||
|
||||
opCount: anime.opCount,
|
||||
edCount: anime.edCount,
|
||||
insertCount: anime.insertCount,
|
||||
})
|
||||
.from(anime)
|
||||
.orderBy(desc(anime.year), desc(anime.seasonId), desc(anime.annId))
|
||||
@@ -62,6 +66,10 @@ export async function searchAnimeByName(
|
||||
seasonId: anime.seasonId,
|
||||
malId: anime.malId,
|
||||
aniListId: anime.aniListId,
|
||||
|
||||
opCount: anime.opCount,
|
||||
edCount: anime.edCount,
|
||||
insertCount: anime.insertCount,
|
||||
})
|
||||
.from(anime)
|
||||
.where(like(anime.mainName, pattern))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ListPlus, SkipForward } from "@lucide/svelte";
|
||||
import { Debounced } from "runed";
|
||||
import { useSearchParams } from "runed/kit";
|
||||
import { onMount } from "svelte";
|
||||
@@ -8,6 +9,8 @@
|
||||
getClientDb,
|
||||
searchAnimeByName,
|
||||
} 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 { seasonName } from "$lib/utils/amq";
|
||||
|
||||
@@ -49,6 +52,63 @@
|
||||
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() {
|
||||
status = "loading";
|
||||
error = null;
|
||||
@@ -63,10 +123,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
void loadInitial();
|
||||
});
|
||||
|
||||
// React to debounced query changes (URL updates + user typing)
|
||||
$effect(() => {
|
||||
if (status !== "ready") return;
|
||||
@@ -117,12 +173,43 @@
|
||||
<ul class="mt-4 space-y-2">
|
||||
{#each anime as a (a.annId)}
|
||||
<li class="rounded border px-3 py-2">
|
||||
<a class="font-medium hover:underline" href={animeHref(a.annId)}>
|
||||
{a.mainName}
|
||||
</a>
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{a.year}
|
||||
{seasonName(a.seasonId)} • ANN {a.annId} • MAL {a.malId}
|
||||
<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.mainName}
|
||||
</a>
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{a.year}
|
||||
{seasonName(a.seasonId)} • ANN {a.annId} • MAL {a.malId}
|
||||
</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>
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user