@soyaxell09/zenbot-scraper 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -180
- package/package.json +13 -4
- package/src/index.js +12 -0
- package/src/nsfw/index.js +17 -0
- package/src/nsfw/phdl.js +147 -0
- package/src/nsfw/phsearch.js +48 -0
- package/src/nsfw/rule34.js +86 -0
- package/src/nsfw/xhammerdl.js +162 -0
- package/src/nsfw/xhamstersearch.js +41 -0
- package/src/nsfw/xnxxdl.js +81 -0
- package/src/nsfw/xnxxsearch.js +59 -0
- package/src/nsfw/xvideosdl.js +79 -0
- package/src/nsfw/xvideossearch.js +54 -0
- package/src/scrapers/index.js +3 -1
- package/src/scrapers/instagram.js +98 -0
- package/src/scrapers/spotidown.js +89 -0
- package/src/tools/index.js +1 -0
- package/src/tools/screenshot.js +34 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* © Created by AxelDev09 🔥
|
|
3
|
+
* GitHub: https://github.com/AxelDev09
|
|
4
|
+
* Instagram: @axeldev09
|
|
5
|
+
* Deja los créditos we 🗣️
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import * as cheerio from 'cheerio';
|
|
10
|
+
|
|
11
|
+
const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
12
|
+
|
|
13
|
+
function parseDuration(iso) {
|
|
14
|
+
if (!iso) return null;
|
|
15
|
+
const match = iso.match(/PT(\d+)H(\d+)M(\d+)S/);
|
|
16
|
+
if (!match) return iso;
|
|
17
|
+
const h = parseInt(match[1]);
|
|
18
|
+
const m = parseInt(match[2]);
|
|
19
|
+
const s = parseInt(match[3]);
|
|
20
|
+
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
21
|
+
return `${m}:${String(s).padStart(2, '0')}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function xvideosDownload(url) {
|
|
25
|
+
const { data } = await axios.get(url, {
|
|
26
|
+
headers: { 'User-Agent': UA },
|
|
27
|
+
timeout: 12000
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const $ = cheerio.load(data);
|
|
31
|
+
const scripts = $('script').map((_, el) => $(el).html()).get();
|
|
32
|
+
|
|
33
|
+
let playerScript = null;
|
|
34
|
+
for (const s of scripts) {
|
|
35
|
+
if (s && s.includes('setVideoUrlLow')) {
|
|
36
|
+
playerScript = s;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const extract = (key) => {
|
|
42
|
+
if (!playerScript) return null;
|
|
43
|
+
const match = playerScript.match(new RegExp(`${key}\\('([^']+)'\\)`));
|
|
44
|
+
return match ? match[1] : null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const low = extract('setVideoUrlLow');
|
|
48
|
+
const high = extract('setVideoUrlHigh');
|
|
49
|
+
const hls = extract('setVideoHLS');
|
|
50
|
+
const thumb = extract('setThumbUrl169') || extract('setThumbUrl');
|
|
51
|
+
|
|
52
|
+
const jsonLd = $('script[type="application/ld+json"]').first().html();
|
|
53
|
+
let title = null, duration = null, views = null, uploadDate = null, thumbFallback = null;
|
|
54
|
+
if (jsonLd) {
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(jsonLd);
|
|
57
|
+
title = parsed.name || null;
|
|
58
|
+
thumbFallback = Array.isArray(parsed.thumbnailUrl) ? parsed.thumbnailUrl[0] : parsed.thumbnailUrl || null;
|
|
59
|
+
duration = parseDuration(parsed.duration);
|
|
60
|
+
views = parsed.interactionStatistic?.userInteractionCount || null;
|
|
61
|
+
uploadDate = parsed.uploadDate?.slice(0, 10) || null;
|
|
62
|
+
} catch {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!low && !high) throw new Error('No se encontraron URLs de descarga.');
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
title,
|
|
69
|
+
thumb: thumb || thumbFallback,
|
|
70
|
+
duration,
|
|
71
|
+
views,
|
|
72
|
+
uploadDate,
|
|
73
|
+
download: {
|
|
74
|
+
low: low ? { quality: '240p', url: low } : null,
|
|
75
|
+
high: high ? { quality: '360p', url: high } : null,
|
|
76
|
+
hls: hls ? { quality: 'HLS', url: hls } : null
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* © Created by AxelDev09 🔥
|
|
3
|
+
* GitHub: https://github.com/AxelDev09
|
|
4
|
+
* Instagram: @axeldev09
|
|
5
|
+
* Deja los créditos we 🗣️
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import * as cheerio from 'cheerio';
|
|
10
|
+
|
|
11
|
+
const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
12
|
+
|
|
13
|
+
export async function xvideosSearch(query, limit = 10) {
|
|
14
|
+
const { data } = await axios.get(`https://www.xvideos.com/?k=${encodeURIComponent(query)}`, {
|
|
15
|
+
headers: { 'User-Agent': UA },
|
|
16
|
+
timeout: 12000
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const $ = cheerio.load(data);
|
|
20
|
+
const results = [];
|
|
21
|
+
|
|
22
|
+
$('.thumb-block').each((_, el) => {
|
|
23
|
+
if (results.length >= limit) return false;
|
|
24
|
+
|
|
25
|
+
const img = $(el).find('img');
|
|
26
|
+
const anchor = $(el).find('.thumb-inside a').first();
|
|
27
|
+
const titleEl = $(el).find('a[title]').first();
|
|
28
|
+
const metadata = $(el).find('.metadata').text().replace(/\s+/g, ' ').trim();
|
|
29
|
+
|
|
30
|
+
const href = anchor.attr('href') || '';
|
|
31
|
+
const title = titleEl.attr('title') || '';
|
|
32
|
+
const thumb = img.attr('data-src') || '';
|
|
33
|
+
const preview = img.attr('data-pvv') || '';
|
|
34
|
+
const duration = $(el).find('.duration').first().text().trim();
|
|
35
|
+
const quality = $(el).find('.video-hd-mark').text().trim();
|
|
36
|
+
|
|
37
|
+
const viewsMatch = metadata.match(/([\d.]+[KMB]?)\s*Views/i);
|
|
38
|
+
const views = viewsMatch ? viewsMatch[1] : '';
|
|
39
|
+
|
|
40
|
+
if (!title || !href) return;
|
|
41
|
+
|
|
42
|
+
results.push({
|
|
43
|
+
title,
|
|
44
|
+
url: `https://www.xvideos.com${href}`,
|
|
45
|
+
thumb,
|
|
46
|
+
preview,
|
|
47
|
+
duration,
|
|
48
|
+
views,
|
|
49
|
+
quality
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return results;
|
|
54
|
+
}
|
package/src/scrapers/index.js
CHANGED
|
@@ -6,4 +6,6 @@ export { tweetInfo, tweetDownload } from './twitt
|
|
|
6
6
|
export { mediafireInfo } from './mediafire.js'
|
|
7
7
|
export { githubInfo, githubRelease, githubContents, githubSearch } from './github.js'
|
|
8
8
|
export { apkSearch, apkInfo } from './apk.js'
|
|
9
|
-
export { gdriveInfo, gdriveDownload } from './gdrive.js'
|
|
9
|
+
export { gdriveInfo, gdriveDownload } from './gdrive.js'
|
|
10
|
+
export { igDownload } from './instagram.js'
|
|
11
|
+
export { spotidownTrack } from './spotidown.js'
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* © Created by AxelDev09 🔥
|
|
3
|
+
* GitHub: https://github.com/AxelDev09
|
|
4
|
+
* Instagram: @axeldev09
|
|
5
|
+
* Deja los créditos we 🗣️
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import * as cheerio from 'cheerio';
|
|
10
|
+
|
|
11
|
+
const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
12
|
+
const AJAX_URL = 'https://igsnapinsta.com/wp-admin/admin-ajax.php';
|
|
13
|
+
const BASE_URL = 'https://igsnapinsta.com';
|
|
14
|
+
|
|
15
|
+
function decodeUrl(encodedUrl) {
|
|
16
|
+
try { return Buffer.from(encodedUrl, 'base64').toString('utf-8'); }
|
|
17
|
+
catch { return encodedUrl; }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseItems(html) {
|
|
21
|
+
const $ = cheerio.load(html);
|
|
22
|
+
const items = [];
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
|
|
25
|
+
function add(type, url) {
|
|
26
|
+
const clean = url.replace(/&/g, '&').trim();
|
|
27
|
+
if (!clean || seen.has(clean)) return;
|
|
28
|
+
seen.add(clean);
|
|
29
|
+
items.push({ type, url: clean });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
$('source[src]').each((_, el) => {
|
|
33
|
+
const src = $(el).attr('src');
|
|
34
|
+
if (src) add('video', src);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$('a[href]').each((_, el) => {
|
|
38
|
+
const href = $(el).attr('href') || '';
|
|
39
|
+
if (!href.includes('kdnsd/v1/download')) return;
|
|
40
|
+
const b64 = href.split('url=')[1] || '';
|
|
41
|
+
const decoded = decodeUrl(decodeURIComponent(b64));
|
|
42
|
+
const type = decoded.includes('.mp4') ? 'video' : 'image';
|
|
43
|
+
add(type, href.replace(/&/g, '&'));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
$('img[src]').each((_, el) => {
|
|
47
|
+
const src = $(el).attr('src') || '';
|
|
48
|
+
if (src.includes('kdnsd/v1/download') || src.includes('cdninstagram') || src.includes('fbcdn'))
|
|
49
|
+
add('image', src);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return items;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function detectType(url) {
|
|
56
|
+
if (url.includes('/reel/')) return 'reel';
|
|
57
|
+
if (url.includes('/p/')) return 'post';
|
|
58
|
+
if (url.includes('/stories/')) return 'story';
|
|
59
|
+
if (url.includes('/tv/')) return 'video';
|
|
60
|
+
const path = new URL(url).pathname.replace(/\/$/, '');
|
|
61
|
+
if (path.split('/').length === 2) return 'profile';
|
|
62
|
+
return 'post';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function igDownload(url) {
|
|
66
|
+
if (!url.includes('instagram.com'))
|
|
67
|
+
throw new Error('URL inválida. Debe ser un link de Instagram.');
|
|
68
|
+
|
|
69
|
+
const { data } = await axios.post(
|
|
70
|
+
AJAX_URL,
|
|
71
|
+
new URLSearchParams({ action: 'kdnsd_get_instagram_video', url }),
|
|
72
|
+
{
|
|
73
|
+
headers: {
|
|
74
|
+
'User-Agent': UA,
|
|
75
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
76
|
+
'Referer': `${BASE_URL}/es/`,
|
|
77
|
+
'Origin': BASE_URL,
|
|
78
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
79
|
+
},
|
|
80
|
+
timeout: 20000
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (!data?.success || !data?.data?.html) {
|
|
85
|
+
const html = data?.data?.html || '';
|
|
86
|
+
if (html.includes('private') || html.includes('privado') || data?.data?.message?.includes('private'))
|
|
87
|
+
throw new Error('Perfil privado. Solo se puede descargar contenido de perfiles públicos.');
|
|
88
|
+
throw new Error('No se pudo obtener el contenido. Verificá que el perfil/post sea público.');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const type = detectType(url);
|
|
92
|
+
const items = parseItems(data.data.html);
|
|
93
|
+
|
|
94
|
+
if (!items.length)
|
|
95
|
+
throw new Error('No se encontró contenido descargable.');
|
|
96
|
+
|
|
97
|
+
return { type, items };
|
|
98
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* © Created by AxelDev09 🔥
|
|
3
|
+
* GitHub: https://github.com/AxelDev09
|
|
4
|
+
* Instagram: @axeldev09
|
|
5
|
+
* Deja los créditos we 🗣️
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import * as cheerio from 'cheerio';
|
|
10
|
+
|
|
11
|
+
const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
12
|
+
const BASE_URL = 'https://spotidown.app';
|
|
13
|
+
|
|
14
|
+
async function getSession() {
|
|
15
|
+
const { data, headers } = await axios.get(`${BASE_URL}/es5`, {
|
|
16
|
+
headers: { 'User-Agent': UA }, timeout: 12000
|
|
17
|
+
});
|
|
18
|
+
const $ = cheerio.load(data);
|
|
19
|
+
const tokenName = $('input[type="hidden"]').not('[name="g-recaptcha-response"]').first().attr('name');
|
|
20
|
+
const token = $('input[type="hidden"]').not('[name="g-recaptcha-response"]').first().val();
|
|
21
|
+
const cookies = headers['set-cookie']?.map(c => c.split(';')[0]).join('; ') || '';
|
|
22
|
+
return { tokenName, token, cookies };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildHeaders(cookies) {
|
|
26
|
+
return {
|
|
27
|
+
'User-Agent': UA,
|
|
28
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
29
|
+
'Referer': `${BASE_URL}/es5`,
|
|
30
|
+
'Origin': BASE_URL,
|
|
31
|
+
'Cookie': cookies,
|
|
32
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function spotidownTrack(url) {
|
|
37
|
+
if (!url.includes('spotify.com/track'))
|
|
38
|
+
throw new Error('URL inválida. Debe ser un link de track de Spotify.');
|
|
39
|
+
|
|
40
|
+
const { tokenName, token, cookies } = await getSession();
|
|
41
|
+
|
|
42
|
+
const { data: actionData } = await axios.post(
|
|
43
|
+
`${BASE_URL}/action`,
|
|
44
|
+
new URLSearchParams({ url, 'g-recaptcha-response': '', [tokenName]: token }),
|
|
45
|
+
{ headers: buildHeaders(cookies), timeout: 20000 }
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (actionData?.error) throw new Error(actionData.message || 'Error al obtener el track.');
|
|
49
|
+
|
|
50
|
+
const $r = cheerio.load(actionData.data || '');
|
|
51
|
+
const dataF = $r('input[name="data"]').first().val();
|
|
52
|
+
const baseF = $r('input[name="base"]').first().val();
|
|
53
|
+
const tkF = $r('input[name="token"]').first().val();
|
|
54
|
+
|
|
55
|
+
if (!dataF) throw new Error('No se pudo obtener la info del track.');
|
|
56
|
+
|
|
57
|
+
const trackInfo = JSON.parse(Buffer.from(dataF, 'base64').toString());
|
|
58
|
+
|
|
59
|
+
const { data: trackData } = await axios.post(
|
|
60
|
+
`${BASE_URL}/action/track`,
|
|
61
|
+
new URLSearchParams({ data: dataF, base: baseF, token: tkF }),
|
|
62
|
+
{ headers: buildHeaders(cookies), timeout: 30000 }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (trackData?.error) throw new Error(trackData.message || 'Error al descargar el track.');
|
|
66
|
+
|
|
67
|
+
const $t = cheerio.load(trackData.data || '');
|
|
68
|
+
const links = [];
|
|
69
|
+
|
|
70
|
+
$t('a[id="popup"]').each((_, el) => {
|
|
71
|
+
const href = $t(el).attr('href') || '';
|
|
72
|
+
const label = $t(el).find('span span').text().trim();
|
|
73
|
+
if (href) links.push({ label, url: href });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const mp3 = links.find(l => l.label.toLowerCase().includes('mp3'))?.url || null;
|
|
77
|
+
const cover = links.find(l => l.label.toLowerCase().includes('cover'))?.url || null;
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
name: trackInfo.name,
|
|
81
|
+
artist: trackInfo.artist,
|
|
82
|
+
album: trackInfo.album,
|
|
83
|
+
duration: trackInfo.duration,
|
|
84
|
+
year: trackInfo.date,
|
|
85
|
+
cover: trackInfo.cover,
|
|
86
|
+
mp3,
|
|
87
|
+
coverHd: cover,
|
|
88
|
+
};
|
|
89
|
+
}
|
package/src/tools/index.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* © Created by AxelDev09 🔥
|
|
3
|
+
* GitHub: https://github.com/AxelDev09
|
|
4
|
+
* Instagram: @axeldev09
|
|
5
|
+
* Deja los créditos we 🗣️
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
|
|
10
|
+
const UA = 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
11
|
+
|
|
12
|
+
export async function screenshot(url, width = 1280, height = 720) {
|
|
13
|
+
if (!/^https?:\/\//i.test(url)) url = `https://${url}`;
|
|
14
|
+
|
|
15
|
+
const { data } = await axios.get(
|
|
16
|
+
`https://image.thum.io/get/width/${width}/crop/${height}/${url}`,
|
|
17
|
+
{
|
|
18
|
+
responseType: 'arraybuffer',
|
|
19
|
+
timeout: 20000,
|
|
20
|
+
headers: { 'User-Agent': UA }
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (!data || data.byteLength < 5000) throw new Error('No se pudo capturar la página.');
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
url,
|
|
28
|
+
width,
|
|
29
|
+
height,
|
|
30
|
+
size: `${(data.byteLength / 1024).toFixed(1)} KB`,
|
|
31
|
+
buffer: Buffer.from(data)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|