feat(library): add media library browsing functionality

- Introduced new `library` module in the API routes to handle media library requests.
- Enhanced `AppState` to include a media provider for library interactions.
- Defined new `IMediaProvider` trait methods for listing collections, series, and genres.
- Implemented Jellyfin media provider methods for fetching collections and series.
- Added frontend components for selecting series and displaying filter previews.
- Created hooks for fetching collections, series, and genres from the library.
- Updated media filter to support series name and search term.
- Enhanced API client to handle new library-related endpoints.
This commit is contained in:
2026-03-12 02:54:30 +01:00
parent f069376136
commit bf07a65dcd
14 changed files with 1005 additions and 86 deletions

View File

@@ -8,6 +8,10 @@ import type {
ScheduleResponse,
ScheduledSlotResponse,
CurrentBroadcastResponse,
CollectionResponse,
SeriesResponse,
LibraryItemResponse,
MediaFilter,
} from "@/lib/types";
const API_BASE =
@@ -103,6 +107,39 @@ export const api = {
request<void>(`/channels/${id}`, { method: "DELETE", token }),
},
library: {
collections: (token: string) =>
request<CollectionResponse[]>("/library/collections", { token }),
series: (token: string, collectionId?: string) => {
const params = new URLSearchParams();
if (collectionId) params.set("collection", collectionId);
const qs = params.toString();
return request<SeriesResponse[]>(`/library/series${qs ? `?${qs}` : ""}`, { token });
},
genres: (token: string, contentType?: string) => {
const params = new URLSearchParams();
if (contentType) params.set("type", contentType);
const qs = params.toString();
return request<string[]>(`/library/genres${qs ? `?${qs}` : ""}`, { token });
},
items: (
token: string,
filter: Pick<MediaFilter, "content_type" | "series_name" | "collections" | "search_term" | "genres">,
limit = 50,
) => {
const params = new URLSearchParams();
if (filter.search_term) params.set("q", filter.search_term);
if (filter.content_type) params.set("type", filter.content_type);
if (filter.series_name) params.set("series", filter.series_name);
if (filter.collections?.[0]) params.set("collection", filter.collections[0]);
params.set("limit", String(limit));
return request<LibraryItemResponse[]>(`/library/items?${params}`, { token });
},
},
schedule: {
generate: (channelId: string, token: string) =>
request<ScheduleResponse>(`/channels/${channelId}/schedule`, {