Back to Home
Gistify Snippet
Public
Scraper lyrics-v2
Scraper lyrics-v2
#github-gist#javascript#gist:02f75f86281956dcbac9728fc47c49a3#gistsync:2026-09-02T12:40:29Z
2
Rawlyrics-v2.jsjavascript
143 lines| 1 | |
| 2 | |
| 3 | import * as __ns_218 from 'axios' |
| 4 | const axios = __ns_218.default |
| 5 | import * as __ns_219 from 'node:url' |
| 6 | const pathToFileURL = __ns_219.pathToFileURL |
| 7 | |
| 8 | async 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 | |
| 96 | const lyricsV2 = getLyrics; |
| 97 | |
| 98 | const __dflt_2 = { |
| 99 | getLyrics, |
| 100 | lyricsV2 |
| 101 | }; |
| 102 | |
| 103 | if (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.