adonix-scraper
Version:
Scraper para YouTube audio/video gratis. ( hecho por Ado )
142 lines (135 loc) • 5 kB
JavaScript
//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