hutatools / lib /spotify.js
fullpwerr's picture
o
de913e8
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
}