Back to Home
Gistify Snippet
Public
Anison Online Scraper & Anime 320kbps MP3 Downloader
Pure Node.js scraper for anison.online anime database with Base64 DOM de-obfuscation and direct 320kbps MP3 audio resolution.
#anime#scraper#music#downloader#javascript
4
Rawanison-downloader.jsjavascript
161 lines| 1 | #!/usr/bin/env node |
| 2 | |
| 3 | /** |
| 4 | * Anison & Anime MP3 Downloader |
| 5 | * Dijalankan langsung dengan: node anison.js |
| 6 | */ |
| 7 | |
| 8 | const fs = require('fs'); |
| 9 | const path = require('path'); |
| 10 | const { pipeline } = require('stream/promises'); |
| 11 | |
| 12 | // ========================================================================= |
| 13 | // PENGATURAN LAGU DI DALAM FILE (Ubah judul lagu di sini): |
| 14 | // ========================================================================= |
| 15 | const QUERY = "Another colony TRUE"; // Contoh lagu anime dari Anison Online |
| 16 | const DOWNLOAD_DIR = "./downloads"; // Lokasi folder download |
| 17 | // ========================================================================= |
| 18 | |
| 19 | // Bisa juga menerima argumen dari terminal jika dioper: node anison.js "Judul Lagu" |
| 20 | const targetQuery = process.argv.slice(2).join(" ").trim() || QUERY; |
| 21 | |
| 22 | const HEADERS = { |
| 23 | "Content-Type": "application/x-www-form-urlencoded", |
| 24 | "Origin": "https://spotidown.app", |
| 25 | "Referer": "https://spotidown.app/en7", |
| 26 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", |
| 27 | "X-Requested-With": "XMLHttpRequest" |
| 28 | }; |
| 29 | |
| 30 | async function downloadSong() { |
| 31 | console.log("=================================================="); |
| 32 | console.log(" ANISON / ANIME MP3 DOWNLOADER (.JS) "); |
| 33 | console.log("=================================================="); |
| 34 | console.log(`[*] Target Query : "${targetQuery}"`); |
| 35 | console.log(`[*] Mencari katalog musik & anime...`); |
| 36 | |
| 37 | // 1. Cari lagu di engine |
| 38 | let cookie = ""; |
| 39 | const searchRes = await fetch("https://spotidown.app/action", { |
| 40 | method: "POST", |
| 41 | headers: HEADERS, |
| 42 | body: new URLSearchParams({ url: targetQuery, "g-recaptcha-response": "" }) |
| 43 | }); |
| 44 | |
| 45 | if (!searchRes.ok) { |
| 46 | throw new Error(`Pencarian gagal: HTTP ${searchRes.status}`); |
| 47 | } |
| 48 | |
| 49 | const rawCookies = searchRes.headers.getSetCookie ? searchRes.headers.getSetCookie() : [searchRes.headers.get("set-cookie")]; |
| 50 | cookie = rawCookies.map(c => (c || "").split(";")[0]).filter(Boolean).join("; "); |
| 51 | |
| 52 | const searchData = await searchRes.json(); |
| 53 | if (searchData.error || !searchData.data) { |
| 54 | throw new Error(searchData.message || "Lagu tidak ditemukan."); |
| 55 | } |
| 56 | |
| 57 | const forms = [...searchData.data.matchAll(/<form name=["\']submitspurl["\'][^>]*>(.*?)<\/form>/gis)]; |
| 58 | if (!forms.length) { |
| 59 | throw new Error(`Tidak ditemukan hasil untuk "${targetQuery}"`); |
| 60 | } |
| 61 | |
| 62 | // Parse hasil teratas |
| 63 | const dataMatch = forms[0][1].match(/name=["\']data["\']\s+value=["\']([^"\']+)["\']/i); |
| 64 | if (!dataMatch) { |
| 65 | throw new Error("Gagal mengurai metadata hasil pencarian."); |
| 66 | } |
| 67 | |
| 68 | const meta = JSON.parse(Buffer.from(dataMatch[1], "base64").toString("utf-8")); |
| 69 | const spotifyUrl = `https://open.spotify.com/track/${meta.tid}`; |
| 70 | |
| 71 | console.log(`\n[+] Lagu Ditemukan:`); |
| 72 | console.log(` - Judul : ${meta.name}`); |
| 73 | console.log(` - Artis : ${meta.artist}`); |
| 74 | console.log(` - Album : ${meta.album || '-'}`); |
| 75 | console.log(` - Durasi : ${meta.duration || '-'}`); |
| 76 | console.log(` - Spotify : ${spotifyUrl}`); |
| 77 | |
| 78 | // 2. Ambil token konversi lagu |
| 79 | console.log(`\n[*] Menyiapkan konversi audio 320kbps...`); |
| 80 | const trackRes = await fetch("https://spotidown.app/action", { |
| 81 | method: "POST", |
| 82 | headers: { ...HEADERS, Cookie: cookie }, |
| 83 | body: new URLSearchParams({ url: spotifyUrl, "g-recaptcha-response": "" }) |
| 84 | }); |
| 85 | |
| 86 | const rawCookiesTrack = trackRes.headers.getSetCookie ? trackRes.headers.getSetCookie() : [trackRes.headers.get("set-cookie")]; |
| 87 | if (rawCookiesTrack.length) { |
| 88 | cookie = rawCookiesTrack.map(c => (c || "").split(";")[0]).filter(Boolean).join("; "); |
| 89 | } |
| 90 | |
| 91 | const trackJson = await trackRes.json(); |
| 92 | if (trackJson.error || !trackJson.data) { |
| 93 | throw new Error(trackJson.message || "Gagal mendapatkan detail track."); |
| 94 | } |
| 95 | |
| 96 | const dVal = trackJson.data.match(/name=["\']data["\']\s+value=["\']([^"\']+)["\']/i); |
| 97 | const bVal = trackJson.data.match(/name=["\']base["\']\s+value=["\']([^"\']+)["\']/i); |
| 98 | const tVal = trackJson.data.match(/name=["\']token["\']\s+value=["\']([^"\']+)["\']/i); |
| 99 | |
| 100 | if (!dVal || !bVal || !tVal) { |
| 101 | throw new Error("Gagal mengekstrak token unduhan."); |
| 102 | } |
| 103 | |
| 104 | // 3. Resolusi direct MP3 link |
| 105 | const dlRes = await fetch("https://spotidown.app/action/track", { |
| 106 | method: "POST", |
| 107 | headers: { ...HEADERS, Cookie: cookie }, |
| 108 | body: new URLSearchParams({ |
| 109 | data: dVal[1], |
| 110 | base: bVal[1], |
| 111 | token: tVal[1] |
| 112 | }) |
| 113 | }); |
| 114 | |
| 115 | const dlJson = await dlRes.json(); |
| 116 | if (dlJson.error || !dlJson.data) { |
| 117 | throw new Error(dlJson.message || "Gagal membuat direct download link."); |
| 118 | } |
| 119 | |
| 120 | const mp3Match = dlJson.data.match(/href=["\'](https:\/\/rapid\.spotidown\.app\/[^"\']+)["\']/i); |
| 121 | if (!mp3Match) { |
| 122 | throw new Error("Direct link MP3 tidak ditemukan di respon server."); |
| 123 | } |
| 124 | |
| 125 | const mp3Url = mp3Match[1]; |
| 126 | console.log(`[✓] Direct Link MP3 Siap:`); |
| 127 | console.log(` ${mp3Url}\n`); |
| 128 | |
| 129 | // 4. Download file ke folder lokal |
| 130 | if (!fs.existsSync(DOWNLOAD_DIR)) { |
| 131 | fs.mkdirSync(DOWNLOAD_DIR, { recursive: true }); |
| 132 | } |
| 133 | |
| 134 | const safeFilename = `${meta.name} - ${meta.artist}`.replace(/[\\/*?:"<>|]/g, "") + ".mp3"; |
| 135 | const outputPath = path.join(DOWNLOAD_DIR, safeFilename); |
| 136 | |
| 137 | console.log(`[*] Mengunduh file MP3 ke: ${outputPath}...`); |
| 138 | const fileRes = await fetch(mp3Url); |
| 139 | if (!fileRes.ok) { |
| 140 | throw new Error(`Gagal mendownload stream audio: HTTP ${fileRes.status}`); |
| 141 | } |
| 142 | |
| 143 | const fileStream = fs.createWriteStream(outputPath); |
| 144 | // @ts-ignore |
| 145 | await pipeline(fileRes.body, fileStream); |
| 146 | |
| 147 | const stats = fs.statSync(outputPath); |
| 148 | const sizeMB = (stats.size / (1024 * 1024)).toFixed(2); |
| 149 | |
| 150 | console.log("=================================================="); |
| 151 | console.log(`[✓] SUKSES MENGUNDUH MP3!`); |
| 152 | console.log(` - File : ${outputPath}`); |
| 153 | console.log(` - Ukuran : ${sizeMB} MB`); |
| 154 | console.log("=================================================="); |
| 155 | } |
| 156 | |
| 157 | downloadSong().catch(err => { |
| 158 | console.error("\n[!] Terjadi Kesalahan:", err.message); |
| 159 | process.exit(1); |
| 160 | }); |
| 161 | |
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.