feat(discover): wire A4 search + A5 downloads to backend

Adds DownloadJob/ExternalSearchResult/SourceInfo contract types + mappers, the downloads + search RTKQ endpoints, and the SearchDownloadPage (search external sources, per-result download states) and DownloadsManagerPage (active/history, progress, retry/cancel, poll-while-active). en/ru i18n. Snapshot also bundles in-progress queue/metadata-editor/storage UI work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Senko-san
2026-06-14 14:04:43 +03:00
parent cdcacc56d1
commit 231887c3b7
23 changed files with 1168 additions and 91 deletions
+5 -2
View File
@@ -60,7 +60,9 @@ async function handleAudio(event) {
// 2) Cache miss → fetch the WHOLE file (strip Range) so we can store a
// complete copy, then satisfy the original request (range-sliced if asked).
try {
const fullReq = new Request(req.url, { headers: withoutRange(req.headers) });
const fullReq = new Request(req.url, {
headers: withoutRange(req.headers),
});
const resp = await fetch(fullReq);
if (isCacheable(resp)) {
event.waitUntil(storeInCache(key, resp.clone()));
@@ -135,7 +137,8 @@ async function buildRangeResponse(response, rangeHeader) {
const buf = await response.clone().arrayBuffer();
const size = buf.byteLength;
const r = parseRangeHeader(rangeHeader, size);
const type = response.headers.get('content-type') || 'application/octet-stream';
const type =
response.headers.get('content-type') || 'application/octet-stream';
if (!r) {
return new Response(buf, {