songs page init
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
import { desc, eq, inArray, like } from "drizzle-orm";
|
||||
import {
|
||||
and,
|
||||
between,
|
||||
desc,
|
||||
eq,
|
||||
gte,
|
||||
inArray,
|
||||
like,
|
||||
lte,
|
||||
or,
|
||||
} from "drizzle-orm";
|
||||
import { anime, animeSongLinks, artists, groups, songs } from "$lib/db/schema";
|
||||
import type { ClientDb } from "./index";
|
||||
|
||||
@@ -183,6 +193,113 @@ export async function getSongsForMalAnimeIds(
|
||||
);
|
||||
}
|
||||
|
||||
// Define interfaces for filters
|
||||
export interface SongFilters {
|
||||
songName?: string;
|
||||
artistName?: string;
|
||||
animeName?: string; // Searches mainName, mainNameEn, mainNameJa
|
||||
songTypes?: number[]; // 1: OP, 2: ED, 3: INS
|
||||
globalPercentMin?: number; // 0-100
|
||||
globalPercentMax?: number; // 0-100
|
||||
category?: number; // 0: none, 1: instrumental, 2: chanting, 3: character, 4: standard
|
||||
}
|
||||
|
||||
export async function getSongsWithFilters(
|
||||
db: ClientDb,
|
||||
filters: SongFilters,
|
||||
limit = DEFAULT_LIST_LIMIT,
|
||||
) {
|
||||
const safeLimit = clampLimit(limit);
|
||||
const {
|
||||
songName,
|
||||
artistName,
|
||||
animeName,
|
||||
songTypes,
|
||||
globalPercentMin,
|
||||
globalPercentMax,
|
||||
category,
|
||||
} = filters;
|
||||
|
||||
const query = db
|
||||
.select({
|
||||
annSongId: songs.annSongId,
|
||||
songName: songs.name,
|
||||
fileName: songs.fileName,
|
||||
globalPercent: songs.globalPercent,
|
||||
category: songs.category,
|
||||
|
||||
type: animeSongLinks.type,
|
||||
number: animeSongLinks.number,
|
||||
|
||||
animeAnnId: anime.annId,
|
||||
animeMainName: anime.mainName,
|
||||
animeMainNameEn: anime.mainNameEn,
|
||||
animeMainNameJa: anime.mainNameJa,
|
||||
|
||||
artistName: artists.name,
|
||||
groupName: groups.name,
|
||||
})
|
||||
.from(songs)
|
||||
.leftJoin(artists, eq(artists.songArtistId, songs.songArtistId))
|
||||
.leftJoin(groups, eq(groups.songGroupId, songs.songGroupId))
|
||||
.innerJoin(animeSongLinks, eq(animeSongLinks.annSongId, songs.annSongId))
|
||||
.innerJoin(anime, eq(anime.annId, animeSongLinks.annId))
|
||||
.limit(safeLimit);
|
||||
|
||||
const conditions = [];
|
||||
|
||||
if (songName) {
|
||||
conditions.push(like(songs.name, `%${songName}%`));
|
||||
}
|
||||
|
||||
if (artistName) {
|
||||
// Search artistName OR groupName
|
||||
const artistPattern = `%${artistName}%`;
|
||||
conditions.push(
|
||||
or(like(artists.name, artistPattern), like(groups.name, artistPattern)),
|
||||
);
|
||||
}
|
||||
|
||||
if (animeName) {
|
||||
// Search mainName, mainNameEn, or mainNameJa
|
||||
const animePattern = `%${animeName}%`;
|
||||
conditions.push(
|
||||
or(
|
||||
like(anime.mainName, animePattern),
|
||||
like(anime.mainNameEn, animePattern),
|
||||
like(anime.mainNameJa, animePattern),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (songTypes && songTypes.length > 0) {
|
||||
conditions.push(inArray(animeSongLinks.type, songTypes));
|
||||
}
|
||||
|
||||
if (globalPercentMin !== undefined && globalPercentMax !== undefined) {
|
||||
conditions.push(
|
||||
between(songs.globalPercent, globalPercentMin, globalPercentMax),
|
||||
);
|
||||
} else if (globalPercentMin !== undefined) {
|
||||
conditions.push(gte(songs.globalPercent, globalPercentMin));
|
||||
} else if (globalPercentMax !== undefined) {
|
||||
conditions.push(lte(songs.globalPercent, globalPercentMax));
|
||||
}
|
||||
|
||||
if (category !== undefined) {
|
||||
conditions.push(eq(songs.category, category));
|
||||
}
|
||||
|
||||
if (conditions.length > 0) {
|
||||
query.where(and(...conditions));
|
||||
}
|
||||
|
||||
// Order by song name for now, can add more sophisticated sorting later
|
||||
query.orderBy(songs.name);
|
||||
|
||||
return query.execute();
|
||||
}
|
||||
|
||||
function clampLimit(limit: number) {
|
||||
const n = Number(limit);
|
||||
if (!Number.isFinite(n)) return DEFAULT_LIST_LIMIT;
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./season";
|
||||
export * from "./song-utils";
|
||||
|
||||
20
src/lib/utils/amq/song-utils.ts
Normal file
20
src/lib/utils/amq/song-utils.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const SongTypeMap: Record<string, number> = {
|
||||
OP: 1,
|
||||
ED: 2,
|
||||
INS: 3,
|
||||
};
|
||||
|
||||
// Map number back to string for displaying in UI
|
||||
export const SongTypeReverseMap: Record<number, string> = {
|
||||
1: "OP",
|
||||
2: "ED",
|
||||
3: "INS",
|
||||
};
|
||||
|
||||
export const SongCategoryMap: Record<number, string> = {
|
||||
0: "None",
|
||||
1: "Instrumental",
|
||||
2: "Chanting",
|
||||
3: "Character",
|
||||
4: "Standard",
|
||||
};
|
||||
Reference in New Issue
Block a user