@zenaveline/scraper 1.3.2 → 1.4.3
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 +7 -3
- package/package.json +2 -1
- package/src/mediafiredl.js +144 -0
- package/src/nanobanana.js +115 -0
- package/src/savetube.js +85 -0
package/README.md
CHANGED
|
@@ -49,10 +49,11 @@ console.log(data) // output
|
|
|
49
49
|
Untuk project standar Node.js (seperti bot WhatsApp pada umumnya):
|
|
50
50
|
|
|
51
51
|
```javascript
|
|
52
|
-
const scraper = require(
|
|
52
|
+
const scraper = require("@zenaveline/scraper")
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
console.log
|
|
54
|
+
scraper.bypasstools("url")
|
|
55
|
+
.then(console.log)
|
|
56
|
+
.catch(console.error)
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
### 🎶 Khusus Penggunaan Spotify API
|
|
@@ -90,6 +91,8 @@ Panggil nama fungsinya sesuai daftar di bawah ini untuk menikmati semua fiturnya
|
|
|
90
91
|
| `douyindl(url)` | Download video Douyin tanpa watermark. |
|
|
91
92
|
| `allinonedownloader(url, tool)` | Downloader all-in-one yang mendukung banyak platform (Tiktok, YouTube, IG, dll). |
|
|
92
93
|
| `tiktokdownload(url)` | Download video/foto Tiktok tanpa watermark. |
|
|
94
|
+
| `savetube` | Class API untuk download video/audio dari YouTube. Gunakan dengan `new scraper.savetube()`. |
|
|
95
|
+
| `mediafiredl(url)` | Unduh file atau folder secara langsung dari Mediafire. |
|
|
93
96
|
|
|
94
97
|
### 🎵 Musik & Audio
|
|
95
98
|
| Fungsi | Deskripsi Singkat |
|
|
@@ -107,6 +110,7 @@ Panggil nama fungsinya sesuai daftar di bawah ini untuk menikmati semua fiturnya
|
|
|
107
110
|
| `novaai(text)` | Chatbot interaktif menggunakan Nova AI untuk menjawab pertanyaan apa saja. |
|
|
108
111
|
| `sharpify(img, model)` | Tools manipulasi gambar keren: `enhance`, `upscale` (Bikin HD), atau `removebg`. |
|
|
109
112
|
| `pixaremovebg(img)` | Algoritma canggih dari Pixacut API untuk menghapus background dengan hasil super rapi. |
|
|
113
|
+
| `nanobanana(buffer, prompt)` | Edit gambar dengan instruksi teks (prompt) menggunakan AI Live3D. |
|
|
110
114
|
|
|
111
115
|
### ℹ️ Utility
|
|
112
116
|
| Fungsi | Deskripsi Singkat |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenaveline/scraper",
|
|
3
|
-
"version": "1.3
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "Kumpulan scraper yang mudah digunakan!",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"@zenaveline/scraper",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"axios": "^1.6.0",
|
|
26
26
|
"cheerio": "^1.0.0",
|
|
27
27
|
"crypto": "^1.0.1",
|
|
28
|
+
"form-data": "^4.0.0",
|
|
28
29
|
"sharp": "^0.33.2"
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const cheerio = require('cheerio')
|
|
2
|
+
const axios = require("axios")
|
|
3
|
+
|
|
4
|
+
const regex_ = {
|
|
5
|
+
folder: /\.com\/folder\/([^\/]+)\/?/,
|
|
6
|
+
file: /\.com\/(view|file)\/([a-zA-Z0-9]+)/
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function extractFromWeb(is, link) {
|
|
10
|
+
try {
|
|
11
|
+
const lnk = link.replace('.com/view', '.com/file');
|
|
12
|
+
const f = await is.get(lnk)
|
|
13
|
+
const $ = cheerio.load(f.data)
|
|
14
|
+
const url = $('.input.popsok').attr('href')
|
|
15
|
+
|
|
16
|
+
if (!url || !/\/\/download\d+\.mediafire\.com\//.test(url)) throw Error ('Failed to find download url on the web')
|
|
17
|
+
|
|
18
|
+
const [name, date, size, type] = [
|
|
19
|
+
$('.intro .filename').text(),
|
|
20
|
+
$('.details li:nth-child(2) span').text(),
|
|
21
|
+
$('.details li:nth-child(1) span').text(),
|
|
22
|
+
$('.intro .filetype').text()
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
const cont = {
|
|
26
|
+
'af': 'Africa',
|
|
27
|
+
'an': 'Antarctica',
|
|
28
|
+
'as': 'Asia',
|
|
29
|
+
'eu': 'Europe',
|
|
30
|
+
'na': 'North America',
|
|
31
|
+
'oc': 'Oceania',
|
|
32
|
+
'sa': 'South America'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const $lo = $('.DLExtraInfo-uploadLocation')
|
|
36
|
+
|
|
37
|
+
const [continent, location, flag] = [
|
|
38
|
+
$lo.find('.DLExtraInfo-uploadLocationRegion').attr('data-lazyclass')?.replace('continent-', ''),
|
|
39
|
+
$lo.find('.DLExtraInfo-sectionDetails p').text().match(/from (.*?) on/)?.[1],
|
|
40
|
+
$lo.find('div.lazyload.flag').attr('data-lazyclass')?.replace('flag-', '')
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
size_format: size,
|
|
45
|
+
continent: cont[continent] || 'Unkown',
|
|
46
|
+
flag,
|
|
47
|
+
location,
|
|
48
|
+
url,
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
throw e
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function mediafire(link) {
|
|
56
|
+
try {
|
|
57
|
+
const is = axios.create({
|
|
58
|
+
baseURL: "https://www.mediafire.com",
|
|
59
|
+
headers: {
|
|
60
|
+
'accept-encoding' : 'gzip, deflate, br, zstd',
|
|
61
|
+
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (regex_.folder.test(link)) {
|
|
66
|
+
const ab = link.match(regex_.folder)
|
|
67
|
+
const getId = ab ? ab[1] : null;
|
|
68
|
+
|
|
69
|
+
const { data: info } = await is.get('/api/1.4/folder/get_info.php', {
|
|
70
|
+
params: {
|
|
71
|
+
recursive: 'yes',
|
|
72
|
+
folder_key: getId,
|
|
73
|
+
response_format: 'json'
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
let files_ = [], chunk = 1;
|
|
78
|
+
|
|
79
|
+
while (true) {
|
|
80
|
+
const { data: files } = await is.get('/api/1.4/folder/get_content.php', {
|
|
81
|
+
params: {
|
|
82
|
+
r: 'hrdd',
|
|
83
|
+
content_type: 'files',
|
|
84
|
+
filter: 'all',
|
|
85
|
+
order_by: 'name',
|
|
86
|
+
order_direction: 'asc',
|
|
87
|
+
chunk: chunk,
|
|
88
|
+
version: '1.5',
|
|
89
|
+
folder_key: getId,
|
|
90
|
+
response_format: 'json'
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
files.response.folder_content.files.map(p => files_.push({
|
|
94
|
+
...p,
|
|
95
|
+
links: p.links.normal_download,
|
|
96
|
+
}));
|
|
97
|
+
if (files.response.folder_content.more_chunks === 'no') break;
|
|
98
|
+
chunk++;
|
|
99
|
+
await new Promise(r => setTimeout(r, 2e3));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
status: true,
|
|
104
|
+
type: 'folder',
|
|
105
|
+
...info.response.folder_info,
|
|
106
|
+
files: files_
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const match = link.match(regex_.file);
|
|
111
|
+
const ab = match ? match[2] : null;
|
|
112
|
+
|
|
113
|
+
let { data: info } = await is.get('/api/1.5/file/get_info.php', {
|
|
114
|
+
params: {
|
|
115
|
+
quick_key: ab,
|
|
116
|
+
response_format: 'json'
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
let inf = info.response.file_info, wb = await extractFromWeb(is, link);
|
|
121
|
+
if (!wb.type) wb = await extractFromWeb(is, link);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
status: true,
|
|
125
|
+
type: 'file',
|
|
126
|
+
...inf,
|
|
127
|
+
links: inf.links.normal_download,
|
|
128
|
+
...wb,
|
|
129
|
+
...(!!inf.links.view ? {
|
|
130
|
+
preview: is.defaults.baseURL + '/convkey/' + inf.hash.substr(0, 4) + '/' + inf.quickkey + '9g.' + inf.filename.split('.').pop()
|
|
131
|
+
} : {}),
|
|
132
|
+
}
|
|
133
|
+
} catch(e) {
|
|
134
|
+
if (e.status === 404) {
|
|
135
|
+
return {
|
|
136
|
+
status: false,
|
|
137
|
+
msg: "Page not found or invalid link"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw e.response ? e.response.data : e.message
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = mediafire;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
const FormData = require('form-data');
|
|
4
|
+
|
|
5
|
+
async function live3d(buffer, prompt) {
|
|
6
|
+
const config = {
|
|
7
|
+
pkey: "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDd2xPK2JvQzZjd1JvM1VmWFZCYWRhWXdjWDB6S1MyZnVWTlkycVowZGd3YjFOSisvUTlGZUFvc0w0T05pb3NENzFvbjNQVllxUlVsTDUwNDVtdkgySzlpOGJBRlZNRWlwN0U2Uk1LNnRLQUFpZjd4elpyWG5QMUdaNVJpanRxZGd3aCtZbXpUbzM5Y3VCQ3NacUs5b0VvZVEzci9teUc5Uys5Y1I1aHVUdUZRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==",
|
|
8
|
+
aid: "aifaceswap",
|
|
9
|
+
uid: "1H5tRtzsBkqXcaJ",
|
|
10
|
+
origin: "8f3f0c7387123ae0",
|
|
11
|
+
theme_version: '83EmcUoQTUv50LhNx0VrdcK8rcGexcP35FcZDcpgWsAXEyO4xqL5shCY6sFIWB2Q',
|
|
12
|
+
model: 'nano_banana_2',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let currentFp = crypto.randomBytes(16).toString('hex');
|
|
16
|
+
|
|
17
|
+
const crypt = {
|
|
18
|
+
aes: (data, key) => {
|
|
19
|
+
const cipher = crypto.createCipheriv('aes-128-cbc', key, key);
|
|
20
|
+
return Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]).toString('base64')
|
|
21
|
+
},
|
|
22
|
+
rsa: (data) => {
|
|
23
|
+
return crypto.publicEncrypt({
|
|
24
|
+
key: Buffer.from(config.pkey, "base64").toString(),
|
|
25
|
+
padding: crypto.constants.RSA_PKCS1_PADDING,
|
|
26
|
+
}, Buffer.from(data, 'utf8')).toString('base64');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const api = axios.create({
|
|
31
|
+
baseURL: 'https://app-v1.live3d.io',
|
|
32
|
+
headers: {
|
|
33
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 16; NX729J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.34 Mobile Safari/537.36',
|
|
34
|
+
'origin': 'https://live3d.io',
|
|
35
|
+
'referer': 'https://live3d.io/',
|
|
36
|
+
'theme-version': config.theme_version
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
api.interceptors.request.use((cfg) => {
|
|
41
|
+
const [i, d, n] = [
|
|
42
|
+
crypto.randomBytes(8).toString('hex'),
|
|
43
|
+
crypto.randomUUID(),
|
|
44
|
+
Math.floor(Date.now() / 1000)
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
const s = crypt.rsa(i);
|
|
48
|
+
const signStr = cfg.url.includes('upload-img') ? `${config.aid}:${d}:${s}` : `${config.aid}:${config.uid}:${n}:${d}:${s}`;
|
|
49
|
+
|
|
50
|
+
Object.assign(cfg.headers, {
|
|
51
|
+
'fp': currentFp,
|
|
52
|
+
'fp1': crypt.aes(`${config.aid}:${currentFp}`, i),
|
|
53
|
+
'x-guide': s,
|
|
54
|
+
'x-sign': crypt.aes(signStr, i),
|
|
55
|
+
'x-code': Date.now().toString()
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return cfg;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const form = new FormData();
|
|
63
|
+
form.append('file', buffer, { filename: 'input.jpg', contentType: 'image/jpeg' });
|
|
64
|
+
form.append('fn_name', 'demo-image-editor');
|
|
65
|
+
form.append('request_from', '9');
|
|
66
|
+
form.append('origin_from', config.origin);
|
|
67
|
+
|
|
68
|
+
const { data: upRes } = await api.post('/aitools/upload-img', form, {
|
|
69
|
+
headers: form.getHeaders()
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const { data: job } = await api.post('/aitools/of/create', {
|
|
73
|
+
fn_name: 'demo-image-editor',
|
|
74
|
+
call_type: 3,
|
|
75
|
+
input: {
|
|
76
|
+
model: config.model,
|
|
77
|
+
source_images: [upRes.data.path],
|
|
78
|
+
prompt: prompt,
|
|
79
|
+
aspect_radio: 'auto',
|
|
80
|
+
request_from: 9
|
|
81
|
+
},
|
|
82
|
+
data: '',
|
|
83
|
+
request_from: 9,
|
|
84
|
+
origin_from: config.origin
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
const taskId = job.data.task_id;
|
|
89
|
+
if (!taskId) throw new Error("TaskId cannot be found")
|
|
90
|
+
|
|
91
|
+
while (true) {
|
|
92
|
+
const { data: status } = await api.post('/aitools/of/check-status', {
|
|
93
|
+
task_id: taskId,
|
|
94
|
+
fn_name: 'demo-image-editor',
|
|
95
|
+
call_type: 3,
|
|
96
|
+
request_from: 9,
|
|
97
|
+
origin_from: config.origin
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (status.data.status === 2) {
|
|
101
|
+
return {
|
|
102
|
+
status: 'success',
|
|
103
|
+
image_url: 'https://temp.live3d.io/' + status.data.result_image
|
|
104
|
+
};
|
|
105
|
+
} else if (status.data.status === 3) {
|
|
106
|
+
return status.data
|
|
107
|
+
}
|
|
108
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new Error(`Process failed: ${error.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = live3d;
|
package/src/savetube.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const crypto = require("crypto")
|
|
2
|
+
const axios = require("axios")
|
|
3
|
+
|
|
4
|
+
class savetube {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.ky = 'C5D58EF67A7584E4A29F6C35BBC4EB12';
|
|
7
|
+
this.fmt = ['144', '240', '360', '480', '720', '1080', 'mp3'];
|
|
8
|
+
this.m = /^((?:https?:)?\/\/)?((?:www|m|music)\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(?:embed\/)?(?:v\/)?(?:shorts\/)?([a-zA-Z0-9_-]{11})/;
|
|
9
|
+
this.is = axios.create({
|
|
10
|
+
headers: {
|
|
11
|
+
'content-type': 'application/json',
|
|
12
|
+
'origin': 'https://yt.savetube.me',
|
|
13
|
+
'user-agent': 'Mozilla/5.0 (Android 15; Mobile; SM-F958; rv:130.0) Gecko/130.0 Firefox/130.0'
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async decrypt(enc) {
|
|
19
|
+
try {
|
|
20
|
+
const [sr, ky] = [Buffer.from(enc,'base64'), Buffer.from(this.ky,'hex')]
|
|
21
|
+
const [iv, dt] = [sr.slice(0,16), sr.slice(16)]
|
|
22
|
+
const dc = crypto.createDecipheriv('aes-128-cbc', ky, iv);
|
|
23
|
+
return JSON.parse(Buffer.concat([dc.update(dt), dc.final()]).toString());
|
|
24
|
+
} catch (e) {
|
|
25
|
+
throw new Error(`Error while decrypting data: ${e.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getCdn() {
|
|
30
|
+
const response = await this.is.get("https://media.savetube.vip/api/random-cdn");
|
|
31
|
+
if (!response.status) return response;
|
|
32
|
+
return {
|
|
33
|
+
status: true,
|
|
34
|
+
data: response.data.cdn
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async download(url, format = 'mp3') {
|
|
39
|
+
const id = url.match(this.m)?.[3];
|
|
40
|
+
if (!id) {
|
|
41
|
+
return {
|
|
42
|
+
status: false,
|
|
43
|
+
msg: "ID cannot be extracted from url"
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (!format || !this.fmt.includes(format)) {
|
|
47
|
+
return {
|
|
48
|
+
status: false,
|
|
49
|
+
msg: "Formats not found",
|
|
50
|
+
list: this.fmt
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const u = await this.getCdn();
|
|
55
|
+
if (!u.status) return u;
|
|
56
|
+
const res = await this.is.post(`https://${u.data}/v2/info`, {
|
|
57
|
+
url: `https://www.youtube.com/watch?v=${id}`
|
|
58
|
+
});
|
|
59
|
+
const dec = await this.decrypt(res.data.data);
|
|
60
|
+
const dl = await this.is.post(`https://${u.data}/download`, {
|
|
61
|
+
id: id,
|
|
62
|
+
downloadType: format === 'mp3' ? 'audio' : 'video',
|
|
63
|
+
quality: format === 'mp3' ? '128' : format,
|
|
64
|
+
key: dec.key
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
status: true,
|
|
69
|
+
title: dec.title,
|
|
70
|
+
format: format,
|
|
71
|
+
thumb: dec.thumbnail || `https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
|
|
72
|
+
duration: dec.duration,
|
|
73
|
+
cached: dec.fromCache,
|
|
74
|
+
dl: dl.data.data.downloadUrl
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
status: false,
|
|
79
|
+
error: error.message
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = savetube;
|