Two defects with one cause: "server only" was a private $derived inside MediaCard. The list view (what LibraryGrid renders when the stored view preference is list) had no notion of it at all, so a library browsed as a list offline showed every revealed item as an ordinary tappable row that plays nothing, with no way to queue it. And the rule asked the downloads store whether *this item id* was downloaded — but only a playable leaf (Audio, Movie, Episode) ever has a download row. An album's tracks carry them, the album does not, so a fully downloaded album greyed itself out and offered to queue what was already on the device. The rule moves to the pure $lib/utils/serverOnly and both views call it. The container half is answered by the backend rather than guessed at: get_download_disk_usage().sizes already carries container subtotals beside leaf sizes (DR-085), so deviceContentIds is membership in a Rust-computed map, not a frontend list of which item types are containers. That map was loaded only by the Downloads page, so the shell primes it at startup and re-reads it whenever the offline gate settles. Queueing is shared too, since the list view had no copy to diverge from. TRACES: UR-052, UR-055 | DR-292 | UT-257, UT-258
34 lines
1.0 KiB
TypeScript
34 lines
1.0 KiB
TypeScript
/**
|
|
* Queue a server-only item for download on the next reconnect.
|
|
*
|
|
* Offline this only persists a `pending` downloads row with no `stream_url`;
|
|
* the reconnect handler resolves the URL and the pump starts it (see
|
|
* `offlineCatalog`). Shared by the grid card and the list row so the two
|
|
* surfaces queue identically — the list view previously had no way to queue at
|
|
* all.
|
|
*
|
|
* TRACES: UR-052 | DR-292
|
|
*/
|
|
|
|
import type { MediaItem } from "$lib/api/types";
|
|
import { downloads } from "$lib/stores/downloads";
|
|
import { auth } from "$lib/stores/auth";
|
|
|
|
export async function queueOfflineDownload(item: MediaItem): Promise<void> {
|
|
const userId = auth.getUserId();
|
|
if (!userId) throw new Error("Not signed in");
|
|
|
|
// A sensible on-disk path; the backend heals `stream_url` on reconnect.
|
|
const filePath = `downloads/${item.id}`;
|
|
await downloads.downloadItem(
|
|
item.id,
|
|
userId,
|
|
filePath,
|
|
undefined,
|
|
undefined,
|
|
item.name,
|
|
item.artists?.join(", ") ?? undefined,
|
|
item.albumName ?? undefined,
|
|
);
|
|
}
|