Separate responsibilities: start-listening command, API-side JSON converters, bulk track endpoints, mix kinds

This commit is contained in:
2026-09-24 12:14:53 +02:00
parent 75d0c0817e
commit 0fa033faff
64 changed files with 2903 additions and 651 deletions
@@ -54,8 +54,9 @@ export const actions: Actions = {
if (!trackId) return fail(400, { message: 'Falta la canción.' });
const api = createApiClient({ fetch, accessToken });
const result = await api.POST('/albums/{albumId}/tracks/{trackId}', {
params: { path: { albumId: params.id, trackId } }
const result = await api.POST('/albums/{id}/tracks', {
params: { path: { id: params.id } },
body: { trackIds: [trackId] }
});
const failure = unwrapOrFail(result, 'No se pudo añadir la canción.');
if (failure) return failure;
@@ -18,11 +18,12 @@
import ContextMenu from '$lib/components/ui/overlay/ContextMenu.svelte';
import ListPlus from '@lucide/svelte/icons/list-plus';
import { createTrackMenu } from '$lib/state/menus.svelte';
import { mixItemTrack } from '$lib/data/mixes';
import { mixItemTrack, mixText } from '$lib/data/mixes';
let { data, form } = $props();
const mix = $derived(data.mix);
const text = $derived(mixText(mix));
const items = $derived(mix.items);
const tracks = $derived(items.map(mixItemTrack));
const queue = $derived(tracks.map(toQueueItem));
@@ -49,8 +50,8 @@
</script>
<svelte:head>
<title>{mix.title}</title>
<meta name="description" content="Mezcla {mix.title}, hecha para ti." />
<title>{text.title}</title>
<meta name="description" content="Mezcla {text.title}, hecha para ti." />
</svelte:head>
<Page>
@@ -58,15 +59,15 @@
<PageHeader
eyebrow="Mezcla"
title={mix.title}
description={mix.subtitle ?? undefined}
title={text.title}
description={text.subtitle}
meta="{plural(items.length, 'canción', 'canciones')} · {fmtTime(totalSeconds)}"
>
{#snippet cover()}
<Artwork
trackIds={items.map((item) => item.trackId)}
size="hero"
alt={mix.title}
alt={text.title}
class="shrink-0"
/>
{/snippet}
+3 -3
View File
@@ -14,7 +14,7 @@
} from '$lib/player/player.svelte';
import { pressable } from '$lib/actions/pressable';
import { mergeRecentlyPlayed } from '$lib/data/recentlyPlayed';
import { mixItemTrack } from '$lib/data/mixes';
import { mixItemTrack, mixText } from '$lib/data/mixes';
import { fmtTime, fmtDurationLong, fmtPlays, plural } from '$lib/utils/format';
import Page from '$lib/components/ui/layout/Page.svelte';
import Artwork from '$lib/components/ui/media/Artwork.svelte';
@@ -279,8 +279,8 @@
{#each mixes as mix, i (mix.id)}
<MediaCard
href="/mixes/{mix.id}"
title={mix.title}
subtitle={mix.subtitle}
title={mixText(mix).title}
subtitle={mixText(mix).subtitle}
trackIds={mix.items.map((item) => item.trackId)}
onPlay={(event) => playMix(mix, event)}
index={i}