cd /news/developer-tools/yt2mp3-gs-scrape-by-claidex-alfidev · home topics developer-tools article
[ARTICLE · art-37777] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

yt2mp3.gs scrape by claidex ( alfidev )

A developer known as claidex (alfidev) created a script to scrape the YouTube-to-MP3 conversion service yt2mp3.gs. The script automates the authentication, conversion, and download process, handling redirects and progress polling. It demonstrates how to programmatically interact with the service's API endpoints hosted on epsilon.epsiloncloud.org.

read3 min views2 publishedJun 24, 2026
| import { createWriteStream } from "fs"; | |
| import { pipeline } from "stream/promises"; | |

| const EPS = "epsilon.epsiloncloud.org"; | |

| const ORIGIN = "https://yt2mp3.gs"; | |
| const youtube = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; | |
| const FORMAT = "mp3"; | |

| let key, geo; | |

| const HEADERS = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0", | |

| "Accept": "/", | | | "Accept-Language": "en-US,en;q=0.9", | | | "Origin": ORIGIN, | |

| "Referer": `${ORIGIN}/`, | |
| }; | |
| async function req(url, extra = {}) { | |
| const res = await fetch(url, { headers: { ...HEADERS, ...extra } }); | |
| const text = await res.text(); | |
| if (!res.ok) throw new Error(`HTTP ${res.status} ${url}`); | |
| return JSON.parse(text); | |

| } | |

| async function auth(vid, fmt) { | |
| const r = await req(`https://${EPS}/api/v1/auth?_=${Date.now()}`); | |
| if (r.error > 0) throw new Error(`auth: ${r.error}`); | |
| geo = r.geo; | |
| key = r.key; | |
| await initialize(vid, fmt); | |

| } | |

| async function initialize(vid, fmt) { | |
| console.log("→ initializing..."); | |
| const r = await req(`https://${EPS}/api/v1/init?_=${Date.now()}`, { Authorization: `Bearer ${key}` }); | |
| if (r.error > 0) throw new Error(`init: ${r.error}`); | |
| await convert(r.convertURL, vid, fmt, 0); | |

| } | |

| async function convert(cUrl, vid, fmt, redirected) { | |
| const r = await req(`${cUrl}&v=${vid}&f=${fmt}&_=${Date.now()}`); | |
| if (r.error > 0) throw new Error(`convert: ${r.error}`); | |
| if (redirected === 1) { | |

| return geo | | | ? waitProgress(r.progressURL, r.downloadURL, vid, fmt, r.title) | | | : download(r.downloadURL, vid, fmt, r.title); | | | } | | | if (r.redirect === 1) return convert(r.redirectURL, vid, fmt, 1); | | | await pollProgress(r.progressURL, r.downloadURL, vid, fmt); | | | } | | | const STATES = ["checking video", "extracting video", "converting video", "done"]; | |

| async function pollProgress(pUrl, dlUrl, vid, fmt, prev = -1) { | |
| const r = await req(`${pUrl}&_=${Date.now()}`); | |
| if (r.error > 0) throw new Error(`progress: ${r.error}`); | |
| if (r.title) console.log(` title: ${r.title}`); | |
| if (r.progress !== prev) console.log(` ${STATES[r.progress] || r.progress}`); | |
| if (r.progress < 3) { | |
| await delay(3000); | |

| return pollProgress(pUrl, dlUrl, vid, fmt, r.progress); | | | } | | | await download(dlUrl, vid, fmt); | | | } | | | async function waitProgress(pUrl, dlUrl, vid, fmt, title) { | |

| for (const s of ["extracting video", "converting video"]) { | |
| await delay(3000); | |
| console.log(` ${s}`); | |

| } | | | await download(dlUrl, vid, fmt, title); | | | } | |

| async function download(dlUrl, vid, fmt, title) { | |
| const safe = `${(title || vid).replace(/[/\\?%*:|"<>]/g, "_")}.${fmt}`; | |
| console.log(`\n✓ down: ${safe}`); | |
| const res = await fetch(`${dlUrl}&v=${vid}&f=${fmt}&r=cli`, { headers: HEADERS, redirect: "follow" }); | |
| if (!res.ok) throw new Error(`download: HTTP ${res.status}`); | |
| await pipeline(res.body, createWriteStream(safe)); | |
| console.log(`✓ saved: ${safe}`); | |

| } | |

| const delay = (ms) => new Promise((r) => setTimeout(r, ms)); | |
| function extractId(str) { | |
| return (/(?:youtu\.be\/|youtube\.com\/(?:embed\/|live\/|shorts\/)|[?&]v=)([a-zA-Z0-9-_]{11})/.exec(str) || [])[1] || null; | |

| } | |

| const vid = extractId(youtube); | |
| if (!vid) { console.error("invalid URL"); process.exit(1); } | |
| if (FORMAT !== "mp3" && FORMAT !== "mp4") { console.error("invalid format"); process.exit(1); } | |
| console.log(`\n→ processing [${vid}] as ${FORMAT}`); | |
| try { await auth(vid, FORMAT); } | |
| catch (e) { console.error("✗", e.message); process.exit(1); } |
── more in #developer-tools 4 stories · sorted by recency
── more on @claidex 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/yt2mp3-gs-scrape-by-…] indexed:0 read:3min 2026-06-24 ·