list page pt. 2

This commit is contained in:
2026-02-05 19:39:51 -08:00
parent 1c51fd32db
commit a558bee991
2 changed files with 53 additions and 72 deletions

View File

@@ -1,4 +1,4 @@
import { desc, eq, like } from "drizzle-orm";
import { desc, eq, inArray, like } from "drizzle-orm";
import { anime, animeSongLinks, artists, groups, songs } from "$lib/db/schema";
import type { ClientDb } from "./index";
@@ -124,6 +124,53 @@ export async function getAnimeWithSongsByAnnId(db: ClientDb, annId: number) {
};
}
/**
* Fetch songs for a list of MAL anime ids.
*
* This joins `anime` -> `anime_song_links` -> `songs` and includes artist/group name.
*
* Intended usage: MAL animelist entries give you `node.id` (MAL id); pass those ids here.
*/
export async function getSongsForMalAnimeIds(
db: ClientDb,
malAnimeIds: number[],
) {
const ids = malAnimeIds.filter((n) => Number.isFinite(n));
if (ids.length === 0) return [];
return db
.select({
annId: anime.annId,
malId: anime.malId,
animeName: anime.mainName,
year: anime.year,
seasonId: anime.seasonId,
annSongId: animeSongLinks.annSongId,
type: animeSongLinks.type,
number: animeSongLinks.number,
songName: songs.name,
fileName: songs.fileName,
artistName: artists.name,
groupName: groups.name,
})
.from(anime)
.innerJoin(animeSongLinks, eq(animeSongLinks.annId, anime.annId))
.innerJoin(songs, eq(songs.annSongId, animeSongLinks.annSongId))
.leftJoin(artists, eq(artists.songArtistId, songs.songArtistId))
.leftJoin(groups, eq(groups.songGroupId, songs.songGroupId))
.where(inArray(anime.malId, ids))
.orderBy(
desc(anime.year),
desc(anime.seasonId),
desc(anime.annId),
desc(animeSongLinks.type),
desc(animeSongLinks.number),
);
}
function clampLimit(limit: number) {
const n = Number(limit);
if (!Number.isFinite(n)) return DEFAULT_LIST_LIMIT;

View File

@@ -1,18 +1,13 @@
<script lang="ts">
import { desc, eq, inArray } from "drizzle-orm";
import { Debounced } from "runed";
import { useSearchParams } from "runed/kit";
import { onMount } from "svelte";
import { z } from "zod";
import type { ClientDb } from "$lib/db/client-db";
import { ensureSeeded, getClientDb } from "$lib/db/client-db";
import {
anime,
animeSongLinks,
artists,
groups,
songs,
} from "$lib/db/schema";
ensureSeeded,
getClientDb,
getSongsForMalAnimeIds,
} from "$lib/db/client-db";
import {
MalAnimeListQuerySchema,
MalAnimeListResponseSchema,
@@ -45,7 +40,7 @@
let malEntries = $state<MalEntry[]>([]);
let malUsername = $state<string | null>(null);
type SongRow = Awaited<ReturnType<typeof querySongsForMalAnimeIds>>[number];
type SongRow = Awaited<ReturnType<typeof getSongsForMalAnimeIds>>[number];
let songRows = $state<SongRow[]>([]);
/**
@@ -84,67 +79,6 @@
return MalAnimeListResponseSchema.parse(json);
}
/**
* Client-side DB query:
* Given MAL anime ids, find matching `anime` rows by `anime.malId`,
* then fetch linked songs with artist/group names.
*
* Uses inferred types from the Drizzle select shape; no separate type defs.
*/
async function querySongsForMalAnimeIds(db: ClientDb, malAnimeIds: number[]) {
const ids = malAnimeIds.filter((n) => Number.isFinite(n));
if (ids.length === 0) return [];
// 1) Resolve MAL ids -> AMQ annIds
const annRows = await db
.select({
annId: anime.annId,
malId: anime.malId,
animeName: anime.mainName,
year: anime.year,
seasonId: anime.seasonId,
})
.from(anime)
.where(inArray(anime.malId, ids));
const annIds = annRows.map((r) => r.annId);
if (annIds.length === 0) return [];
// 2) Fetch songs linked to those annIds
// Note: we keep the selection explicit for stable inferred return types.
return db
.select({
annId: animeSongLinks.annId,
annSongId: animeSongLinks.annSongId,
type: animeSongLinks.type,
number: animeSongLinks.number,
songName: songs.name,
fileName: songs.fileName,
artistName: artists.name,
groupName: groups.name,
animeName: anime.mainName,
year: anime.year,
seasonId: anime.seasonId,
malId: anime.malId,
})
.from(animeSongLinks)
.innerJoin(anime, eq(anime.annId, animeSongLinks.annId))
.innerJoin(songs, eq(songs.annSongId, animeSongLinks.annSongId))
.leftJoin(artists, eq(artists.songArtistId, songs.songArtistId))
.leftJoin(groups, eq(groups.songGroupId, songs.songGroupId))
.where(inArray(animeSongLinks.annId, annIds))
.orderBy(
desc(anime.year),
desc(anime.seasonId),
desc(anime.annId),
desc(animeSongLinks.type),
desc(animeSongLinks.number),
);
}
async function loadAllFor(username: string) {
const u = username.trim();
if (!u) {