feat(search): keep scrape-sourced YouTube results across a reload
A live YouTube search was always dropped on reload so it could never re-spend quota. But the default scrape source costs no quota, so there's no reason to bounce the user back to the feed — they can stay on their results. Feed now stamps history.state._ytScrape=true once a search resolves via the scrape source; App restores _yt on reload only when that flag is set (and re-runs the search, which is free). An api-source search is left unmarked and still drops to the feed on reload, since re-fetching it would cost ~100 units. The flag is cleared when a new search starts (Feed re-stamps it once the new results' source is known).
This commit is contained in:
parent
703ae41f2d
commit
b498755067
2 changed files with 33 additions and 8 deletions
|
|
@ -130,10 +130,18 @@ export default function App() {
|
|||
// popstate handler below derives ytSearch from it, so Back steps player → search → feed in
|
||||
// that order (a player opened over the results pops first, then the search, then the feed) —
|
||||
// instead of the search vanishing because it had no history entry of its own.
|
||||
const [ytSearch, setYtSearch] = useState<string | null>(null);
|
||||
const [ytSearch, setYtSearch] = useState<string | null>(() => {
|
||||
// Restore a live search across a reload ONLY when it was served by the zero-quota scrape
|
||||
// source (re-fetching is free) — an api-source search would re-spend ~100 units, so it's
|
||||
// dropped to the normal feed as before. The scrape flag rides in history.state (survives F5).
|
||||
const st = window.history.state;
|
||||
return st?._yt && st?._ytScrape ? (st._yt as string) : null;
|
||||
});
|
||||
const enterYtSearch = useCallback((q: string) => {
|
||||
setYtSearch(q);
|
||||
const st = window.history.state || {};
|
||||
// Drop any prior _ytScrape marker — the new search's source isn't known yet; Feed re-stamps
|
||||
// it once the results resolve, so a reload only restores a confirmed scrape-sourced search.
|
||||
const { _ytScrape: _drop, ...st } = window.history.state || {};
|
||||
if (st._yt) window.history.replaceState({ ...st, _yt: q }, ""); // refine current search
|
||||
else window.history.pushState({ ...st, sfPage: "feed", _yt: q }, ""); // new sub-view entry
|
||||
}, []);
|
||||
|
|
@ -271,12 +279,17 @@ export default function App() {
|
|||
// from history.state on popstate. (stripUrlParams preserves history.state, so this stamp
|
||||
// survives a later query-string strip.)
|
||||
useEffect(() => {
|
||||
// Drop any stale _yt from a prior session (a reload starts on the normal feed; ytSearch
|
||||
// begins null), so the first Back doesn't resurrect a search we're no longer showing.
|
||||
// Drop a stale _yt (a reload starts on the normal feed; a search would re-spend quota), but
|
||||
// KEEP _chan/_chanName so the open channel page survives F5 (channelView restores from it above).
|
||||
const { _yt: _staleYt, ...rest } = window.history.state || {};
|
||||
window.history.replaceState({ ...rest, sfPage: page }, "");
|
||||
// A reload returns to the normal feed by dropping a stale _yt — EXCEPT when the search was
|
||||
// scrape-sourced (zero quota): then we keep _yt + _ytScrape so it restores and re-fetches for
|
||||
// free (ytSearch above already initialised from it). An api-source search is still dropped (it
|
||||
// would re-spend ~100 units). _chan/_chanName are always kept so a channel page survives F5.
|
||||
const st = window.history.state || {};
|
||||
if (st._yt && st._ytScrape) {
|
||||
window.history.replaceState({ ...st, sfPage: page }, "");
|
||||
} else {
|
||||
const { _yt: _staleYt, _ytScrape: _staleScrape, ...rest } = st;
|
||||
window.history.replaceState({ ...rest, sfPage: page }, "");
|
||||
}
|
||||
function onPop(e: PopStateEvent) {
|
||||
const p = (e.state?.sfPage as Page) ?? "feed";
|
||||
// Guard a Back step that leaves Settings with unsaved changes: re-assert the Settings
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue