diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 65c1d7b..362343d 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -44,6 +44,9 @@ { "url": "http://*.deezer.com/**" }, + { + "url": "https://api.deezer.com/**" + }, { "url": "https://media.deezer.com/**" }, diff --git a/src/lib/services/deezer.ts b/src/lib/services/deezer.ts index 454b87f..5502e5c 100644 --- a/src/lib/services/deezer.ts +++ b/src/lib/services/deezer.ts @@ -250,6 +250,35 @@ export class DeezerAPI { return this.apiCall('song.getData', { SNG_ID: trackId }); } + // Search tracks using public API (no authentication required) + async searchTracks(query: string, limit: number = 25): Promise { + const url = `https://api.deezer.com/search/track?q=${encodeURIComponent(query)}&limit=${limit}`; + + console.log('[DEBUG] Searching Deezer API:', { query, limit, url }); + + try { + const response = await fetch(url, { + method: 'GET', + headers: { + ...this.httpHeaders + }, + connectTimeout: 30000 + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const result = await response.json(); + console.log('[DEBUG] Search results:', result); + + return result; + } catch (error: any) { + console.error('[ERROR] Search failed:', error); + throw error; + } + } + // Get playlist data async getPlaylist(playlistId: string): Promise { return this.apiCall('deezer.pagePlaylist', { diff --git a/src/lib/services/deezer/addToQueue.ts b/src/lib/services/deezer/addToQueue.ts new file mode 100644 index 0000000..52d7131 --- /dev/null +++ b/src/lib/services/deezer/addToQueue.ts @@ -0,0 +1,51 @@ +/** + * Utility to add a Deezer track to the download queue + * Used by both search results and services/deezer pages + */ + +import { deezerAPI } from '$lib/services/deezer'; +import { addToQueue } from '$lib/stores/downloadQueue'; + +/** + * Fetch track metadata and add to download queue + * @param trackId - Deezer track ID + * @returns Promise that resolves when track is added to queue + */ +export async function addDeezerTrackToQueue(trackId: string): Promise { + // Fetch full track data from GW API + const trackInfo = await deezerAPI.getTrack(trackId); + + if (!trackInfo || !trackInfo.SNG_ID) { + throw new Error('Track not found or invalid track ID'); + } + + // Build track object + const track = { + id: trackInfo.SNG_ID, + title: trackInfo.SNG_TITLE, + artist: trackInfo.ART_NAME, + artistId: trackInfo.ART_ID, + artists: [trackInfo.ART_NAME], + album: trackInfo.ALB_TITLE, + albumId: trackInfo.ALB_ID, + albumArtist: trackInfo.ART_NAME, + albumArtistId: trackInfo.ART_ID, + trackNumber: trackInfo.TRACK_NUMBER || 1, + discNumber: trackInfo.DISK_NUMBER || 1, + duration: trackInfo.DURATION, + explicit: trackInfo.EXPLICIT_LYRICS === 1, + md5Origin: trackInfo.MD5_ORIGIN, + mediaVersion: trackInfo.MEDIA_VERSION, + trackToken: trackInfo.TRACK_TOKEN + }; + + // Add to queue + await addToQueue({ + source: 'deezer', + type: 'track', + title: track.title, + artist: track.artist, + totalTracks: 1, + downloadObject: track + }); +} diff --git a/src/lib/services/deezer/search.ts b/src/lib/services/deezer/search.ts index 235e912..e35e620 100644 --- a/src/lib/services/deezer/search.ts +++ b/src/lib/services/deezer/search.ts @@ -1,71 +1,34 @@ import type { SearchResult } from '$lib/types/search'; +import { deezerAPI } from '../deezer'; /** - * Search Deezer for tracks matching the query - * TODO: Implement actual Deezer search API - * For now, returns mock data + * Search Deezer for tracks using the public API */ export async function searchDeezerTracks(query: string): Promise { if (!query.trim()) { return []; } - // Simulate API delay - await new Promise(resolve => setTimeout(resolve, 300)); + try { + const response = await deezerAPI.searchTracks(query, 50); - // Mock data - replace with actual Deezer API implementation - const mockResults: SearchResult[] = [ - { - title: 'One More Time', - artist: 'Daft Punk', - album: 'Discovery', - duration: 320, - source: 'online', - trackId: '3135556', - coverArtUrl: 'https://e-cdns-images.dzcdn.net/images/cover/2e018122cb56986277102d2041a592c8/250x250-000000-80-0-0.jpg' - }, - { - title: 'Get Lucky', - artist: 'Daft Punk', - album: 'Random Access Memories', - duration: 369, - source: 'online', - trackId: '67238732', - coverArtUrl: 'https://e-cdns-images.dzcdn.net/images/cover/b0b1e82769d1a1e452fd3f2f95d3bb0f/250x250-000000-80-0-0.jpg' - }, - { - title: 'Around the World', - artist: 'Daft Punk', - album: 'Homework', - duration: 429, - source: 'online', - trackId: '3135553', - coverArtUrl: 'https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/250x250-000000-80-0-0.jpg' - }, - { - title: 'Harder, Better, Faster, Stronger', - artist: 'Daft Punk', - album: 'Discovery', - duration: 224, - source: 'online', - trackId: '3135554', - coverArtUrl: 'https://e-cdns-images.dzcdn.net/images/cover/2e018122cb56986277102d2041a592c8/250x250-000000-80-0-0.jpg' - }, - { - title: 'Digital Love', - artist: 'Daft Punk', - album: 'Discovery', - duration: 301, - source: 'online', - trackId: '3135555', - coverArtUrl: 'https://e-cdns-images.dzcdn.net/images/cover/2e018122cb56986277102d2041a592c8/250x250-000000-80-0-0.jpg' + // Map Deezer API response to SearchResult format + if (!response.data || !Array.isArray(response.data)) { + console.warn('[searchDeezerTracks] No data in response:', response); + return []; } - ]; - // Filter mock results by query - return mockResults.filter(result => - result.title.toLowerCase().includes(query.toLowerCase()) || - result.artist.toLowerCase().includes(query.toLowerCase()) || - result.album.toLowerCase().includes(query.toLowerCase()) - ); + return response.data.map((track: any): SearchResult => ({ + title: track.title || 'Unknown Track', + artist: track.artist?.name || 'Unknown Artist', + album: track.album?.title || 'Unknown Album', + duration: track.duration, + source: 'online', + trackId: String(track.id), + coverArtUrl: track.album?.cover_medium || track.album?.cover_small + })); + } catch (error) { + console.error('[searchDeezerTracks] Search failed:', error); + throw error; + } } diff --git a/src/routes/search/results/+page.svelte b/src/routes/search/results/+page.svelte index dd5707b..e44754d 100644 --- a/src/routes/search/results/+page.svelte +++ b/src/routes/search/results/+page.svelte @@ -4,7 +4,8 @@ import SearchResultsTable from '$lib/components/SearchResultsTable.svelte'; import { searchLocalTracks } from '$lib/library/search'; import { searchDeezerTracks } from '$lib/services/deezer/search'; - import { downloadTrack } from '$lib/services/deezer/downloader'; + import { deezerAPI } from '$lib/services/deezer'; + import { addDeezerTrackToQueue } from '$lib/services/deezer/addToQueue'; import { settings, loadSettings } from '$lib/stores/settings'; import { deezerAuth } from '$lib/stores/deezer'; import type { SearchResult, SearchType } from '$lib/types/search'; @@ -69,7 +70,7 @@ return; } - if (!$deezerAuth.user) { + if (!$deezerAuth.arl || !$deezerAuth.user) { error = 'Please log in to Deezer first (Services → Deezer)'; return; } @@ -80,11 +81,12 @@ } try { - console.log('Downloading track:', result.trackId); - await downloadTrack(result.trackId); - // TODO: Show success notification + deezerAPI.setArl($deezerAuth.arl); + await addDeezerTrackToQueue(result.trackId); + error = null; // Clear any previous error } catch (e) { - error = 'Error downloading track: ' + (e as Error).message; + console.error('Queue error:', e); + error = 'Error adding to download queue: ' + (e as Error).message; } } diff --git a/src/routes/services/deezer/+page.svelte b/src/routes/services/deezer/+page.svelte index ee8d477..b6c5f39 100644 --- a/src/routes/services/deezer/+page.svelte +++ b/src/routes/services/deezer/+page.svelte @@ -3,7 +3,7 @@ import { goto } from '$app/navigation'; import { deezerAuth, loadDeezerAuth, saveArl, saveUser, clearDeezerAuth } from '$lib/stores/deezer'; import { deezerAPI } from '$lib/services/deezer'; - import { addToQueue } from '$lib/stores/downloadQueue'; + import { addDeezerTrackToQueue } from '$lib/services/deezer/addToQueue'; import { settings } from '$lib/stores/settings'; let arlInput = $state(''); @@ -129,35 +129,8 @@ queueError = ''; try { - // Build track object - const track = { - id: trackInfo.SNG_ID, - title: trackInfo.SNG_TITLE, - artist: trackInfo.ART_NAME, - artistId: trackInfo.ART_ID, - artists: [trackInfo.ART_NAME], - album: trackInfo.ALB_TITLE, - albumId: trackInfo.ALB_ID, - albumArtist: trackInfo.ART_NAME, - albumArtistId: trackInfo.ART_ID, - trackNumber: trackInfo.TRACK_NUMBER || 1, - discNumber: trackInfo.DISK_NUMBER || 1, - duration: trackInfo.DURATION, - explicit: trackInfo.EXPLICIT_LYRICS === 1, - md5Origin: trackInfo.MD5_ORIGIN, - mediaVersion: trackInfo.MEDIA_VERSION, - trackToken: trackInfo.TRACK_TOKEN - }; - - // Add to queue - await addToQueue({ - source: 'deezer', - type: 'track', - title: track.title, - artist: track.artist, - totalTracks: 1, - downloadObject: track - }); + // Use shared utility to add track to queue + await addDeezerTrackToQueue(trackIdInput); queueStatus = '✓ Added to download queue!';