Part of the #180 library picker fixes (SPA side). Channel builder: TelevisionSeason is removed from the library grid fan-out, so a multi-season show renders as one tile instead of one tile per season. Show tiles gain a "Seasons" drill-in affordance (both grid and compact layouts) that opens a dialog listing that show's seasons (via the new GET /api/library/browse?parentId= &mediaType=TelevisionSeason), each with title, artwork and an Add button that drops the specific season into the lineup. Collections add-items dialog: the default search fan-out now excludes seasons, and a media-kind filter row (All / Movies / Shows / Seasons / Artists, default = All-without-seasons) keeps seasons reachable when explicitly selected. Client: getLibraryBrowseItems gains an optional parentId param. Tests cover the param mapping, the builder no longer requesting TelevisionSeason, and the collections dialog default-excluding vs explicitly-including seasons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
import { ApiError, request } from './client';
|
|
import type { components } from './generated/v1';
|
|
|
|
export type LibraryBrowseItem = components['schemas']['LibraryBrowseItemResponseModel'];
|
|
export type LibraryBrowseMediaType = components['schemas']['LibraryBrowseMediaType'];
|
|
export type PagedLibraryBrowseItems = components['schemas']['PagedLibraryBrowseItemsResponseModel'];
|
|
|
|
export interface GetLibraryBrowseItemsParams {
|
|
libraryId?: number;
|
|
mediaType?: LibraryBrowseMediaType;
|
|
pageNum?: number;
|
|
pageSize?: number;
|
|
// Only meaningful with mediaType 'TelevisionSeason': filters seasons to the given show id.
|
|
parentId?: number;
|
|
query?: string;
|
|
}
|
|
|
|
export function getLibraryBrowseItems(params: GetLibraryBrowseItemsParams = {}): Promise<PagedLibraryBrowseItems> {
|
|
const searchParams = new URLSearchParams();
|
|
|
|
if (params.query) {
|
|
searchParams.set('query', params.query);
|
|
}
|
|
|
|
if (params.libraryId != null) {
|
|
searchParams.set('libraryId', String(params.libraryId));
|
|
}
|
|
|
|
if (params.mediaType) {
|
|
searchParams.set('mediaType', params.mediaType);
|
|
}
|
|
|
|
if (params.pageNum != null) {
|
|
searchParams.set('pageNum', String(params.pageNum));
|
|
}
|
|
|
|
if (params.pageSize != null) {
|
|
searchParams.set('pageSize', String(params.pageSize));
|
|
}
|
|
|
|
if (params.parentId != null) {
|
|
searchParams.set('parentId', String(params.parentId));
|
|
}
|
|
|
|
const queryString = searchParams.toString();
|
|
|
|
return request<PagedLibraryBrowseItems>(`/api/library/browse${queryString ? `?${queryString}` : ''}`);
|
|
}
|
|
|
|
export function messageFromLibraryBrowseError(error: unknown, fallback = 'Unable to load library items'): string {
|
|
if (error instanceof ApiError) {
|
|
return error.detail ?? error.message;
|
|
}
|
|
|
|
if (error instanceof Error) {
|
|
return error.message;
|
|
}
|
|
|
|
return fallback;
|
|
}
|