zhg.sql 1.4.5
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 +13 -0
- package/index.js +864 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @leoo-vanth/zarv7z
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://codecov.io/)
|
|
5
|
+
|
|
6
|
+
Yet another downloader module. Written with only Javascript and a node-friendly streaming interface.
|
|
7
|
+
|
|
8
|
+
# By L7z
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
___
|
package/index.js
ADDED
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const cheerio = require('cheerio')
|
|
3
|
+
const { createDecipheriv } = require('crypto')
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const FormData = require('form-data')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const { spawn } = require('child_process')
|
|
8
|
+
const YTDL = require('@distube/ytdl-core')
|
|
9
|
+
const ffmpeg = require('fluent-ffmpeg')
|
|
10
|
+
const randomKarakter = (length) => {
|
|
11
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
12
|
+
return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const FileSize = (path) => {
|
|
16
|
+
const bytes = fs.statSync(path).size
|
|
17
|
+
if (bytes >= 1073741824) return (bytes / 1073741824).toFixed(2) + ' GB'
|
|
18
|
+
if (bytes >= 1048576) return (bytes / 1048576).toFixed(2) + ' MB'
|
|
19
|
+
if (bytes >= 1024) return (bytes / 1024).toFixed(2) + ' KB'
|
|
20
|
+
return bytes + ' B'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function catbox(path) {
|
|
24
|
+
const data = new FormData()
|
|
25
|
+
data.append('reqtype', 'fileupload')
|
|
26
|
+
data.append('userhash', '')
|
|
27
|
+
data.append('fileToUpload', fs.createReadStream(path))
|
|
28
|
+
const config = {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
url: 'https://catbox.moe/user/api.php',
|
|
31
|
+
headers: {
|
|
32
|
+
...data.getHeaders(),
|
|
33
|
+
'User-Agent': 'Mozilla/5.0 (Android 10; Mobile; rv:131.0) Gecko/131.0 Firefox/131.0',
|
|
34
|
+
},
|
|
35
|
+
data: data
|
|
36
|
+
}
|
|
37
|
+
const api = await axios.request(config)
|
|
38
|
+
return api.data
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function uguu(path) {
|
|
42
|
+
try {
|
|
43
|
+
const form = new FormData()
|
|
44
|
+
form.append('files[]', fs.createReadStream(path))
|
|
45
|
+
|
|
46
|
+
const { data } = await axios.post('https://uguu.se/upload', form, {
|
|
47
|
+
headers: {
|
|
48
|
+
...form.getHeaders()
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return data.files[0].url
|
|
53
|
+
} catch (err) {
|
|
54
|
+
throw new Error(err.message)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function theoks(path) {
|
|
59
|
+
try {
|
|
60
|
+
let form = new FormData()
|
|
61
|
+
form.append('files[]', fs.createReadStream(path))
|
|
62
|
+
|
|
63
|
+
let { data } = await axios.post('https://pomf-api.theoks.net/upload.php', form, {
|
|
64
|
+
headers: form.getHeaders()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return data.files[0].url
|
|
68
|
+
} catch (err) {
|
|
69
|
+
throw new Error(err.message)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function litterbox(path) {
|
|
74
|
+
try {
|
|
75
|
+
let form = new FormData()
|
|
76
|
+
form.append('fileToUpload', fs.createReadStream(path))
|
|
77
|
+
form.append('reqtype', 'fileupload')
|
|
78
|
+
form.append('time', '24h')
|
|
79
|
+
|
|
80
|
+
let { data } = await axios.post('https://litterbox.catbox.moe/resources/internals/api.php', form, {
|
|
81
|
+
headers: {
|
|
82
|
+
...form.getHeaders()
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return data
|
|
87
|
+
} catch (err) {
|
|
88
|
+
throw new Error(err.message)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function cloudmini(path) {
|
|
93
|
+
try {
|
|
94
|
+
const file_buffer = fs.readFileSync(path)
|
|
95
|
+
const file_type = path.split('.').pop()
|
|
96
|
+
const file_name = path.split('/').pop()
|
|
97
|
+
const unique_id = randomKarakter(2) + (file_buffer.length + file_type + file_name).length
|
|
98
|
+
|
|
99
|
+
const form = new FormData()
|
|
100
|
+
form.append('file', fs.createReadStream(path), `${unique_id}.${file_type}`)
|
|
101
|
+
|
|
102
|
+
const response = await axios.post('https://files.cloudmini.net/upload', form, {
|
|
103
|
+
headers: { ...form.getHeaders() }
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const { filename } = response.data
|
|
107
|
+
return `https://files.cloudmini.net/download/${filename}`
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throw new Error(err.message)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function tempfiles(path) {
|
|
114
|
+
try {
|
|
115
|
+
const form = new FormData()
|
|
116
|
+
form.append('file', fs.createReadStream(path))
|
|
117
|
+
|
|
118
|
+
const { data } = await axios.post('https://tmpfiles.org/api/v1/upload', form, {
|
|
119
|
+
headers: {
|
|
120
|
+
...form.getHeaders()
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
return data.data.url
|
|
125
|
+
} catch (err) {
|
|
126
|
+
throw new Error(err.message)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const QualsVideo = ["144", "240", "360", "480", "720", "1080"]
|
|
131
|
+
const QualsAudio = ['32', '64', '128', '192', '256', '320']
|
|
132
|
+
|
|
133
|
+
const downloadFolder = '/home/container'
|
|
134
|
+
if (!fs.existsSync(downloadFolder)) fs.mkdirSync(downloadFolder)
|
|
135
|
+
|
|
136
|
+
async function ytdlv1(url, type, qual = null) {
|
|
137
|
+
let cookie
|
|
138
|
+
const match = cookie?.match(/Expires=([^;]+)/)
|
|
139
|
+
const date = match ? new Date(match[1]) : null
|
|
140
|
+
const now = new Date()
|
|
141
|
+
|
|
142
|
+
if (!cookie || (date && now > date)) {
|
|
143
|
+
const yt_page = await axios.get("https://www.youtube.com", { timeout: 5000 })
|
|
144
|
+
cookie = yt_page.headers['set-cookie']?.join('; ') || ''
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const config = { requestOptions: { headers: { Cookie: cookie } } }
|
|
148
|
+
const info = await YTDL.getInfo(url, config)
|
|
149
|
+
const video = info.videoDetails
|
|
150
|
+
const file_id = randomKarakter(8)
|
|
151
|
+
|
|
152
|
+
if (type === 'mp3') {
|
|
153
|
+
const file_path = `./${file_id}.mp3`
|
|
154
|
+
|
|
155
|
+
const stream = YTDL(url, {
|
|
156
|
+
filter: 'audioonly',
|
|
157
|
+
highWaterMark: 32 * 1024 * 1024,
|
|
158
|
+
requestOptions: { headers: { Cookie: cookie } }
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
const ffmpeg = spawn('ffmpeg', [
|
|
162
|
+
'-i', 'pipe:0',
|
|
163
|
+
'-b:a', `${qual}k`,
|
|
164
|
+
'-preset', 'ultrafast',
|
|
165
|
+
'-movflags', '+faststart',
|
|
166
|
+
file_path
|
|
167
|
+
])
|
|
168
|
+
|
|
169
|
+
stream.pipe(ffmpeg.stdin)
|
|
170
|
+
|
|
171
|
+
await new Promise((resolve, reject) => {
|
|
172
|
+
ffmpeg.on('close', resolve)
|
|
173
|
+
ffmpeg.on('error', reject)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const file_size = FileSize(file_path)
|
|
177
|
+
return {
|
|
178
|
+
audio: {
|
|
179
|
+
title: video.title,
|
|
180
|
+
duration: video.lengthSeconds,
|
|
181
|
+
views: video.viewCount,
|
|
182
|
+
likes: video.likes,
|
|
183
|
+
quality: qual + 'kbps',
|
|
184
|
+
description: video.description,
|
|
185
|
+
thumbnail: video.thumbnails.pop().url
|
|
186
|
+
},
|
|
187
|
+
channel: {
|
|
188
|
+
name: video.ownerChannelName,
|
|
189
|
+
subscriber: video.author.subscriber_count,
|
|
190
|
+
verified: video.author.verified,
|
|
191
|
+
url: video.author.channel_url
|
|
192
|
+
},
|
|
193
|
+
file_name: `${video.title}.mp3`,
|
|
194
|
+
file_size,
|
|
195
|
+
download: file_path
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const formats = info.formats.map(f => ({
|
|
200
|
+
itag: f.itag,
|
|
201
|
+
quality: f.qualityLabel || 'Audio',
|
|
202
|
+
hasAudio: !!f.audioBitrate,
|
|
203
|
+
url: f.url,
|
|
204
|
+
type: f.mimeType.split(';')[0]
|
|
205
|
+
}))
|
|
206
|
+
|
|
207
|
+
let format_video = formats.find(f => f.quality.includes(`${qual}p`) && !f.hasAudio) || formats.find(f => f.quality.includes('p') && !f.hasAudio)
|
|
208
|
+
let format_audio = formats.find(f => f.hasAudio)
|
|
209
|
+
|
|
210
|
+
if (!format_video || !format_audio) return { availableFormats: formats }
|
|
211
|
+
|
|
212
|
+
const video_path = `./${file_id}.mp4`
|
|
213
|
+
|
|
214
|
+
const video_stream = YTDL(url, {
|
|
215
|
+
quality: format_video.itag,
|
|
216
|
+
highWaterMark: 64 * 1024 * 1024,
|
|
217
|
+
requestOptions: { headers: { Cookie: cookie } }
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
const audio_stream = YTDL(url, {
|
|
221
|
+
quality: format_audio.itag,
|
|
222
|
+
highWaterMark: 32 * 1024 * 1024,
|
|
223
|
+
requestOptions: { headers: { Cookie: cookie } }
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const ffmpeg = spawn('ffmpeg', [
|
|
227
|
+
'-i', 'pipe:3',
|
|
228
|
+
'-i', 'pipe:4',
|
|
229
|
+
'-c:v', 'copy',
|
|
230
|
+
'-c:a', 'aac',
|
|
231
|
+
'-preset', 'ultrafast',
|
|
232
|
+
'-movflags', '+faststart',
|
|
233
|
+
video_path
|
|
234
|
+
], { stdio: ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'] })
|
|
235
|
+
|
|
236
|
+
video_stream.pipe(ffmpeg.stdio[3])
|
|
237
|
+
audio_stream.pipe(ffmpeg.stdio[4])
|
|
238
|
+
|
|
239
|
+
await new Promise((resolve, reject) => {
|
|
240
|
+
ffmpeg.on('close', resolve)
|
|
241
|
+
ffmpeg.on('error', reject)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
const file_size = FileSize(video_path)
|
|
245
|
+
return {
|
|
246
|
+
video: {
|
|
247
|
+
title: video.title,
|
|
248
|
+
duration: video.lengthSeconds,
|
|
249
|
+
views: video.viewCount,
|
|
250
|
+
likes: video.likes,
|
|
251
|
+
quality: format_video.quality,
|
|
252
|
+
description: video.description,
|
|
253
|
+
thumbnail: video.thumbnails.pop().url
|
|
254
|
+
},
|
|
255
|
+
channel: {
|
|
256
|
+
name: video.ownerChannelName,
|
|
257
|
+
subscriber: video.author.subscriber_count,
|
|
258
|
+
verified: video.author.verified,
|
|
259
|
+
url: video.author.channel_url
|
|
260
|
+
},
|
|
261
|
+
file_name: `${video.title}.mp4`,
|
|
262
|
+
file_size,
|
|
263
|
+
download: video_path
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function ytdlv2(url, type, quality) {
|
|
268
|
+
const api = {
|
|
269
|
+
base: 'https://media.savetube.me/api',
|
|
270
|
+
cdn: '/random-cdn',
|
|
271
|
+
info: '/v2/info',
|
|
272
|
+
download: '/download'
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const headers = {
|
|
276
|
+
accept: '*/*',
|
|
277
|
+
'content-type': 'application/json',
|
|
278
|
+
origin: 'https://yt.savetube.me',
|
|
279
|
+
referer: 'https://yt.savetube.me/',
|
|
280
|
+
'user-agent': 'Postify/1.0.0'
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const vid_quality = ['144', '240', '360', '480', '720', '1080']
|
|
284
|
+
const aud_quality = ['32', '64', '128', '192', '256', '320']
|
|
285
|
+
|
|
286
|
+
const hex_to_buf = (hex) => Buffer.from(hex, 'hex')
|
|
287
|
+
|
|
288
|
+
const decrypt = (enc) => {
|
|
289
|
+
try {
|
|
290
|
+
const secret_key = 'C5D58EF67A7584E4A29F6C35BBC4EB12'
|
|
291
|
+
const data = Buffer.from(enc, 'base64')
|
|
292
|
+
const iv = data.slice(0, 16)
|
|
293
|
+
const content = data.slice(16)
|
|
294
|
+
const key = hex_to_buf(secret_key)
|
|
295
|
+
|
|
296
|
+
const decipher = createDecipheriv('aes-128-cbc', key, iv)
|
|
297
|
+
let decrypted = Buffer.concat([decipher.update(content), decipher.final()])
|
|
298
|
+
|
|
299
|
+
return JSON.parse(decrypted.toString())
|
|
300
|
+
} catch (error) {
|
|
301
|
+
throw new Error(error.message)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const get_id = (url) => {
|
|
306
|
+
const regex = [
|
|
307
|
+
/youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/,
|
|
308
|
+
/youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
|
|
309
|
+
/youtube\.com\/v\/([a-zA-Z0-9_-]{11})/,
|
|
310
|
+
/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/,
|
|
311
|
+
/youtu\.be\/([a-zA-Z0-9_-]{11})/
|
|
312
|
+
]
|
|
313
|
+
for (let r of regex) {
|
|
314
|
+
let match = url.match(r)
|
|
315
|
+
if (match) return match[1]
|
|
316
|
+
}
|
|
317
|
+
return null
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const dl_file = (url, file_path) => {
|
|
321
|
+
return new Promise(async (resolve, reject) => {
|
|
322
|
+
try {
|
|
323
|
+
const response = await axios({
|
|
324
|
+
url,
|
|
325
|
+
method: 'GET',
|
|
326
|
+
responseType: 'stream'
|
|
327
|
+
})
|
|
328
|
+
const writer = fs.createWriteStream(file_path)
|
|
329
|
+
response.data.pipe(writer)
|
|
330
|
+
writer.on('finish', () => resolve(file_path))
|
|
331
|
+
writer.on('error', reject)
|
|
332
|
+
} catch (error) {
|
|
333
|
+
reject(error)
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const convert_audio = (input, output, bitrate) => {
|
|
339
|
+
return new Promise((resolve, reject) => {
|
|
340
|
+
const process = spawn('ffmpeg', [
|
|
341
|
+
'-i', 'pipe:0',
|
|
342
|
+
'-b:a', `${bitrate}k`,
|
|
343
|
+
'-preset', 'ultrafast',
|
|
344
|
+
'-movflags', '+faststart',
|
|
345
|
+
output
|
|
346
|
+
])
|
|
347
|
+
|
|
348
|
+
const readStream = fs.createReadStream(input)
|
|
349
|
+
readStream.pipe(process.stdin)
|
|
350
|
+
|
|
351
|
+
process.on('close', (code) => {
|
|
352
|
+
if (code === 0) resolve(output)
|
|
353
|
+
else reject(new Error('Error :('))
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const id = get_id(url)
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
const { data: cdn_res } = await axios.get(api.base+api.cdn, { headers })
|
|
362
|
+
const cdn = cdn_res.cdn
|
|
363
|
+
|
|
364
|
+
const { data: info_res } = await axios.post(`https://${cdn}${api.info}`, {
|
|
365
|
+
url: `https://www.youtube.com/watch?v=${id}`
|
|
366
|
+
}, { headers })
|
|
367
|
+
|
|
368
|
+
const decrypted = decrypt(info_res.data)
|
|
369
|
+
|
|
370
|
+
if (type === 'mp4') {
|
|
371
|
+
if (!vid_quality.includes(quality.toString())) quality = '360'
|
|
372
|
+
} else if (type === 'mp3') {
|
|
373
|
+
if (!aud_quality.includes(quality.toString())) quality = '192'
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const { data: dl_res } = await axios.post(`https://${cdn}${api.download}`, {
|
|
377
|
+
id,
|
|
378
|
+
downloadType: type === 'mp3' ? 'audio' : 'video',
|
|
379
|
+
quality,
|
|
380
|
+
key: decrypted.key
|
|
381
|
+
}, { headers })
|
|
382
|
+
|
|
383
|
+
const file_name = `${randomKarakter(4)}.${type}`
|
|
384
|
+
const file_path = './' + file_name
|
|
385
|
+
|
|
386
|
+
await dl_file(dl_res.data.downloadUrl, file_path)
|
|
387
|
+
|
|
388
|
+
if (type === 'mp3') {
|
|
389
|
+
const output_file = `./${randomKarakter(4)}.mp3`
|
|
390
|
+
await convert_audio(file_path, output_file, quality)
|
|
391
|
+
fs.unlinkSync(file_path)
|
|
392
|
+
return {
|
|
393
|
+
title: decrypted.title,
|
|
394
|
+
format: 'mp3',
|
|
395
|
+
quality: quality+'kbps',
|
|
396
|
+
duration: decrypted.duration,
|
|
397
|
+
thumbnail: decrypted.thumbnail || `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
|
|
398
|
+
file_name: decrypted.title+'.mp3',
|
|
399
|
+
file_size: FileSize(output_file),
|
|
400
|
+
download: output_file
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return {
|
|
405
|
+
title: decrypted.title,
|
|
406
|
+
format: 'mp4',
|
|
407
|
+
quality: quality+'p',
|
|
408
|
+
duration: decrypted.duration,
|
|
409
|
+
thumbnail: decrypted.thumbnail || `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
|
|
410
|
+
file_name: decrypted.title+'.mp4',
|
|
411
|
+
file_size: FileSize(file_path),
|
|
412
|
+
download: file_path
|
|
413
|
+
}
|
|
414
|
+
} catch (err) {
|
|
415
|
+
return { error: err.message }
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
async function getTokenFB() {
|
|
420
|
+
const { data: html } = await axios.get("https://fbdown.me/")
|
|
421
|
+
const $ = cheerio.load(html)
|
|
422
|
+
return $("#token").val()
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async function fbdl(url) {
|
|
426
|
+
try {
|
|
427
|
+
const token = await getTokenFB()
|
|
428
|
+
const formData = new FormData()
|
|
429
|
+
formData.append("url", url)
|
|
430
|
+
formData.append("token", token)
|
|
431
|
+
|
|
432
|
+
const { data } = await axios.post(
|
|
433
|
+
"https://fbdown.me/wp-json/aio-dl/video-data",
|
|
434
|
+
formData,
|
|
435
|
+
{ headers: { ...formData.getHeaders() } }
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
title: data.title,
|
|
440
|
+
thumbnail: data.thumbnail,
|
|
441
|
+
videos: data.medias.map(v => ({
|
|
442
|
+
url: v.url,
|
|
443
|
+
quality: v.quality,
|
|
444
|
+
size: v.formattedSize
|
|
445
|
+
}))
|
|
446
|
+
}
|
|
447
|
+
} catch (err) {
|
|
448
|
+
throw Error(err.message)
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function igdl(url) {
|
|
453
|
+
const { data } = await axios.post(
|
|
454
|
+
'https://yt1s.io/api/ajaxSearch',
|
|
455
|
+
new URLSearchParams({
|
|
456
|
+
p: 'home',
|
|
457
|
+
q: url,
|
|
458
|
+
w: '',
|
|
459
|
+
lang: 'en'
|
|
460
|
+
}),
|
|
461
|
+
{
|
|
462
|
+
headers: {
|
|
463
|
+
'User-Agent': 'Postify/1.0.0',
|
|
464
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
465
|
+
'Accept': 'application/json, text/plain, */*',
|
|
466
|
+
'Origin': 'https://yt1s.io',
|
|
467
|
+
'Referer': 'https://yt1s.io/'
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
const $ = cheerio.load(data.data)
|
|
473
|
+
|
|
474
|
+
return $('a.abutton.is-success.is-fullwidth.btn-premium')
|
|
475
|
+
.map((_, el) => ({
|
|
476
|
+
title: $(el).attr('title'),
|
|
477
|
+
url: $(el).attr('href')
|
|
478
|
+
}))
|
|
479
|
+
.get()
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function ttdl(url) {
|
|
483
|
+
return new Promise(async (resolve, reject) => {
|
|
484
|
+
try {
|
|
485
|
+
let data = []
|
|
486
|
+
|
|
487
|
+
function formatNumber(integer) {
|
|
488
|
+
let numb = parseInt(integer)
|
|
489
|
+
return Number(numb).toLocaleString().replace(/,/g, '.')
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function formatDate(n, locale = 'en') {
|
|
493
|
+
let d = new Date(n)
|
|
494
|
+
return d.toLocaleDateString(locale, {
|
|
495
|
+
weekday: 'long',
|
|
496
|
+
day: 'numeric',
|
|
497
|
+
month: 'long',
|
|
498
|
+
year: 'numeric',
|
|
499
|
+
hour: 'numeric',
|
|
500
|
+
minute: 'numeric',
|
|
501
|
+
second: 'numeric'
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
let domain = 'https://www.tikwm.com/api/'
|
|
506
|
+
let res = await (await axios.post(domain, {}, {
|
|
507
|
+
headers: {
|
|
508
|
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
|
509
|
+
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
510
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
511
|
+
'Origin': 'https://www.tikwm.com',
|
|
512
|
+
'Referer': 'https://www.tikwm.com/',
|
|
513
|
+
'Sec-Ch-Ua': '"Not)A;Brand" ;v="24" , "Chromium" ;v="116"',
|
|
514
|
+
'Sec-Ch-Ua-Mobile': '?1',
|
|
515
|
+
'Sec-Ch-Ua-Platform': 'Android',
|
|
516
|
+
'Sec-Fetch-Dest': 'empty',
|
|
517
|
+
'Sec-Fetch-Mode': 'cors',
|
|
518
|
+
'Sec-Fetch-Site': 'same-origin',
|
|
519
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36',
|
|
520
|
+
'X-Requested-With': 'XMLHttpRequest'
|
|
521
|
+
},
|
|
522
|
+
params: {
|
|
523
|
+
url: url,
|
|
524
|
+
count: 12,
|
|
525
|
+
cursor: 0,
|
|
526
|
+
web: 1,
|
|
527
|
+
hd: 1
|
|
528
|
+
}
|
|
529
|
+
})).data.data
|
|
530
|
+
if (!res.size) {
|
|
531
|
+
res.images.map(v => {
|
|
532
|
+
data.push({
|
|
533
|
+
type: 'photo',
|
|
534
|
+
url: v
|
|
535
|
+
})
|
|
536
|
+
})
|
|
537
|
+
} else {
|
|
538
|
+
data.push({
|
|
539
|
+
type: 'watermark',
|
|
540
|
+
url: 'https://www.tikwm.com' + res.wmplay,
|
|
541
|
+
}, {
|
|
542
|
+
type: 'nowatermark',
|
|
543
|
+
url: 'https://www.tikwm.com' + res.play,
|
|
544
|
+
}, {
|
|
545
|
+
type: 'nowatermark_hd',
|
|
546
|
+
url: 'https://www.tikwm.com' + res.hdplay
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
let json = {
|
|
550
|
+
title: res.title,
|
|
551
|
+
region: res.region,
|
|
552
|
+
durations: res.duration,
|
|
553
|
+
cover: 'https://www.tikwm.com' + res.cover,
|
|
554
|
+
size_wm: res.wm_size,
|
|
555
|
+
size_nowm: res.size,
|
|
556
|
+
size_nowm_hd: res.hd_size,
|
|
557
|
+
data: data,
|
|
558
|
+
music_info: {
|
|
559
|
+
id: res.music_info.id,
|
|
560
|
+
title: res.music_info.title,
|
|
561
|
+
author: res.music_info.author,
|
|
562
|
+
album: res.music_info.album ? res.music_info.album : null,
|
|
563
|
+
url: 'https://www.tikwm.com' + res.music || res.music_info.play
|
|
564
|
+
},
|
|
565
|
+
stats: {
|
|
566
|
+
views: formatNumber(res.play_count),
|
|
567
|
+
likes: formatNumber(res.digg_count),
|
|
568
|
+
comment: formatNumber(res.comment_count),
|
|
569
|
+
share: formatNumber(res.share_count),
|
|
570
|
+
download: formatNumber(res.download_count)
|
|
571
|
+
},
|
|
572
|
+
author: {
|
|
573
|
+
id: res.author.id,
|
|
574
|
+
fullname: res.author.unique_id,
|
|
575
|
+
nickname: res.author.nickname,
|
|
576
|
+
avatar: 'https://www.tikwm.com' + res.author.avatar
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
resolve(json)
|
|
580
|
+
} catch (e) {
|
|
581
|
+
reject(e)
|
|
582
|
+
}
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
async function ttslide(url) {
|
|
587
|
+
try {
|
|
588
|
+
const res = await axios({
|
|
589
|
+
method: 'POST',
|
|
590
|
+
url: 'https://tikvideo.app/api/ajaxSearch',
|
|
591
|
+
headers: {
|
|
592
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
593
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
|
594
|
+
},
|
|
595
|
+
data: new URLSearchParams({ q: url, lang: 'id' }).toString(),
|
|
596
|
+
})
|
|
597
|
+
|
|
598
|
+
const result = []
|
|
599
|
+
if (res.data.status === 'ok') {
|
|
600
|
+
const $ = cheerio.load(res.data.data)
|
|
601
|
+
$('img').each((index, element) => {
|
|
602
|
+
const imgSrc = $(element).attr('src')
|
|
603
|
+
if (imgSrc && !imgSrc.includes('.webp')) {
|
|
604
|
+
result.push(imgSrc)
|
|
605
|
+
}
|
|
606
|
+
})
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return result.length > 0 ? result : null
|
|
610
|
+
} catch (err) {
|
|
611
|
+
throw Error(err.message)
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
async function spotify(url) {
|
|
616
|
+
try {
|
|
617
|
+
const response = await axios.get(`https://api.siputzx.my.id/api/d/spotify?url=${encodeURIComponent(url)}`)
|
|
618
|
+
return {
|
|
619
|
+
title: response.data.data.title,
|
|
620
|
+
download: response.data.data.download,
|
|
621
|
+
image: response.data.data.image,
|
|
622
|
+
duration: response.data.data.durasi
|
|
623
|
+
}
|
|
624
|
+
} catch (err) {
|
|
625
|
+
console.error(err)
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
async function capcut(url) {
|
|
630
|
+
const BASE_URI = "https://snapsave.cc/wp-json/aio-dl/video-data"
|
|
631
|
+
const headers = {
|
|
632
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
|
633
|
+
'Accept': 'application/json, text/plain, */*',
|
|
634
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
635
|
+
'Content-Type': 'application/json;charset=UTF-8',
|
|
636
|
+
'Connection': 'keep-alive',
|
|
637
|
+
'Referer': 'https://snapsave.cc/capcut-video-downloader/',
|
|
638
|
+
'Origin': 'https://snapsave.cc',
|
|
639
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
640
|
+
'Cache-Control': 'no-cache',
|
|
641
|
+
'Pragma': 'no-cache',
|
|
642
|
+
'DNT': '1'
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
try {
|
|
646
|
+
const response = await axios.get(`https://snapsave.cc/capcut-video-downloader/#url=${encodeURIComponent(url)}`, { headers })
|
|
647
|
+
const $ = cheerio.load(response.data)
|
|
648
|
+
const token = $("#token").val()
|
|
649
|
+
|
|
650
|
+
const payload = {
|
|
651
|
+
url,
|
|
652
|
+
token,
|
|
653
|
+
hash: "aHR0cHM6Ly93d3cuY2FwY3V0LmNvbS9pZC1pZC90ZW1wbGF0ZS1kZXRhaWwvRm9yLXlvdS0vNzQxNDE2Mjk3MzU3ODU2MjgyMg==1073YWlvLWRs"
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const { data: videoData } = await axios.post(BASE_URI, payload, { headers })
|
|
657
|
+
|
|
658
|
+
return {
|
|
659
|
+
title: videoData.title,
|
|
660
|
+
thumbnail: videoData.thumbnail,
|
|
661
|
+
source: videoData.source,
|
|
662
|
+
media: videoData.medias.map((item) => ({
|
|
663
|
+
url: item.url,
|
|
664
|
+
quality: item.quality,
|
|
665
|
+
format: item.extension,
|
|
666
|
+
size: item.formattedSize
|
|
667
|
+
}))
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
} catch (err) {
|
|
671
|
+
throw Error(err.message)
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async function threads(url) {
|
|
676
|
+
try {
|
|
677
|
+
const { data } = await axios.get('https://threads.snapsave.app/api/action', {
|
|
678
|
+
params: { url: url },
|
|
679
|
+
headers: {
|
|
680
|
+
'accept': 'application/json, text/plain, */*',
|
|
681
|
+
'referer': 'https://threads.snapsave.app/',
|
|
682
|
+
'user-agent': 'Postify/1.0.0',
|
|
683
|
+
},
|
|
684
|
+
timeout: 10000,
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
const type = (type) => ({
|
|
688
|
+
GraphImage: 'Photo',
|
|
689
|
+
GraphVideo: 'Video',
|
|
690
|
+
GraphSidecar: 'Gallery',
|
|
691
|
+
}[type] || type)
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
postInfo: {
|
|
695
|
+
id: data.postinfo.id,
|
|
696
|
+
username: data.postinfo.username,
|
|
697
|
+
avatarUrl: data.postinfo.avatar_url,
|
|
698
|
+
mediaTitle: data.postinfo.media_title,
|
|
699
|
+
type: type(data.postinfo.__type),
|
|
700
|
+
},
|
|
701
|
+
media: data.items.map((item) => ({
|
|
702
|
+
type: type(item.__type),
|
|
703
|
+
id: item.id,
|
|
704
|
+
url: item.url,
|
|
705
|
+
width: item.width,
|
|
706
|
+
height: item.height,
|
|
707
|
+
...(item.__type === 'GraphVideo' && {
|
|
708
|
+
thumbnailUrl: item.display_url,
|
|
709
|
+
videoUrl: item.video_url,
|
|
710
|
+
duration: item.video_duration,
|
|
711
|
+
}),
|
|
712
|
+
})),
|
|
713
|
+
}
|
|
714
|
+
} catch (err) {
|
|
715
|
+
throw Error(err.message)
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
async function terabox(url) {
|
|
720
|
+
const terabox = {
|
|
721
|
+
api: {
|
|
722
|
+
base: "https://teraboxdl.site/api/",
|
|
723
|
+
token: "token",
|
|
724
|
+
terabox: "terabox"
|
|
725
|
+
},
|
|
726
|
+
headers: {
|
|
727
|
+
'authority': 'teraboxdl.site',
|
|
728
|
+
'user-agent': 'Postify/1.0.0'
|
|
729
|
+
},
|
|
730
|
+
token: null
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const getToken = async () => {
|
|
734
|
+
if (terabox.token) return terabox.token
|
|
735
|
+
|
|
736
|
+
try {
|
|
737
|
+
const { data } = await axios.get(`${terabox.api.base}${terabox.api.token}`, { headers: terabox.headers })
|
|
738
|
+
|
|
739
|
+
terabox.token = data.token
|
|
740
|
+
return terabox.token
|
|
741
|
+
|
|
742
|
+
} catch (err) {
|
|
743
|
+
throw Error(err.message)
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const isUrl = (url) => {
|
|
748
|
+
const match = url.match(/https?:\/\/(?:www\.)?(?:\w+)\.(com|app)\/s\/([^\/]+)/i)
|
|
749
|
+
return match ? `https://1024terabox.com/s/${match[2]}` : null
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
const request = async (endpoint, params = {}) => {
|
|
753
|
+
const token = await getToken()
|
|
754
|
+
const url = `${terabox.api.base}${endpoint}?` + new URLSearchParams(params)
|
|
755
|
+
|
|
756
|
+
try {
|
|
757
|
+
const { data } = await axios.get(url, { headers: { ...terabox.headers, 'x-access-token': token } })
|
|
758
|
+
const fileData = data.data.all_files[0]
|
|
759
|
+
|
|
760
|
+
return {
|
|
761
|
+
file_name: fileData.file_name,
|
|
762
|
+
file_id: fileData.fs_id,
|
|
763
|
+
size: fileData.size,
|
|
764
|
+
thumbnail: fileData.thumb,
|
|
765
|
+
download: fileData.download_url,
|
|
766
|
+
bytes: fileData.sizebytes
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
} catch (err) {
|
|
770
|
+
throw Error(err.message)
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const linkNya = isUrl(url.trim())
|
|
775
|
+
return await request(terabox.api.terabox, { url: linkNya })
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
async function gdrive(url) {
|
|
779
|
+
let id = (url.match(/\/?id=(.+)/i) || url.match(/\/d\/(.*?)\//))[1]
|
|
780
|
+
|
|
781
|
+
let { data } = await axios.post(`https://drive.google.com/uc?id=${id}&authuser=0&export=download`, null, {
|
|
782
|
+
headers: {
|
|
783
|
+
'accept-encoding': 'gzip, deflate, br',
|
|
784
|
+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
785
|
+
'origin': 'https://drive.google.com',
|
|
786
|
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
|
|
787
|
+
'x-client-data': 'CKG1yQEIkbbJAQiitskBCMS2yQEIqZ3KAQioo8oBGLeYygE=',
|
|
788
|
+
'x-drive-first-party': 'DriveWebUi',
|
|
789
|
+
'x-json-requested': 'true'
|
|
790
|
+
}
|
|
791
|
+
})
|
|
792
|
+
|
|
793
|
+
let { fileName, sizeBytes, downloadUrl } = JSON.parse(data.slice(4))
|
|
794
|
+
|
|
795
|
+
return {
|
|
796
|
+
download: downloadUrl,
|
|
797
|
+
fileName,
|
|
798
|
+
fileSize: `${(sizeBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
799
|
+
mimetype: (await axios.head(downloadUrl)).headers['content-type'],
|
|
800
|
+
extension: fileName.split('.').pop(),
|
|
801
|
+
modified: (await axios.head(downloadUrl)).headers['last-modified']
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
async function whatmusic(input) {
|
|
806
|
+
try {
|
|
807
|
+
let file_path = './sampah.mp3'
|
|
808
|
+
|
|
809
|
+
if (Buffer.isBuffer(input)) {
|
|
810
|
+
fs.writeFileSync(file_path, input)
|
|
811
|
+
} else if (typeof input === 'string') {
|
|
812
|
+
if (/^https?:\/\//.test(input)) {
|
|
813
|
+
let response = await axios.get(input, { responseType: 'arraybuffer' })
|
|
814
|
+
fs.writeFileSync(file_path, Buffer.from(response.data))
|
|
815
|
+
} else if (fs.existsSync(input)) {
|
|
816
|
+
file_path = input
|
|
817
|
+
}
|
|
818
|
+
} else {
|
|
819
|
+
throw Error('Harus berupa URL, file atau buffer!')
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
let outputna = './hasilnya.mp3'
|
|
823
|
+
|
|
824
|
+
return new Promise((resolve, reject) => {
|
|
825
|
+
ffmpeg(file_path)
|
|
826
|
+
.audioCodec('libmp3lame')
|
|
827
|
+
.saveToFile(outputna)
|
|
828
|
+
.on('error', (err) => {
|
|
829
|
+
fs.unlinkSync(file_path)
|
|
830
|
+
reject(err.message)
|
|
831
|
+
})
|
|
832
|
+
.on('end', async () => {
|
|
833
|
+
fs.unlinkSync(file_path)
|
|
834
|
+
let sample = fs.readFileSync(outputna)
|
|
835
|
+
|
|
836
|
+
acr.identify(sample).then((metadata) => {
|
|
837
|
+
fs.unlinkSync(outputna)
|
|
838
|
+
if (metadata.status.msg === 'No result') {
|
|
839
|
+
return reject('Nggak ketemu :(')
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
let song = metadata.metadata.music[0]
|
|
843
|
+
let spotify_data = song.external_metadata?.spotify
|
|
844
|
+
let youtube_id = song.external_metadata?.youtube?.vid || null
|
|
845
|
+
|
|
846
|
+
resolve({
|
|
847
|
+
title: song.title,
|
|
848
|
+
artists: song.artists.map(a => a.name).join(', '),
|
|
849
|
+
album: song.album.name,
|
|
850
|
+
release_date: song.release_date,
|
|
851
|
+
label: song.label,
|
|
852
|
+
duration: song.duration_ms,
|
|
853
|
+
spotify: spotify_data?.track?.id ? { name: song.title, url: `https://open.spotify.com/track/${spotify_data.track.id}` } : null,
|
|
854
|
+
youtube: youtube_id ? `https://www.youtube.com/watch?v=${youtube_id}` : null
|
|
855
|
+
})
|
|
856
|
+
}).catch((err) => reject(err.message))
|
|
857
|
+
})
|
|
858
|
+
})
|
|
859
|
+
} catch (err) {
|
|
860
|
+
throw Error(err.message)
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
module.exports = { catbox, uguu, theoks, litterbox, cloudmini, tempfiles, ytdlv1, ytdlv2, fbdl, igdl, ttdl, ttslide, spotify, capcut, threads, terabox, gdrive, whatmusic }
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zhg.sql",
|
|
3
|
+
"version": "1.4.5",
|
|
4
|
+
"description": "Modules Converter.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"No tests specified\" && exit 0"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"api",
|
|
11
|
+
"meta-api",
|
|
12
|
+
"file-uploader",
|
|
13
|
+
"downloader"
|
|
14
|
+
],
|
|
15
|
+
"author": "vourfly",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@distube/ytdl-core": "^4.16.4",
|
|
19
|
+
"axios": "^1.8.1",
|
|
20
|
+
"cheerio": "^1.0.0",
|
|
21
|
+
"form-data": "^4.0.2"
|
|
22
|
+
}
|
|
23
|
+
}
|