hydra_scraper
Version:
A simple scraper.
367 lines (326 loc) • 11 kB
JavaScript
const axios = require('axios');
const yts = require('yt-search');
const { createDecipheriv } = require('crypto');
const cheerio = require('cheerio');
const formData = require('form-data');
const { lookup } = require('mime-types');
const extractVideoId = (url) => {
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|v\/|embed\/|user\/[^\/\n\s]+\/)?(?:watch\?v=|v%3D|embed%2F|video%2F)?|youtu\.be\/|youtube\.com\/watch\?v=|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/shorts\/|youtube\.com\/playlist\?list=)([a-zA-Z0-9_-]{11})/;
const result = url.match(regex);
return result ? result[1] : null;
};
const audioQualities = [32, 64, 96, 128, 160, 192, 256, 320];
const videoQualities = [144, 240, 360, 480, 720, 1080, 1440];
const decryptInfo = (encoded) => {
const secret = 'C5D58EF67A7584E4A29F6C35BBC4EB12';
const buffer = Buffer.from(encoded, 'base64');
const iv = buffer.slice(0, 16);
const encrypted = buffer.slice(16);
const key = Buffer.from(secret, 'hex');
const decipher = createDecipheriv('aes-128-cbc', key, iv);
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
return JSON.parse(decrypted.toString());
};
const fetchDownload = async (url, quality, type) => {
try {
const { data: cdnData } = await axios.get('https://media.savetube.me/api/random-cdn');
const cdnUrl = `https://${cdnData.cdn}`;
const { data: infoEnc } = await axios.post(`${cdnUrl}/v2/info`, { url }, {
headers: {
'User-Agent': 'Mozilla/5.0 (Android)',
'Referer': 'https://yt.savetube.me/1kejjj1?id=362796039'
}
});
const info = decryptInfo(infoEnc.data);
const { data: downloadRes } = await axios.post(`${cdnUrl}/download`, {
downloadType: type,
quality: String(quality),
key: info.key
}, {
headers: {
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Android)',
'Referer': 'https://yt.savetube.me/start-download?from=1kejjj1%3Fid%3D362796039'
}
});
let size = null;
try {
const { headers } = await axios.head(downloadRes.data.downloadUrl);
size = headers['content-length'] ? Number(headers['content-length']) : null;
} catch (e) {
console.warn('Gagal mengambil ukuran file:', e.message);
}
return {
status: true,
url: downloadRes.data.downloadUrl,
quality: `${quality}${type === 'audio' ? 'kbps' : 'p'}`,
availableQuality: type === 'audio' ? audioQualities : videoQualities,
size,
filename: `${info.title} (${quality}${type === 'audio' ? 'kbps).mp3' : 'p).mp4'}`
};
} catch (err) {
console.error('Download error:', err.message);
return { status: false, message: 'Download gagal' };
}
};
const ytmp3 = async (link, quality = 128) => {
const id = extractVideoId(link);
if (!id) return { status: false, message: 'URL YouTube tidak valid' };
const finalQuality = audioQualities.includes(+quality) ? +quality : 128;
const videoUrl = `https://youtube.com/watch?v=${id}`;
try {
const info = await yts(videoUrl);
const result = await fetchDownload(videoUrl, finalQuality, 'audio');
return {
status: true,
creator: 'hydra_scraper',
metadata: info.all[0],
download: result
};
} catch (e) {
return { status: false, message: e.message };
}
};
const ytmp4 = async (link, quality = 360) => {
if (!link.includes('youtube.com') && !link.includes('youtu.be')) {
return { status: false, message: 'URL YouTube tidak valid' };
}
try {
const info = await yts(link);
const videoUrl = await axios.get(`https://api.ryzumi.vip/api/downloader/ytmp4?url=${link}&quality=${quality}`);
return {
status: true,
creator: 'hydra_scraper',
metadata: info.all[0],
download: {
url: videoUrl.data.url,
quality: quality,
filename: `${videoUrl.data.title} (${quality}p).mp4`,
},
};
} catch (e) {
return { status: false, message: e.message };
}
};
const transcript = async (url) => {
try {
let res = await axios.get('https://yts.kooska.xyz/', {
params: { url: url },
headers: {
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36',
'Referer': 'https://kooska.xyz/'
}
}).then(i=>i.data)
return {
status: true,
creator: "hydra_scraper",
video_id: res.video_id,
summarize: res.ai_response,
transcript: res.transcript
}
} catch(e) {
return {
status: false,
msg: `Gagal mendapatkan respon, dengan pesan: ${e.message}`
}
}
}
const playmp3 = async (query, quality = 128) => {
try {
const searchResult = await search(query);
if (!searchResult.status || !searchResult.results.length)
return { status: false, message: 'Video tidak ditemukan' };
const results = [];
for (let video of searchResult.results.slice(0, 5)) {
const downloadInfo = await fetchDownload(video.url, quality, 'audio');
results.push({
title: video.title,
author: video.author.name,
duration: video.timestamp,
url: video.url,
thumbnail: video.thumbnail,
download: downloadInfo
});
}
return {
status: true,
creator: 'hydra_scraper',
type: 'audio',
results
};
} catch (err) {
return { status: false, message: err.message };
}
};
const playmp4 = async (query, quality = 360) => {
try {
const searchResult = await search(query);
if (!searchResult.status || !searchResult.results.length)
return { status: false, message: 'Video tidak ditemukan' };
const results = [];
for (let video of searchResult.results.slice(0, 5)) {
const downloadInfo = await fetchDownload(video.url, quality, 'video');
results.push({
title: video.title,
author: video.author.name,
duration: video.timestamp,
url: video.url,
thumbnail: video.thumbnail,
download: downloadInfo
});
}
return {
status: true,
creator: 'hydra_scraper',
type: 'video',
results
};
} catch (err) {
return { status: false, message: err.message };
}
};
const ttdl = async (url) => {
let retries = 0;
let maxRetries = 10;
let retryDelay = 4000;
while (retries < maxRetries) {
try {
const res = await axios(`https://tikwm.com/api/?url=${url}`);
const data = res.data?.data;
if (!data) throw new Error(res.data?.msg || 'Invalid API response');
const isPhotoMode = Array.isArray(data.images);
return {
status: true,
creator: "hydra_scraper",
type: isPhotoMode ? "photo" : "video",
title: data.title,
author: {
username: data.author?.unique_id,
nickname: data.author?.nickname,
avatar: data.author?.avatar
},
...(isPhotoMode
? {
images: data.images,
imageCount: data.images.length
}
: {
duration: data.duration,
video_no_watermark: data.play,
video_watermark: data.wmplay,
music_url: data.music,
music_title: data.music_info?.title,
music_play: data.music_info?.play,
size: data.size,
wm_size: data.wm_size,
})
};
} catch (error) {
retries++;
if (retries >= maxRetries) {
return {
status: false,
message: `Failed after ${maxRetries} attempts: ${error.message}`
};
}
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
};
const pindl = async (url) => {
try {
let a = await axios.get(url, {
headers: {
'User-Agent': "Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/17.0 Chrome/96.0.4664.104 Mobile Safari/537.36",
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
}
});
let $ = cheerio.load(a.data);
let x = $('script[data-test-id="leaf-snippet"]').text();
let y = $('script[data-test-id="video-snippet"]').text();
let g = {
status: true,
creator: "hydra_scraper",
isVideo: !!y,
info: JSON.parse(x),
image: JSON.parse(x).image,
video: y ? JSON.parse(y).contentUrl : ''
};
return g;
} catch (e) {
return {
status: false,
mess: "failed download"
};
}
};
const igdl = async (url) => {
try {
let result = {
status: true,
creator: "hydra_scraper",
media: []
}
const {
data
} = await axios(`https://www.y2mate.com/mates/analyzeV2/ajax`, {
method: "post",
data: {
k_query: url,
k_page: "Instagram",
hl: "id",
q_auto: 0
},
headers: {
"content-type": "application/x-www-form-urlencoded",
"user-agent": "PostmanRuntime/7.32.2"
}
})
await data.links.video.map((video) => result.media.push(video.url))
return result
} catch (err) {
const result = {
status: false,
message: `Media not found`
}
return result
}
}
const mfdl = async (url) => {
try {
const res = await fetch(`https://rianofc-bypass.hf.space/scrape?url=${encodeURIComponent(url)}`);
const html = await res.json();
const $ = cheerio.load(html.html);
const result = {
filename: $('.dl-info').find('.intro .filename').text().trim(),
type: $('.dl-btn-label').find('.filetype > span').text().trim(),
size: $('.details li:contains("File size:") span').text().trim(),
uploaded: $('.details li:contains("Uploaded:") span').text().trim(),
ext: /\.(.*?)/.exec($('.dl-info').find('.filetype > span').eq(1).text())?.[1]?.trim() || 'bin',
download: $('.input').attr('href')
};
result.mimetype = lookup(result.ext.toLowerCase()) || 'application/octet-stream';
return {
status: true,
creator: 'hydra_scraper',
result
};
} catch (err) {
return {
status: false,
message: err.message
};
}
}
module.exports = {
ttdl,
playmp3,
playmp4,
ytmp3,
ytmp4,
transcript,
pindl,
igdl,
mfdl
};