Search streams the rest: after the first page the app asks for each further page as the server pages YouTube and appends it
This commit is contained in:
@@ -583,8 +583,8 @@ async function opfsClear() {
|
||||
let _currentBlobUrl = null;
|
||||
|
||||
const API = {
|
||||
search: (query, { refresh = false } = {}) => WEB
|
||||
? webFetch(`/api/search?q=${encodeURIComponent(query)}${refresh ? '&refresh=1' : ''}`)
|
||||
search: (query, { refresh = false, after = 0 } = {}) => WEB
|
||||
? webFetch(`/api/search?q=${encodeURIComponent(query)}${refresh ? '&refresh=1' : ''}${after ? `&after=${after}` : ''}`)
|
||||
: call('yt.search', 'yt_search', { query }),
|
||||
related: (meta, { refresh = false } = {}) => WEB && /^[\w-]{11}$/.test(meta.id)
|
||||
? webFetch(`/api/related?${new URLSearchParams({ videoId: meta.id, title: meta.title || '', channel: meta.channel || meta.artist || '', ...(refresh ? { refresh: '1' } : {}) })}`)
|
||||
@@ -8118,26 +8118,31 @@ function wireUI() {
|
||||
if (refresh) toast('Search updated');
|
||||
perfMeasure('ytp:search', 'ytp:search-start');
|
||||
// The server answered with YouTube's first page and is still fetching
|
||||
// the rest; pick up the full list quietly once it has landed.
|
||||
if (res.partial) setTimeout(async () => {
|
||||
if (mySeq !== searchSeq || view.type !== 'search') return;
|
||||
try {
|
||||
const more = await API.search(q);
|
||||
const full = merged(more?.results || []);
|
||||
if (mySeq !== searchSeq || !more?.ok || full.length <= results.length) return;
|
||||
const shown = searchResults;
|
||||
const prefix = shown.length <= full.length && shown.every((v, i) => full[i] && full[i].id === v.id);
|
||||
if (prefix && els.cards.children.length) {
|
||||
// Grow the same array, so cards already drawn queue the full list too.
|
||||
const from = shown.length;
|
||||
shown.push(...full.slice(from));
|
||||
searchResults = shown;
|
||||
appendListCards(shown, from);
|
||||
} else { searchResults = full; renderList(); }
|
||||
RecentSearches.cacheResults(q, full, Date.now());
|
||||
showSearchMeta(q, Date.now());
|
||||
} catch { /* keep the first page */ }
|
||||
}, 10000);
|
||||
// the rest; keep asking for anything beyond what we have (the server holds
|
||||
// each ask until the next page lands) and append every page as it comes.
|
||||
if (res.partial) (async () => {
|
||||
let have = (res.results || []).length; // what the server has sent so far
|
||||
for (let round = 0; round < 40 && mySeq === searchSeq && view.type === 'search'; round++) {
|
||||
let more;
|
||||
try { more = await API.search(q, { after: have }); } catch { return; /* keep what is shown */ }
|
||||
if (mySeq !== searchSeq || !more?.ok) return;
|
||||
const got = more.results || [];
|
||||
if (got.length > have) {
|
||||
have = got.length;
|
||||
const full = merged(got);
|
||||
const shown = searchResults;
|
||||
const prefix = shown.length <= full.length && shown.every((v, i) => full[i] && full[i].id === v.id);
|
||||
if (prefix && els.cards.children.length) {
|
||||
// Grow the same array, so cards already drawn queue the full list too.
|
||||
const from = shown.length;
|
||||
shown.push(...full.slice(from));
|
||||
appendListCards(shown, from);
|
||||
} else { searchResults = full; renderList(); }
|
||||
showSearchMeta(q, Date.now());
|
||||
}
|
||||
if (!more.partial) { RecentSearches.cacheResults(q, searchResults, Date.now()); return; }
|
||||
}
|
||||
})();
|
||||
} catch (err) {
|
||||
networkDone = true;
|
||||
if (mySeq !== searchSeq) return;
|
||||
|
||||
Reference in New Issue
Block a user