UNPKG

adonix-scraper

Version:

Scraper para YouTube audio/video gratis. ( hecho por Ado )

142 lines (135 loc) 5 kB
//Hecho por Ado [ github.com/Ado-rgb ] import axios from 'axios' import crypto from 'crypto' const AdonixScraper = { api: { base: "https://api3.apiapi.lat", endpoints: { a: "https://api5.apiapi.lat", b: "https://api.apiapi.lat", c: "https://api3.apiapi.lat" } }, headers: { 'authority': 'api.apiapi.lat', 'content-type': 'application/json', 'origin': 'https://ogmp3.lat', 'referer': 'https://ogmp3.lat/', 'user-agent': 'Postify/1.0.0' }, formats: { video: ['240', '360', '480', '720', '1080'], audio: ['64', '96', '128', '192', '256', '320'] }, default_fmt: { video: '720', audio: '320' }, utils: { hash: () => crypto.randomBytes(16).toString('hex'), encoded: str => [...str].map(c => String.fromCharCode(c.charCodeAt(0) ^ 1)).join(''), enc_url: (url, sep = ",") => url.split('').map(c => c.charCodeAt(0)).reverse().join(sep) }, isUrl: str => { try { const u = new URL(str) const host = u.hostname.toLowerCase() const yt = [/^(.+\.)?youtube\.com$/, /^(.+\.)?youtube-nocookie\.com$/, /^youtu\.be$/] return yt.some(r => r.test(host)) && !u.searchParams.has("playlist") } catch { return false } }, youtube: url => { const rxs = [ /youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/, /youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/, /youtube\.com\/v\/([a-zA-Z0-9_-]{11})/, /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/, /youtu\.be\/([a-zA-Z0-9_-]{11})/ ] for (let r of rxs) if (r.test(url)) return url.match(r)[1] return null }, request: async (endpoint, data = {}, method = 'post') => { try { const base = Object.values(AdonixScraper.api.endpoints)[Math.floor(Math.random() * 3)] const url = endpoint.startsWith('http') ? endpoint : `${base}${endpoint}` const res = await axios({ method, url, data, headers: AdonixScraper.headers }) return { status: true, code: 200, data: res.data } } catch (e) { return { status: false, code: e.response?.status || 500, error: e.message } } }, checkStatus: async function (id) { const c = this.utils.hash(), d = this.utils.hash() const endpoint = `/${c}/status/${this.utils.encoded(id)}/${d}/` return await this.request(endpoint, { data: id }) }, checkProgress: async function (data) { let tries = 0 while (tries++ < 300) { const res = await this.checkStatus(data.i) if (!res.status) await new Promise(r => setTimeout(r, 2000)) else if (res.data.s === "C") return res.data else if (res.data.s === "P") await new Promise(r => setTimeout(r, 2000)) else return null } return null }, download: async function (link, format = '320', type = 'audio') { if (!link || !this.isUrl(link)) return { status: false, error: "❌ Link no válido" } const valid = this.formats[type] if (!valid.includes(format)) return { status: false, error: `❌ Formato inválido: ${format}` } const id = this.youtube(link) if (!id) return { status: false, error: "❌ ID no válida" } for (let i = 0; i < 20; i++) { const c = this.utils.hash(), d = this.utils.hash() const req = { data: this.utils.encoded(link), format: type === 'audio' ? "0" : "1", referer: "https://ogmp3.cc", mp3Quality: type === 'audio' ? format : null, mp4Quality: type === 'video' ? format : null, userTimeZone: new Date().getTimezoneOffset().toString() } const res = await this.request(`/${c}/init/${this.utils.enc_url(link)}/${d}/`, req) if (!res.status) continue const data = res.data if (data.le) return { status: false, error: "⏱️ Video muy largo" } if (data.i === "blacklisted") return { status: false, error: "🚫 Límite diario alcanzado" } if (data.i === "invalid" || data.e) return { status: false, error: "📛 Video no disponible" } if (data.s === "C") { return { status: true, result: { title: data.t || "Sin título", id, format, type, quality: format, thumbnail: `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`, download: `${this.api.base}/${this.utils.hash()}/download/${this.utils.encoded(data.i)}/${this.utils.hash()}/` } } } const check = await this.checkProgress(data) if (check?.s === "C") { return { status: true, result: { title: check.t || "Sin título", id, format, type, quality: format, thumbnail: `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`, download: `${this.api.base}/${this.utils.hash()}/download/${this.utils.encoded(check.i)}/${this.utils.hash()}/` } } } } return { status: false, error: "❌ Muchos intentos fallidos" } } } export default AdonixScraper