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
+10 -2
View File
@@ -185,7 +185,7 @@ export async function search(
/** Resolves a URL that may point at a single track, a playlist, or an album. */
export async function resolveUrl(url: string, requestedBy: Requester, maxTracks: number): Promise<SearchResult> {
const { stdout } = await runYtDlp([
const { stdout, stderr } = await runYtDlp([
...baseArgs(),
"--flat-playlist",
"--dump-single-json",
@@ -194,7 +194,15 @@ export async function resolveUrl(url: string, requestedBy: Requester, maxTracks:
url,
]);
const root = parseNdjson(stdout)[0];
if (!root) throw new UserFacingError("Не удалось разобрать ответ yt-dlp");
if (!root) {
// Typically a dead or malformed link; yt-dlp's own line says it best.
log.warn({ url, stderr: stderr.slice(0, 500) }, "url resolved to nothing");
throw new UserFacingError(
stderr.trim()
? firstUsefulError(stderr)
: "По этой ссылке ничего не открылось — проверьте, что она рабочая",
);
}
if (root._type === "playlist" && Array.isArray(root.entries)) {
const entries = root.entries.filter((e): e is YtDlpEntry => Boolean(e));