Back to Home
Gistify Snippet
kyiov
Sep 4ยท1 file(s)
Public

Scraper lyrics-v2

Scraper lyrics-v2

#github-gist#javascript#gist:02f75f86281956dcbac9728fc47c49a3#gistsync:2026-09-02T12:40:29Z
2
Raw
lyrics-v2.jsjavascript
143 lines
1
2
3import * as __ns_218 from 'axios'
4const axios = __ns_218.default
5import * as __ns_219 from 'node:url'
6const pathToFileURL = __ns_219.pathToFileURL
7
8async function getLyrics(queryOrTrack, artist = "") {
9 if (!queryOrTrack || !queryOrTrack.trim()) {
10 throw new Error("Parameter 'q' (judul lagu atau link Spotify) wajib diisi.");
11 }
12
13 let trackName = String(queryOrTrack).trim();
14 let artistName = String(artist || "").trim();
15
16 if (trackName.includes("spotify.com/track/")) {
17 const match = trackName.match(/track\/([a-zA-Z0-9]+)/);
18 if (match) {
19 try {
20 const oembed = await axios.get(
21 `https://open.spotify.com/oembed?url=https://open.spotify.com/track/${match[1]}`,
22 { timeout: 5000 }
23 );
24 trackName = oembed.data?.title?.replace(/\(feat\..*?\)/i, "").trim() || trackName;
25
26 const resEmbed = await axios.get(`https://open.spotify.com/embed/track/${match[1]}`, { timeout: 5000 });
27 const matchArtist = resEmbed.data.match(/"artists":\[\{"name":"([^"]+)"/);
28 if (matchArtist && !artistName) {
29 artistName = matchArtist[1];
30 }
31 } catch (_) {}
32 }
33 }
34
35 try {
36 const res = await axios.get("https://lrclib.net/api/get", {
37 params: {
38 track_name: trackName,
39 artist_name: artistName,
40 },
41 headers: {
42 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
43 },
44 timeout: 10000,
45 });
46
47 if (res.data && (res.data.plainLyrics || res.data.syncedLyrics)) {
48 const dur = res.data.duration;
49 return {
50 status: true,
51 trackName: res.data.trackName || trackName,
52 artistName: res.data.artistName || artistName || "Unknown Artist",
53 albumName: res.data.albumName || null,
54 duration: dur || null,
55 durationFormatted: dur ? `${Math.floor(dur / 60)}:${String(Math.floor(dur % 60)).padStart(2, "0")}` : null,
56 hasSynced: Boolean(res.data.syncedLyrics),
57 plainLyrics: res.data.plainLyrics || null,
58 syncedLyrics: res.data.syncedLyrics || null
59 };
60 }
61 } catch (_) {}
62
63 try {
64 const searchRes = await axios.get("https://lrclib.net/api/search", {
65 params: {
66 q: `${trackName} ${artistName}`.trim(),
67 },
68 headers: {
69 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
70 },
71 timeout: 10000,
72 });
73
74 if (Array.isArray(searchRes.data) && searchRes.data.length > 0) {
75 const best = searchRes.data[0];
76 const dur = best.duration;
77 return {
78 status: true,
79 trackName: best.trackName,
80 artistName: best.artistName || "Unknown Artist",
81 albumName: best.albumName || null,
82 duration: dur || null,
83 durationFormatted: dur ? `${Math.floor(dur / 60)}:${String(Math.floor(dur % 60)).padStart(2, "0")}` : null,
84 hasSynced: Boolean(best.syncedLyrics),
85 plainLyrics: best.plainLyrics || null,
86 syncedLyrics: best.syncedLyrics || null
87 };
88 }
89 } catch (err) {
90 throw new Error(err.message || "Gagal mengambil lirik lagu.");
91 }
92
93 throw new Error("Lirik lagu tidak ditemukan.");
94}
95
96const lyricsV2 = getLyrics;
97
98const __dflt_2 = {
99 getLyrics,
100 lyricsV2
101};
102
103if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
104 const __exports = { getLyrics: getLyrics, lyricsV2: lyricsV2, default: __dflt_2 }
105 const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function'))
106 const __names = Object.keys(__fns)
107 if (__names.length === 0) {
108 console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.')
109 } else {
110 const __search = __names.find((n) => /search|cari/i.test(n))
111 const __name = __search || __names[0]
112 const __fn = __fns[__name]
113 const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn))
114 const __defaultArgs = (() => {
115 const n = __name.toLowerCase()
116 if (/emoji/.test(n)) return [{ emoji: '๐Ÿ˜€๐Ÿ˜ƒ' }]
117 if (/textpro|generate.*text|effect/.test(n)) return ['neon', 'Hello']
118 if (/image|wallpaper|search|query|anime|movie|manga|news|lyrics|wiki|quote|stalk|detail/.test(n)) return ['naruto']
119 if (/download|youtube|video|audio|music|spotify|tiktok|instagram|facebook|twitter|reels|terabox|media/.test(n)) return ['https://www.youtube.com/watch?v=dQw4w9WgXcQ']
120 if (/dork/.test(n)) return ['example.com', 'documents']
121 if (/tts|speech|prompt|chat|ask|translate/.test(n)) return ['Hello world']
122 if (/parse|format|normalize|list|features/.test(n)) return []
123 return ['test']
124 })()
125 let __args = __defaultArgs
126 if (process.argv.length > 2) __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } })
127 if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) {
128 console.log('Fungsi: ' + __names.join(', '))
129 console.log('Contoh: node ' + "lyrics-v2.js" + ' ' + __name + ' <arg>')
130 } else {
131 ;(async () => {
132 try {
133 const r = __isClass ? new __fn(...__args) : await __fn(...__args)
134 console.log(JSON.stringify(r, null, 2))
135 } catch (e) {
136 console.error('Error: ' + (e && e.message ? e.message : e))
137 process.exitCode = 1
138 }
139 })()
140 }
141 }
142}
143
Discussion & Comments0

No comments yet โ€” be the first to leave feedback or start a code discussion.

Sign in with your GitHub account to write comments and join the discussion.