feat(spotify): hook existing download queue

This commit is contained in:
2025-10-16 13:25:03 -04:00
parent df4967dd55
commit 651d87af4c
6 changed files with 829 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import type { Track } from '$lib/types/track';
import PageDecoration from '$lib/components/PageDecoration.svelte';
import { deezerAuth } from '$lib/stores/deezer';
interface Props {
title: string;
@@ -8,8 +9,12 @@
metadata?: string;
coverImageUrl?: string;
tracks: Track[];
trackExistsMap?: Map<string, boolean>;
selectedTrackIndex?: number | null;
onTrackClick?: (index: number) => void;
onDownloadTrack?: (index: number) => void;
onDownloadPlaylist?: () => void;
downloadingTrackIds?: Set<string>;
}
let {
@@ -18,8 +23,12 @@
metadata,
coverImageUrl,
tracks,
trackExistsMap = new Map(),
selectedTrackIndex = null,
onTrackClick
onTrackClick,
onDownloadTrack,
onDownloadPlaylist,
downloadingTrackIds = new Set()
}: Props = $props();
type ViewMode = 'tracks' | 'info';
@@ -30,6 +39,30 @@
onTrackClick(index);
}
}
function handleDownloadClick(index: number, event: MouseEvent) {
event.stopPropagation();
if (onDownloadTrack) {
onDownloadTrack(index);
}
}
// Get Spotify track ID for existence checking
function getSpotifyTrackId(track: Track): string | undefined {
return (track as any).spotifyId?.toString();
}
function isTrackInLibrary(track: Track): boolean {
const trackId = getSpotifyTrackId(track);
if (!trackId) return false;
return trackExistsMap.get(trackId) ?? false;
}
function isTrackDownloading(track: Track): boolean {
const trackId = getSpotifyTrackId(track);
if (!trackId) return false;
return downloadingTrackIds.has(trackId);
}
</script>
<PageDecoration label="SPOTIFY PLAYLIST" />
@@ -85,6 +118,10 @@
<th>Artist</th>
<th>Album</th>
<th>Duration</th>
{#if $deezerAuth.loggedIn}
<th style="width: 80px;">In Library</th>
<th style="width: 100px;">Actions</th>
{/if}
</tr>
</thead>
<tbody>
@@ -106,6 +143,20 @@
{/if}
</td>
{#if $deezerAuth.loggedIn}
<td class="in-library">
{isTrackInLibrary(track) ? '✓' : '✗'}
</td>
<td class="actions">
<button
onclick={(e) => handleDownloadClick(i, e)}
disabled={isTrackDownloading(track)}
class="download-btn"
>
{isTrackDownloading(track) ? 'Queued' : 'Download'}
</button>
</td>
{/if}
</tr>
{/each}
</tbody>
@@ -131,6 +182,22 @@
<span>{tracks.length}</span>
</div>
</fieldset>
{#if $deezerAuth.loggedIn}
<fieldset style="margin-top: 16px;">
<legend>Actions</legend>
<button onclick={onDownloadPlaylist}>
Download Playlist
</button>
<p class="help-text">Download all tracks via Deezer and save as m3u8 playlist</p>
</fieldset>
{:else}
<fieldset style="margin-top: 16px;">
<legend>Downloads</legend>
<p class="warning-text">Deezer login required to download Spotify tracks</p>
<p class="help-text">Sign in to Deezer in Services → Deezer to enable downloads</p>
</fieldset>
{/if}
</div>
{/if}
</div>
@@ -250,4 +317,31 @@
min-width: 120px;
}
.help-text {
margin: 8px 0 0 0;
font-size: 11px;
color: #808080;
}
.warning-text {
margin: 0 0 8px 0;
font-size: 12px;
color: #c00;
}
.in-library {
text-align: center;
font-weight: bold;
font-size: 1.2em;
}
.actions {
text-align: center;
}
.download-btn {
padding: 2px 8px;
font-size: 11px;
}
</style>