feat(live): remove pagination from Live catalog (#51)
Keep server-side search and cursor pagination for Home and Guide while allowing Live to load the complete filtered catalogue. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -16,7 +16,7 @@ function badRequest(message) {
|
||||
}
|
||||
|
||||
function parseQuery(query, userId) {
|
||||
for (const key of ['sourceId', 'categoryId', 'q', 'includeHidden', 'favoriteOnly', 'limit', 'cursor']) {
|
||||
for (const key of ['sourceId', 'categoryId', 'q', 'includeHidden', 'favoriteOnly', 'limit', 'cursor', 'full']) {
|
||||
if (query[key] !== undefined && typeof query[key] !== 'string') badRequest(`Invalid ${key}`);
|
||||
}
|
||||
const sourceId = query.sourceId === undefined ? null : Number(query.sourceId);
|
||||
@ -28,6 +28,10 @@ function parseQuery(query, userId) {
|
||||
};
|
||||
const requestedLimit = query.limit === undefined ? 100 : Number(query.limit);
|
||||
if (!Number.isSafeInteger(requestedLimit) || requestedLimit < 1) badRequest('Invalid limit');
|
||||
const full = boolean('full');
|
||||
if (full && (query.limit !== undefined || query.cursor !== undefined)) {
|
||||
badRequest('full=true cannot be combined with limit or cursor');
|
||||
}
|
||||
const filters = { sourceId, categoryId: query.categoryId ?? null, q: query.q || '',
|
||||
includeHidden: boolean('includeHidden'), favoriteOnly: boolean('favoriteOnly'), userId };
|
||||
const fingerprint = createHash('sha256').update(JSON.stringify({ ...filters, order: ORDER_VERSION })).digest('hex');
|
||||
@ -42,7 +46,7 @@ function parseQuery(query, userId) {
|
||||
after = cursor.k;
|
||||
} catch { badRequest('Invalid cursor'); }
|
||||
}
|
||||
return { ...filters, limit: Math.min(requestedLimit, 200), fingerprint, after };
|
||||
return { ...filters, full, limit: Math.min(requestedLimit, 200), fingerprint, after };
|
||||
}
|
||||
|
||||
// Optional acceleration: LIKE remains the source of truth and also handles short
|
||||
@ -102,7 +106,7 @@ function getLiveCatalog(db, allSources, options) {
|
||||
where.push(`(${CATALOG_ORDER}) > (@groupKey, @groupTitle, @channelKey, @name, @source, @item)`);
|
||||
[params.groupKey, params.groupTitle, params.channelKey, params.name, params.source, params.item] = options.after;
|
||||
}
|
||||
params.limit = options.limit + 1;
|
||||
if (!options.full) params.limit = options.limit + 1;
|
||||
const rows = db.prepare(`WITH live_sources AS (
|
||||
SELECT json_extract(value, '$.id') AS id, json_extract(value, '$.type') AS type FROM json_each(@sources)
|
||||
) SELECT p.*, s.type AS source_type, ${GROUP_TITLE} AS group_title,
|
||||
@ -114,8 +118,8 @@ function getLiveCatalog(db, allSources, options) {
|
||||
LEFT JOIN favorites f ON f.user_id = @user AND f.source_id = p.source_id
|
||||
AND f.item_id = p.item_id AND f.item_type = 'channel'
|
||||
WHERE ${where.join(' AND ')}
|
||||
ORDER BY ${CATALOG_ORDER} LIMIT @limit`).all(params);
|
||||
const hasMore = rows.length > options.limit;
|
||||
ORDER BY ${CATALOG_ORDER}${options.full ? '' : ' LIMIT @limit'}`).all(params);
|
||||
const hasMore = !options.full && rows.length > options.limit;
|
||||
if (hasMore) rows.pop();
|
||||
const items = rows.map(row => {
|
||||
const data = JSON.parse(row.data || '{}');
|
||||
|
||||
Reference in New Issue
Block a user