import scdl from 'soundcloud-downloader'; import { Readable } from 'stream'; interface SearchTrack { id: number; title: string; user?: { username: string; avatar_url?: string; }; artwork_url?: string; duration: number; permalink_url: string; streamable: boolean; downloadable: boolean; } interface TrackResult { id: number; title: string; channel: string; thumbnail: string; duration: number; url: string; streamable: boolean; downloadable: boolean; } interface TrackInfo { title: string; author: string; length: number; available: boolean; } export class SoundCloudService { constructor() { console.log('SoundCloud service initialized'); } async searchTracks(query: string, maxResults: number = 10): Promise { try { console.log(`Searching SoundCloud for: ${query}`); // Search for tracks on SoundCloud const tracks = await scdl.search({ query: query, limit: maxResults, resourceType: 'tracks' }) as any; if (!tracks || tracks.length === 0) { console.log('No tracks found'); return []; } const trackResults: TrackResult[] = tracks.map(track => ({ id: track.id, title: track.title, channel: track.user?.username || 'Unknown Artist', thumbnail: track.artwork_url || track.user?.avatar_url || 'https://via.placeholder.com/300x300?text=No+Image', duration: Math.floor(track.duration / 1000) || 0, // Convert from ms to seconds url: track.permalink_url, streamable: track.streamable, downloadable: track.downloadable })); console.log(`Found ${trackResults.length} tracks on SoundCloud`); return trackResults; } catch (error: any) { console.error('SoundCloud search error:', error.message); return []; } } async getTrackInfo(trackId: string | number): Promise { try { const track = await scdl.getInfo(String(trackId)) as SearchTrack; return { title: track.title, author: track.user?.username || 'Unknown', length: Math.floor(track.duration / 1000), available: track.streamable }; } catch (error) { console.error('Error getting track info:', error); throw error; } } async getAudioStream(trackId: string | number): Promise { try { console.log(`Getting audio stream for track: ${trackId}`); // Get track info first const trackInfo = await scdl.getInfo(String(trackId)) as SearchTrack; if (!trackInfo.streamable) { throw new Error('Track is not streamable'); } console.log(`Track: ${trackInfo.title}`); console.log(`Artist: ${trackInfo.user?.username || 'Unknown'}`); console.log(`Duration: ${Math.floor(trackInfo.duration / 1000)}s`); // Get audio stream const stream = await scdl.download(String(trackId)); console.log('Audio stream obtained successfully from SoundCloud'); return stream; } catch (error: any) { console.error('SoundCloud download failed:', error.message); // Try alternative approach try { console.log('Trying alternative SoundCloud method...'); const trackUrl = `https://soundcloud.com/track/${trackId}`; const stream = await scdl.download(trackUrl); console.log('Audio stream obtained with alternative method'); return stream; } catch (fallbackError: any) { console.error('Alternative method also failed:', fallbackError.message); throw new Error(`SoundCloud download failed: ${error.message}`); } } } }