feat(live): paginate catalog and search server-side (#49)

Load Live channels from a filtered SQLite cursor API, keep navigation and guide consumers working across pages, and retain the QA reproduction coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 22:43:29 +02:00
parent 8239e6043b
commit e2249154a5
13 changed files with 1280 additions and 387 deletions

View File

@ -6,9 +6,10 @@ const API = {
/**
* Make API request
*/
async request(method, endpoint, data = null) {
async request(method, endpoint, data = null, signal = undefined) {
const options = {
method,
signal,
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
@ -40,6 +41,10 @@ const API = {
throw new Error(result.error || `Server responded with ${response.status}`);
}
if (method !== 'GET' && /^\/(sources|channels)(\/|$)/.test(endpoint)) {
API.liveCatalogRevision = (API.liveCatalogRevision || 0) + 1;
if (window.app?.channelList) window.app.channelList.guideCatalog = null;
}
return result;
},
@ -61,6 +66,13 @@ const API = {
// Channels (hidden items)
channels: {
liveCatalog: (params = {}, signal) => {
const query = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== '') query.set(key, value);
});
return API.request('GET', `/channels/live-catalog?${query}`, null, signal);
},
getHidden: (sourceId = null) => API.request('GET', `/channels/hidden${sourceId ? `?sourceId=${sourceId}` : ''}`),
hide: (sourceId, itemType, itemId) => API.request('POST', '/channels/hide', { sourceId, itemType, itemId }),
show: (sourceId, itemType, itemId) => API.request('POST', '/channels/show', { sourceId, itemType, itemId }),