diff --git a/src/lib/types/amq/anime.ts b/src/lib/types/amq/anime.ts
index 701c64e..f184e85 100644
--- a/src/lib/types/amq/anime.ts
+++ b/src/lib/types/amq/anime.ts
@@ -2,18 +2,28 @@ import { z } from "zod";
import { AmqAnimeCategory, AmqAnimeGenre, AmqAnimeTag } from "./anime-extended";
-export const Season = z.enum({
+export const AmqSeasonMap = {
Winter: 0,
Spring: 1,
Summer: 2,
Fall: 3,
-} as const);
+} as const;
-export const SongLinkType = z.enum({
+export const AmqSeason = z.enum(AmqSeasonMap);
+
+export const AmqSongLinkTypeMap = {
OP: 1,
ED: 2,
INS: 3,
-} as const);
+} as const;
+
+export const AmqSongLinkTypeMapReverse = {
+ 1: "OP",
+ 2: "ED",
+ 3: "INS",
+} as const;
+
+export const AmqSongLinkType = z.enum(AmqSongLinkTypeMap);
const BooleanInt = z.enum({
false: 0,
@@ -23,7 +33,7 @@ const BooleanInt = z.enum({
export const AmqSongLink = z.object({
songId: z.int().positive(),
number: z.int().nonnegative(),
- type: SongLinkType,
+ type: AmqSongLinkType,
annSongId: z.int().positive(),
uploaded: BooleanInt,
rebroadcast: BooleanInt,
@@ -53,7 +63,7 @@ export const AmqAnimeSchema = z.object({
}),
),
year: z.int().positive(),
- seasonId: Season,
+ seasonId: AmqSeason,
songLinks: z.array(AmqSongLink),
opCount: z.int().nonnegative(),
edCount: z.int().nonnegative(),
diff --git a/src/routes/songs/+page.svelte b/src/routes/songs/+page.svelte
index f809f67..4a74e19 100644
--- a/src/routes/songs/+page.svelte
+++ b/src/routes/songs/+page.svelte
@@ -7,17 +7,14 @@
import { Button } from "$lib/components/ui/button";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label";
- import {
- NativeSelect,
- NativeSelectOption,
- } from "$lib/components/ui/native-select";
import { db as clientDb } from "$lib/db/client-db";
import { addAllToQueue, playAllNext } from "$lib/player/player.svelte";
import { trackFromSongRow } from "$lib/player/types";
+ import { AmqSongLinkTypeMap } from "$lib/types/amq";
import type { PageData } from "./$types";
- import { SearchParamsSchemaClient } from "./schema";
+ import { SearchParamsSchema } from "./schema";
- const params = useSearchParams(SearchParamsSchemaClient, {
+ const params = useSearchParams(SearchParamsSchema, {
pushHistory: false,
showDefaults: false,
});
@@ -123,13 +120,20 @@
-
-
- All
- OP
- ED
- INS
-
+
+
@@ -140,7 +144,7 @@
max="200"
step="20"
class="w-1/2"
- bind:value={params.songsLimit}
+ bind:value={params.limit}
/>
diff --git a/src/routes/songs/+page.ts b/src/routes/songs/+page.ts
index fc6417f..efcefb7 100644
--- a/src/routes/songs/+page.ts
+++ b/src/routes/songs/+page.ts
@@ -1,12 +1,12 @@
import type { SongFilters } from "$lib/db/client-db";
import { db, ensureSeeded, getSongsWithFilters } from "$lib/db/client-db";
import type { PageLoad } from "./$types";
-import { SearchParamsSchemaServer } from "./schema";
+import { SearchParamsSchema } from "./schema";
export const load: PageLoad = async ({ url, fetch, depends }) => {
depends("clientdb:songs");
- const parsed = SearchParamsSchemaServer.safeParse(
+ const parsed = SearchParamsSchema.safeParse(
Object.fromEntries(url.searchParams.entries()),
);
@@ -19,7 +19,7 @@ export const load: PageLoad = async ({ url, fetch, depends }) => {
filters.globalPercentMin = parsed.data.gpm;
if (parsed.data.gpx !== undefined)
filters.globalPercentMax = parsed.data.gpx;
- if (parsed.data.songType) filters.songTypes = [parsed.data.songType];
+ if (parsed.data.type) filters.songTypes = parsed.data.type;
}
// Client-only DB: on the server `db` is null, so return [] and let hydration re-run load in browser.
@@ -32,11 +32,7 @@ export const load: PageLoad = async ({ url, fetch, depends }) => {
await ensureSeeded({ fetch });
- const songRows = await getSongsWithFilters(
- db,
- filters,
- parsed.data?.songsLimit,
- );
+ const songRows = await getSongsWithFilters(db, filters, parsed.data?.limit);
return {
filters: parsed.success ? parsed.data : {}, // Return original parsed data for form state
diff --git a/src/routes/songs/schema.ts b/src/routes/songs/schema.ts
index f9230c8..93ceb73 100644
--- a/src/routes/songs/schema.ts
+++ b/src/routes/songs/schema.ts
@@ -1,18 +1,33 @@
import { z } from "zod";
+import {
+ AmqSongLinkType,
+ AmqSongLinkTypeMap,
+ AmqSongLinkTypeMapReverse,
+} from "$lib/types/amq";
+
+const SEP = ",";
+
+const songTypesCodec = z.codec(z.string(), z.array(AmqSongLinkType), {
+ decode: (str) =>
+ str
+ ? decodeURIComponent(str)
+ .split(SEP)
+ .map((s) => AmqSongLinkTypeMap[s as keyof typeof AmqSongLinkTypeMap])
+ : [],
+ encode: (arr) =>
+ arr
+ ? encodeURIComponent(
+ arr.map((a) => AmqSongLinkTypeMapReverse[a]).join(SEP),
+ )
+ : "",
+});
export const SearchParamsSchema = z.object({
- songsLimit: z.coerce.number().int().default(20),
+ limit: z.coerce.number().int().default(20),
song: z.string().optional().default(""),
artist: z.string().optional().default(""),
anime: z.string().optional().default(""),
gpm: z.coerce.number().int().optional().default(0),
gpx: z.coerce.number().int().optional().default(100),
-});
-
-export const SearchParamsSchemaClient = SearchParamsSchema.extend({
- songType: z.string().optional().default("0"),
-});
-
-export const SearchParamsSchemaServer = SearchParamsSchema.extend({
- songType: z.coerce.number().int().optional(),
+ type: songTypesCodec.default([]),
});