Add a source picker to search and use the full window width

Search now queries YouTube and SoundCloud together by default and
interleaves the two result lists so neither buries the other; a picker
left of the input narrows it to one source (plus the local library when
configured), and a prefix typed into the query still outranks it.

The panel was capped at 1180px, which left most of a wide screen empty —
it now scales to 1680px and gives the search column the extra room.

A dead link also reported "could not parse yt-dlp's response", which
described our parser rather than the problem; it now shows yt-dlp's own
error line, or says the link did not open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-09-09 00:11:29 +03:00
co-authored by Claude Opus 5
parent f84489e27e
commit 971fd65b1f
8 changed files with 96 additions and 21 deletions
+18 -1
View File
@@ -16,8 +16,11 @@ interface Props {
onError(message: string | null): void;
}
const SOURCE_KEY = "mbot.searchSource";
export function SearchPanel({ serverId, canControl, localLibrary, onError }: Props) {
const [query, setQuery] = useState("");
const [source, setSource] = useState<string>(() => localStorage.getItem(SOURCE_KEY) ?? "all");
const [results, setResults] = useState<Track[]>([]);
const [busy, setBusy] = useState(false);
const [lastAdded, setLastAdded] = useState<string | null>(null);
@@ -38,7 +41,7 @@ export function SearchPanel({ serverId, canControl, localLibrary, onError }: Pro
setQuery("");
return;
}
const { tracks } = await api.search(serverId, value);
const { tracks } = await api.search(serverId, value, source);
setResults(tracks);
setSearched(true);
} catch (err) {
@@ -62,6 +65,20 @@ export function SearchPanel({ serverId, canControl, localLibrary, onError }: Pro
<div className="card grow">
<h2>Поиск</h2>
<form className="search-form" onSubmit={submit}>
<select
value={source}
onChange={(event) => {
setSource(event.target.value);
localStorage.setItem(SOURCE_KEY, event.target.value);
}}
disabled={!canControl}
title="Где искать"
>
<option value="all">Везде</option>
<option value="youtube">YouTube</option>
<option value="soundcloud">SoundCloud</option>
{localLibrary && <option value="local">Медиатека</option>}
</select>
<input
value={query}
onChange={(event) => setQuery(event.target.value)}