web-player: normalize tracks, albums and playlists into single domain types at the server boundary

This commit is contained in:
2026-09-24 05:09:37 +02:00
parent 37fc229bf6
commit 5b2a0e4d46
41 changed files with 526 additions and 452 deletions
+8 -11
View File
@@ -1,15 +1,12 @@
import { toQueueItems, type ApiTrackLike, type QueueItem } from '$lib/player/player.svelte';
import type { Paged, Track } from '$lib/types';
export async function fetchAlbumQueueItems(albumId: string): Promise<QueueItem[]> {
const res = await fetch(`/api/albums/${albumId}/tracks`);
async function fetchTracks(url: string): Promise<Track[]> {
const res = await fetch(url);
if (!res.ok) return [];
const data = (await res.json()) as { items: ApiTrackLike[] };
return toQueueItems(data.items ?? []);
return ((await res.json()) as Paged<Track>).items;
}
export async function fetchPlaylistQueueItems(playlistId: string): Promise<QueueItem[]> {
const res = await fetch(`/api/playlists/${playlistId}/tracks`);
if (!res.ok) return [];
const data = (await res.json()) as { items: ApiTrackLike[] };
return toQueueItems(data.items ?? []);
}
export const fetchAlbumTracks = (albumId: string) => fetchTracks(`/api/albums/${albumId}/tracks`);
export const fetchPlaylistTracks = (playlistId: string) =>
fetchTracks(`/api/playlists/${playlistId}/tracks`);
-19
View File
@@ -1,19 +0,0 @@
import type { components } from '$lib/api/schema';
import type { ApiTrackLike } from '$lib/player/player.svelte';
export type Mix = components['schemas']['MixApplicationResponse'];
export type MixItem = components['schemas']['MixItemApplicationResponse'];
export function mixItemKey(item: MixItem): string {
return `mf:${item.trackId}`;
}
export function mixItemTrack(item: MixItem): ApiTrackLike {
return {
id: item.trackId,
title: item.title,
artist: item.artist,
duration: item.durationSeconds,
listensCount: item.listensCount
};
}
+8 -15
View File
@@ -1,21 +1,14 @@
import { player, toQueueItems, type ApiTrackLike, type QueueItem } from '$lib/player/player.svelte';
import { player } from '$lib/player/player.svelte';
import type { Track } from '$lib/types';
export function mergeRecentlyPlayed(history: ApiTrackLike[], limit: number): QueueItem[] {
export function mergeRecentlyPlayed(history: Track[], limit: number): Track[] {
const seen = new Set<string>();
const merged: QueueItem[] = [];
const merged: Track[] = [];
for (const t of player.recentlyPlayed) {
const id = String(t.id);
if (seen.has(id)) continue;
seen.add(id);
merged.push({ ...t, id });
}
for (const item of toQueueItems(history)) {
const id = String(item.id);
if (seen.has(id)) continue;
seen.add(id);
merged.push({ ...item, id });
for (const track of [...player.recentlyPlayed, ...history]) {
if (seen.has(track.id)) continue;
seen.add(track.id);
merged.push(track);
}
return merged.slice(0, limit);