File size: 5,562 Bytes
d145b59
 
 
 
 
7ffa092
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7ffa092
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de913e8
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
16bd39e
3ed6900
16bd39e
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
}