From 978ad1cdb07a49b756a57a9207ef2a6df1043447 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Fri, 20 Mar 2026 00:30:03 +0100 Subject: [PATCH] feat(frontend): add library paged types, syncStatus/triggerSync/admin API methods --- k-tv-frontend/lib/api.ts | 43 ++++++++++++++++++++++++++++++++++++++ k-tv-frontend/lib/types.ts | 30 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/k-tv-frontend/lib/api.ts b/k-tv-frontend/lib/api.ts index 93b1fd3..1501bf9 100644 --- a/k-tv-frontend/lib/api.ts +++ b/k-tv-frontend/lib/api.ts @@ -19,6 +19,9 @@ import type { ProviderTestResult, ConfigSnapshot, ScheduleHistoryEntry, + LibrarySyncLogEntry, + PagedLibraryResponse, + AdminSettings, } from "@/lib/types"; const API_BASE = @@ -235,6 +238,35 @@ export const api = { if (provider) params.set("provider", provider); return request(`/library/items?${params}`, { token }); }, + + syncStatus: (token: string): Promise => + request('/library/sync/status', { token }), + + triggerSync: (token: string): Promise => + request('/library/sync', { method: 'POST', token }), + + itemsPage: ( + token: string, + filter: Partial<{ + q: string; type: string; series: string[]; genres: string[]; collection: string; + provider: string; decade: number; min_duration: number; max_duration: number; + offset: number; limit: number; + }> + ): Promise => { + const params = new URLSearchParams(); + if (filter.q) params.set('q', filter.q); + if (filter.type) params.set('type', filter.type); + if (filter.series) filter.series.forEach(s => params.append('series[]', s)); + if (filter.genres) filter.genres.forEach(g => params.append('genres[]', g)); + if (filter.collection) params.set('collection', filter.collection); + if (filter.provider) params.set('provider', filter.provider); + if (filter.decade != null) params.set('decade', String(filter.decade)); + if (filter.min_duration != null) params.set('min_duration', String(filter.min_duration)); + if (filter.max_duration != null) params.set('max_duration', String(filter.max_duration)); + params.set('offset', String(filter.offset ?? 0)); + params.set('limit', String(filter.limit ?? 50)); + return request(`/library/items?${params}`, { token }); + }, }, files: { @@ -266,6 +298,17 @@ export const api = { activity: (token: string) => request("/admin/activity", { token }), + getSettings: (token: string): Promise => + request('/admin/settings', { token }), + + updateSettings: (token: string, patch: Partial): Promise => + request('/admin/settings', { + method: 'PUT', + token, + body: JSON.stringify(patch), + headers: { 'Content-Type': 'application/json' }, + }), + providers: { getProviders: (token: string) => request("/admin/providers", { token }), diff --git a/k-tv-frontend/lib/types.ts b/k-tv-frontend/lib/types.ts index ecb487c..abed0d0 100644 --- a/k-tv-frontend/lib/types.ts +++ b/k-tv-frontend/lib/types.ts @@ -292,3 +292,33 @@ export interface CurrentBroadcastResponse { offset_secs: number; block_access_mode: AccessMode; } + +// Library management +// Note: LibraryItemResponse is already defined in this file (search for it above). +// LibraryItemFull extends it with the extra fields returned by the DB-backed endpoint. + +export interface LibraryItemFull extends LibraryItemResponse { + thumbnail_url?: string | null; + collection_id?: string | null; + collection_name?: string | null; +} + +export interface PagedLibraryResponse { + items: LibraryItemFull[]; + total: number; +} + +export interface LibrarySyncLogEntry { + id: number; + provider_id: string; + started_at: string; + finished_at?: string | null; + items_found: number; + status: 'running' | 'done' | 'error'; + error_msg?: string | null; +} + +export interface AdminSettings { + library_sync_interval_hours: number; + [key: string]: unknown; +}