// The feed's live YouTube search in the address bar (`?page=feed&yt=lofi&ytn=40`), so a search is a // link and survives a reload. Only the term and how many results to gather: which source answers is // the instance's setting at the moment the link opens (an admin may have switched it since), and that // decides whether the search runs by itself (the free page scrape) or waits for a press (an API // search spends 100 quota units, so nobody's reload or bookmark spends them unasked). const YT_SEARCH_KEY = "yt"; const YT_COUNT_KEY = "ytn"; export const YT_SEARCH_KEYS = [YT_SEARCH_KEY, YT_COUNT_KEY] as const; /** How many live-search results one fetch gathers; the first is the default, left out of the URL. */ export const YT_COUNTS = [20, 40, 60, 100] as const; export const DEFAULT_YT_COUNT = YT_COUNTS[0]; /** The search a URL names, or null: a blank term names none (the search box never sends one). */ export function ytSearchFrom(params: URLSearchParams): string | null { return params.get(YT_SEARCH_KEY)?.trim() || null; } /** The result count a URL names; anything but one of the offered counts is the default. */ export function ytCountFrom(params: URLSearchParams): number { const n = Number(params.get(YT_COUNT_KEY)); return (YT_COUNTS as readonly number[]).includes(n) ? n : DEFAULT_YT_COUNT; } /** The URL updates for a search (null = none): a default count clears its key. */ export function ytSearchParams(term: string | null, count: number): Record { return { [YT_SEARCH_KEY]: term, [YT_COUNT_KEY]: term != null && count !== DEFAULT_YT_COUNT ? String(count) : null, }; }