const axios = require('axios'); const yts = require("yt-search"); const { getAudio } = require("../lib/ytdl"); const path = require("path"); const fs = require("fs"); const dirTmp = path.join(__dirname, "../tmp"); const clientId = '8f777f61f80e4051b754d8e50310ad6e'; const clientSecret = '5802d3726d3149bfb880a577aa855fb3'; const tokenUrl = 'https://accounts.spotify.com/api/token'; const base64Credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); // Pastikan folder tmp ada if (!fs.existsSync(dirTmp)) { fs.mkdirSync(dirTmp, { recursive: true }); } async function getAccessToken() { try { const response = await axios.post(tokenUrl, 'grant_type=client_credentials', { headers: { 'Authorization': `Basic ${base64Credentials}`, 'Content-Type': 'application/x-www-form-urlencoded', }, }); return response.data.access_token; } catch (error) { console.error('Gagal mendapatkan token:', error.response?.data || error.message); return null; } } async function spotifyTrack(trackUrl) { const { ID3Writer } = await import('browser-id3-writer'); try { const match = trackUrl.match(/track\/([a-zA-Z0-9]+)/); if (!match) throw new Error('URL tidak valid'); const trackId = match[1]; // Dapatkan token const accessToken = await getAccessToken(); if (!accessToken) throw new Error('Gagal mendapatkan token akses'); // Ambil metadata Spotify const trackResponse = await axios.get(`https://api.spotify.com/v1/tracks/${trackId}`, { headers: { Authorization: `Bearer ${accessToken}` }, }); const trackData = trackResponse.data; // Cari lagu di YouTube const searchResults = await yts(`${trackData.name} - ${trackData.artists.map(a => a.name).join(', ')}`); if (!searchResults.videos.length) throw new Error('Video tidak ditemukan di YouTube'); const videoUrl = searchResults.videos[0].url; const audio = await getAudio(videoUrl); if (!audio) throw new Error("Gagal mendapatkan audio dari YouTube"); // Simpan file dengan nama unik const Filename = `NSpotify_${Date.now()}_${Math.floor(Math.random() * 1000)}.mp3`; const FilenameM = `Spotify_${Date.now()}_${Math.floor(Math.random() * 1000)}.mp3`; await fs.writeFileSync(`${dirTmp}/${Filename}`, audio); // Tambahkan ID3 Tag const writer = new ID3Writer(fs.readFileSync(`${dirTmp}/${Filename}`)); writer .setFrame('TIT2', trackData.name) .setFrame('TPE1', trackData.artists.map(a => a.name)) .setFrame('TALB', trackData.album.name || "") .setFrame('TYER', parseInt(trackData.album.release_date.split('-')[0])) .setFrame('APIC', { type: 3, data: await urlToBuffer(trackData.album.images[0]?.url), description: 'Super picture' }) .addTag(); // Simpan file dengan tag ID3 const taggedSongBuffer = Buffer.from(writer.arrayBuffer); await fs.writeFileSync(`${dirTmp}/${FilenameM}`, taggedSongBuffer); const URI = `https://fullpwerr-hutatools.hf.space/tmp/${FilenameM}`; const res = { status: 200, title: trackData.name, artist: trackData.artists.map(artist => artist.name).join(', '), album: trackData.album.name, duration_ms: trackData.duration_ms, release_date: trackData.album.release_date, thumbnail: trackData.album.images[0]?.url || null, music: [{ url: URI }] }; console.log(res) return res } catch (e) { return { status: 500, message: e.message} } } async function spotifyPlaylist(playlistUrl) { try { const match = playlistUrl.match(/playlist\/([a-zA-Z0-9]+)/); if (!match) throw new Error('URL playlist tidak valid'); const playlistId = match[1]; const accessToken = await getAccessToken(); if (!accessToken) throw new Error('Gagal mendapatkan token akses'); const playlistResponse = await axios.get(`https://api.spotify.com/v1/playlists/${playlistId}`, { headers: { Authorization: `Bearer ${accessToken}` }, }); const playlistData = playlistResponse.data; const tracks = playlistData.tracks.items; if (!tracks.length) throw new Error('Playlist kosong atau tidak ditemukan'); console.log(`🎵 Playlist: ${playlistData.name} (${tracks.length} lagu)`); let results = []; const limitedTracks = tracks.slice(0, 3); for (const item of limitedTracks) { const track = item.track; if (!track) continue; const trackUrl = `https://open.spotify.com/track/${track.id}`; console.log(`🔄 Memproses: ${track.name} - ${track.artists.map(a => a.name).join(', ')}`); const trackData = await spotifyTrack(trackUrl); if (trackData) results.push(trackData.music[0].url); } return { status: 200, playlist_name: playlistData.name, total_tracks: tracks.length, cover_image: playlistData.images[0]?.url || null, tracks: results }; } catch (error) { console.error(error); return null; } } const urlToBuffer = async (url, options) => { try { options ? options : {}; const res = await axios({ method: "get", url, headers: { 'DNT': 1, 'Upgrade-Insecure-Request': 1 }, ...options, responseType: 'arraybuffer' }); return res.data; } catch (e) { console.log(`Error : ${e}`); } }; module.exports = { spotifyTrack, spotifyPlaylist }