UNPKG

vourfly-search

Version:

Modules Downloader.

864 lines (756 loc) 25.6 kB
const axios = require('axios') const cheerio = require('cheerio') const { createDecipheriv } = require('crypto') const fs = require('fs') const FormData = require('form-data') const path = require('path') const { spawn } = require('child_process') const YTDL = require('@distube/ytdl-core') const ffmpeg = require('fluent-ffmpeg') const randomKarakter = (length) => { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('') } const FileSize = (path) => { const bytes = fs.statSync(path).size if (bytes >= 1073741824) return (bytes / 1073741824).toFixed(2) + ' GB' if (bytes >= 1048576) return (bytes / 1048576).toFixed(2) + ' MB' if (bytes >= 1024) return (bytes / 1024).toFixed(2) + ' KB' return bytes + ' B' } async function catbox(path) { const data = new FormData() data.append('reqtype', 'fileupload') data.append('userhash', '') data.append('fileToUpload', fs.createReadStream(path)) const config = { method: 'POST', url: 'https://catbox.moe/user/api.php', headers: { ...data.getHeaders(), 'User-Agent': 'Mozilla/5.0 (Android 10; Mobile; rv:131.0) Gecko/131.0 Firefox/131.0', }, data: data } const api = await axios.request(config) return api.data } async function uguu(path) { try { const form = new FormData() form.append('files[]', fs.createReadStream(path)) const { data } = await axios.post('https://uguu.se/upload', form, { headers: { ...form.getHeaders() } }) return data.files[0].url } catch (err) { throw new Error(err.message) } } async function theoks(path) { try { let form = new FormData() form.append('files[]', fs.createReadStream(path)) let { data } = await axios.post('https://pomf-api.theoks.net/upload.php', form, { headers: form.getHeaders() }) return data.files[0].url } catch (err) { throw new Error(err.message) } } async function litterbox(path) { try { let form = new FormData() form.append('fileToUpload', fs.createReadStream(path)) form.append('reqtype', 'fileupload') form.append('time', '24h') let { data } = await axios.post('https://litterbox.catbox.moe/resources/internals/api.php', form, { headers: { ...form.getHeaders() } }) return data } catch (err) { throw new Error(err.message) } } async function cloudmini(path) { try { const file_buffer = fs.readFileSync(path) const file_type = path.split('.').pop() const file_name = path.split('/').pop() const unique_id = randomKarakter(2) + (file_buffer.length + file_type + file_name).length const form = new FormData() form.append('file', fs.createReadStream(path), `${unique_id}.${file_type}`) const response = await axios.post('https://files.cloudmini.net/upload', form, { headers: { ...form.getHeaders() } }) const { filename } = response.data return `https://files.cloudmini.net/download/${filename}` } catch (err) { throw new Error(err.message) } } async function tempfiles(path) { try { const form = new FormData() form.append('file', fs.createReadStream(path)) const { data } = await axios.post('https://tmpfiles.org/api/v1/upload', form, { headers: { ...form.getHeaders() } }) return data.data.url } catch (err) { throw new Error(err.message) } } const QualsVideo = ["144", "240", "360", "480", "720", "1080"] const QualsAudio = ['32', '64', '128', '192', '256', '320'] const downloadFolder = '/home/container' if (!fs.existsSync(downloadFolder)) fs.mkdirSync(downloadFolder) async function ytdlv1(url, type, qual = null) { let cookie const match = cookie?.match(/Expires=([^;]+)/) const date = match ? new Date(match[1]) : null const now = new Date() if (!cookie || (date && now > date)) { const yt_page = await axios.get("https://www.youtube.com", { timeout: 5000 }) cookie = yt_page.headers['set-cookie']?.join('; ') || '' } const config = { requestOptions: { headers: { Cookie: cookie } } } const info = await YTDL.getInfo(url, config) const video = info.videoDetails const file_id = randomKarakter(8) if (type === 'mp3') { const file_path = `./${file_id}.mp3` const stream = YTDL(url, { filter: 'audioonly', highWaterMark: 32 * 1024 * 1024, requestOptions: { headers: { Cookie: cookie } } }) const ffmpeg = spawn('ffmpeg', [ '-i', 'pipe:0', '-b:a', `${qual}k`, '-preset', 'ultrafast', '-movflags', '+faststart', file_path ]) stream.pipe(ffmpeg.stdin) await new Promise((resolve, reject) => { ffmpeg.on('close', resolve) ffmpeg.on('error', reject) }) const file_size = FileSize(file_path) return { audio: { title: video.title, duration: video.lengthSeconds, views: video.viewCount, likes: video.likes, quality: qual + 'kbps', description: video.description, thumbnail: video.thumbnails.pop().url }, channel: { name: video.ownerChannelName, subscriber: video.author.subscriber_count, verified: video.author.verified, url: video.author.channel_url }, file_name: `${video.title}.mp3`, file_size, download: file_path } } const formats = info.formats.map(f => ({ itag: f.itag, quality: f.qualityLabel || 'Audio', hasAudio: !!f.audioBitrate, url: f.url, type: f.mimeType.split(';')[0] })) let format_video = formats.find(f => f.quality.includes(`${qual}p`) && !f.hasAudio) || formats.find(f => f.quality.includes('p') && !f.hasAudio) let format_audio = formats.find(f => f.hasAudio) if (!format_video || !format_audio) return { availableFormats: formats } const video_path = `./${file_id}.mp4` const video_stream = YTDL(url, { quality: format_video.itag, highWaterMark: 64 * 1024 * 1024, requestOptions: { headers: { Cookie: cookie } } }) const audio_stream = YTDL(url, { quality: format_audio.itag, highWaterMark: 32 * 1024 * 1024, requestOptions: { headers: { Cookie: cookie } } }) const ffmpeg = spawn('ffmpeg', [ '-i', 'pipe:3', '-i', 'pipe:4', '-c:v', 'copy', '-c:a', 'aac', '-preset', 'ultrafast', '-movflags', '+faststart', video_path ], { stdio: ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'] }) video_stream.pipe(ffmpeg.stdio[3]) audio_stream.pipe(ffmpeg.stdio[4]) await new Promise((resolve, reject) => { ffmpeg.on('close', resolve) ffmpeg.on('error', reject) }) const file_size = FileSize(video_path) return { video: { title: video.title, duration: video.lengthSeconds, views: video.viewCount, likes: video.likes, quality: format_video.quality, description: video.description, thumbnail: video.thumbnails.pop().url }, channel: { name: video.ownerChannelName, subscriber: video.author.subscriber_count, verified: video.author.verified, url: video.author.channel_url }, file_name: `${video.title}.mp4`, file_size, download: video_path } } async function ytdlv2(url, type, quality) { const api = { base: 'https://media.savetube.me/api', cdn: '/random-cdn', info: '/v2/info', download: '/download' } const headers = { accept: '*/*', 'content-type': 'application/json', origin: 'https://yt.savetube.me', referer: 'https://yt.savetube.me/', 'user-agent': 'Postify/1.0.0' } const vid_quality = ['144', '240', '360', '480', '720', '1080'] const aud_quality = ['32', '64', '128', '192', '256', '320'] const hex_to_buf = (hex) => Buffer.from(hex, 'hex') const decrypt = (enc) => { try { const secret_key = 'C5D58EF67A7584E4A29F6C35BBC4EB12' const data = Buffer.from(enc, 'base64') const iv = data.slice(0, 16) const content = data.slice(16) const key = hex_to_buf(secret_key) const decipher = createDecipheriv('aes-128-cbc', key, iv) let decrypted = Buffer.concat([decipher.update(content), decipher.final()]) return JSON.parse(decrypted.toString()) } catch (error) { throw new Error(error.message) } } const get_id = (url) => { const regex = [ /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 regex) { let match = url.match(r) if (match) return match[1] } return null } const dl_file = (url, file_path) => { return new Promise(async (resolve, reject) => { try { const response = await axios({ url, method: 'GET', responseType: 'stream' }) const writer = fs.createWriteStream(file_path) response.data.pipe(writer) writer.on('finish', () => resolve(file_path)) writer.on('error', reject) } catch (error) { reject(error) } }) } const convert_audio = (input, output, bitrate) => { return new Promise((resolve, reject) => { const process = spawn('ffmpeg', [ '-i', 'pipe:0', '-b:a', `${bitrate}k`, '-preset', 'ultrafast', '-movflags', '+faststart', output ]) const readStream = fs.createReadStream(input) readStream.pipe(process.stdin) process.on('close', (code) => { if (code === 0) resolve(output) else reject(new Error('Error :(')) }) }) } const id = get_id(url) try { const { data: cdn_res } = await axios.get(api.base+api.cdn, { headers }) const cdn = cdn_res.cdn const { data: info_res } = await axios.post(`https://${cdn}${api.info}`, { url: `https://www.youtube.com/watch?v=${id}` }, { headers }) const decrypted = decrypt(info_res.data) if (type === 'mp4') { if (!vid_quality.includes(quality.toString())) quality = '360' } else if (type === 'mp3') { if (!aud_quality.includes(quality.toString())) quality = '192' } const { data: dl_res } = await axios.post(`https://${cdn}${api.download}`, { id, downloadType: type === 'mp3' ? 'audio' : 'video', quality, key: decrypted.key }, { headers }) const file_name = `${randomKarakter(4)}.${type}` const file_path = './' + file_name await dl_file(dl_res.data.downloadUrl, file_path) if (type === 'mp3') { const output_file = `./${randomKarakter(4)}.mp3` await convert_audio(file_path, output_file, quality) fs.unlinkSync(file_path) return { title: decrypted.title, format: 'mp3', quality: quality+'kbps', duration: decrypted.duration, thumbnail: decrypted.thumbnail || `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`, file_name: decrypted.title+'.mp3', file_size: FileSize(output_file), download: output_file } } return { title: decrypted.title, format: 'mp4', quality: quality+'p', duration: decrypted.duration, thumbnail: decrypted.thumbnail || `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`, file_name: decrypted.title+'.mp4', file_size: FileSize(file_path), download: file_path } } catch (err) { return { error: err.message } } } async function getTokenFB() { const { data: html } = await axios.get("https://fbdown.me/") const $ = cheerio.load(html) return $("#token").val() } async function fbdl(url) { try { const token = await getTokenFB() const formData = new FormData() formData.append("url", url) formData.append("token", token) const { data } = await axios.post( "https://fbdown.me/wp-json/aio-dl/video-data", formData, { headers: { ...formData.getHeaders() } } ) return { title: data.title, thumbnail: data.thumbnail, videos: data.medias.map(v => ({ url: v.url, quality: v.quality, size: v.formattedSize })) } } catch (err) { throw Error(err.message) } } async function igdl(url) { const { data } = await axios.post( 'https://yt1s.io/api/ajaxSearch', new URLSearchParams({ p: 'home', q: url, w: '', lang: 'en' }), { headers: { 'User-Agent': 'Postify/1.0.0', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json, text/plain, */*', 'Origin': 'https://yt1s.io', 'Referer': 'https://yt1s.io/' } } ) const $ = cheerio.load(data.data) return $('a.abutton.is-success.is-fullwidth.btn-premium') .map((_, el) => ({ title: $(el).attr('title'), url: $(el).attr('href') })) .get() } async function ttdl(url) { return new Promise(async (resolve, reject) => { try { let data = [] function formatNumber(integer) { let numb = parseInt(integer) return Number(numb).toLocaleString().replace(/,/g, '.') } function formatDate(n, locale = 'en') { let d = new Date(n) return d.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' }) } let domain = 'https://www.tikwm.com/api/' let res = await (await axios.post(domain, {}, { headers: { 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Origin': 'https://www.tikwm.com', 'Referer': 'https://www.tikwm.com/', 'Sec-Ch-Ua': '"Not)A;Brand" ;v="24" , "Chromium" ;v="116"', 'Sec-Ch-Ua-Mobile': '?1', 'Sec-Ch-Ua-Platform': 'Android', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36', 'X-Requested-With': 'XMLHttpRequest' }, params: { url: url, count: 12, cursor: 0, web: 1, hd: 1 } })).data.data if (!res.size) { res.images.map(v => { data.push({ type: 'photo', url: v }) }) } else { data.push({ type: 'watermark', url: 'https://www.tikwm.com' + res.wmplay, }, { type: 'nowatermark', url: 'https://www.tikwm.com' + res.play, }, { type: 'nowatermark_hd', url: 'https://www.tikwm.com' + res.hdplay }) } let json = { title: res.title, region: res.region, durations: res.duration, cover: 'https://www.tikwm.com' + res.cover, size_wm: res.wm_size, size_nowm: res.size, size_nowm_hd: res.hd_size, data: data, music_info: { id: res.music_info.id, title: res.music_info.title, author: res.music_info.author, album: res.music_info.album ? res.music_info.album : null, url: 'https://www.tikwm.com' + res.music || res.music_info.play }, stats: { views: formatNumber(res.play_count), likes: formatNumber(res.digg_count), comment: formatNumber(res.comment_count), share: formatNumber(res.share_count), download: formatNumber(res.download_count) }, author: { id: res.author.id, fullname: res.author.unique_id, nickname: res.author.nickname, avatar: 'https://www.tikwm.com' + res.author.avatar } } resolve(json) } catch (e) { reject(e) } }) } async function ttslide(url) { try { const res = await axios({ method: 'POST', url: 'https://tikvideo.app/api/ajaxSearch', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', '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', }, data: new URLSearchParams({ q: url, lang: 'id' }).toString(), }) const result = [] if (res.data.status === 'ok') { const $ = cheerio.load(res.data.data) $('img').each((index, element) => { const imgSrc = $(element).attr('src') if (imgSrc && !imgSrc.includes('.webp')) { result.push(imgSrc) } }) } return result.length > 0 ? result : null } catch (err) { throw Error(err.message) } } async function spotify(url) { try { const response = await axios.get(`https://api.siputzx.my.id/api/d/spotify?url=${encodeURIComponent(url)}`) return { title: response.data.data.title, download: response.data.data.download, image: response.data.data.image, duration: response.data.data.durasi } } catch (err) { console.error(err) } } async function capcut(url) { const BASE_URI = "https://snapsave.cc/wp-json/aio-dl/video-data" const headers = { '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', 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'en-US,en;q=0.9', 'Content-Type': 'application/json;charset=UTF-8', 'Connection': 'keep-alive', 'Referer': 'https://snapsave.cc/capcut-video-downloader/', 'Origin': 'https://snapsave.cc', 'X-Requested-With': 'XMLHttpRequest', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'DNT': '1' } try { const response = await axios.get(`https://snapsave.cc/capcut-video-downloader/#url=${encodeURIComponent(url)}`, { headers }) const $ = cheerio.load(response.data) const token = $("#token").val() const payload = { url, token, hash: "aHR0cHM6Ly93d3cuY2FwY3V0LmNvbS9pZC1pZC90ZW1wbGF0ZS1kZXRhaWwvRm9yLXlvdS0vNzQxNDE2Mjk3MzU3ODU2MjgyMg==1073YWlvLWRs" } const { data: videoData } = await axios.post(BASE_URI, payload, { headers }) return { title: videoData.title, thumbnail: videoData.thumbnail, source: videoData.source, media: videoData.medias.map((item) => ({ url: item.url, quality: item.quality, format: item.extension, size: item.formattedSize })) } } catch (err) { throw Error(err.message) } } async function threads(url) { try { const { data } = await axios.get('https://threads.snapsave.app/api/action', { params: { url: url }, headers: { 'accept': 'application/json, text/plain, */*', 'referer': 'https://threads.snapsave.app/', 'user-agent': 'Postify/1.0.0', }, timeout: 10000, }) const type = (type) => ({ GraphImage: 'Photo', GraphVideo: 'Video', GraphSidecar: 'Gallery', }[type] || type) return { postInfo: { id: data.postinfo.id, username: data.postinfo.username, avatarUrl: data.postinfo.avatar_url, mediaTitle: data.postinfo.media_title, type: type(data.postinfo.__type), }, media: data.items.map((item) => ({ type: type(item.__type), id: item.id, url: item.url, width: item.width, height: item.height, ...(item.__type === 'GraphVideo' && { thumbnailUrl: item.display_url, videoUrl: item.video_url, duration: item.video_duration, }), })), } } catch (err) { throw Error(err.message) } } async function terabox(url) { const terabox = { api: { base: "https://teraboxdl.site/api/", token: "token", terabox: "terabox" }, headers: { 'authority': 'teraboxdl.site', 'user-agent': 'Postify/1.0.0' }, token: null } const getToken = async () => { if (terabox.token) return terabox.token try { const { data } = await axios.get(`${terabox.api.base}${terabox.api.token}`, { headers: terabox.headers }) terabox.token = data.token return terabox.token } catch (err) { throw Error(err.message) } } const isUrl = (url) => { const match = url.match(/https?:\/\/(?:www\.)?(?:\w+)\.(com|app)\/s\/([^\/]+)/i) return match ? `https://1024terabox.com/s/${match[2]}` : null } const request = async (endpoint, params = {}) => { const token = await getToken() const url = `${terabox.api.base}${endpoint}?` + new URLSearchParams(params) try { const { data } = await axios.get(url, { headers: { ...terabox.headers, 'x-access-token': token } }) const fileData = data.data.all_files[0] return { file_name: fileData.file_name, file_id: fileData.fs_id, size: fileData.size, thumbnail: fileData.thumb, download: fileData.download_url, bytes: fileData.sizebytes } } catch (err) { throw Error(err.message) } } const linkNya = isUrl(url.trim()) return await request(terabox.api.terabox, { url: linkNya }) } async function gdrive(url) { let id = (url.match(/\/?id=(.+)/i) || url.match(/\/d\/(.*?)\//))[1] let { data } = await axios.post(`https://drive.google.com/uc?id=${id}&authuser=0&export=download`, null, { headers: { 'accept-encoding': 'gzip, deflate, br', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'origin': 'https://drive.google.com', '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', 'x-client-data': 'CKG1yQEIkbbJAQiitskBCMS2yQEIqZ3KAQioo8oBGLeYygE=', 'x-drive-first-party': 'DriveWebUi', 'x-json-requested': 'true' } }) let { fileName, sizeBytes, downloadUrl } = JSON.parse(data.slice(4)) return { download: downloadUrl, fileName, fileSize: `${(sizeBytes / (1024 * 1024)).toFixed(2)} MB`, mimetype: (await axios.head(downloadUrl)).headers['content-type'], extension: fileName.split('.').pop(), modified: (await axios.head(downloadUrl)).headers['last-modified'] } } async function whatmusic(input) { try { let file_path = './sampah.mp3' if (Buffer.isBuffer(input)) { fs.writeFileSync(file_path, input) } else if (typeof input === 'string') { if (/^https?:\/\//.test(input)) { let response = await axios.get(input, { responseType: 'arraybuffer' }) fs.writeFileSync(file_path, Buffer.from(response.data)) } else if (fs.existsSync(input)) { file_path = input } } else { throw Error('Harus berupa URL, file atau buffer!') } let outputna = './hasilnya.mp3' return new Promise((resolve, reject) => { ffmpeg(file_path) .audioCodec('libmp3lame') .saveToFile(outputna) .on('error', (err) => { fs.unlinkSync(file_path) reject(err.message) }) .on('end', async () => { fs.unlinkSync(file_path) let sample = fs.readFileSync(outputna) acr.identify(sample).then((metadata) => { fs.unlinkSync(outputna) if (metadata.status.msg === 'No result') { return reject('Nggak ketemu :(') } let song = metadata.metadata.music[0] let spotify_data = song.external_metadata?.spotify let youtube_id = song.external_metadata?.youtube?.vid || null resolve({ title: song.title, artists: song.artists.map(a => a.name).join(', '), album: song.album.name, release_date: song.release_date, label: song.label, duration: song.duration_ms, spotify: spotify_data?.track?.id ? { name: song.title, url: `https://open.spotify.com/track/${spotify_data.track.id}` } : null, youtube: youtube_id ? `https://www.youtube.com/watch?v=${youtube_id}` : null }) }).catch((err) => reject(err.message)) }) }) } catch (err) { throw Error(err.message) } } module.exports = { catbox, uguu, theoks, litterbox, cloudmini, tempfiles, ytdlv1, ytdlv2, fbdl, igdl, ttdl, ttslide, spotify, capcut, threads, terabox, gdrive, whatmusic }