| const yts = require('yt-search'); |
| const morgan = require('morgan'); |
| const express = require('express'); |
| const ytdl = require('ytdl-core'); |
| const { Writable, pipeline } = require('stream'); |
| const util = require('util'); |
| const axios = require('axios'); |
| const FormData = require('form-data') |
| const cheerio = require('cheerio') |
| const cloudscraper = require('cloudscraper') |
| const { File } = require('megajs') |
| let fetch; |
|
|
| (async () => { |
| fetch = (await import('node-fetch')).default; |
| })(); |
|
|
| |
| const ytIdRegex = /(?:http(?:s|):\/\/|)(?:(?:www\.|)?youtube(?:\-nocookie|)\.com\/(?:shorts\/)?(?:watch\?.*(?:|\&)v=|embed\/|v\/)?|youtu\.be\/)([-_0-9A-Za-z]{11})/; |
|
|
| |
| const post = async (url, form, headers = {}) => { |
| const response = await fetch(url, { |
| method: 'post', |
| body: new URLSearchParams(form), |
| headers |
| }); |
| return response; |
| }; |
|
|
|
|
| |
| async function mediafire(url) { |
| return new Promise(async(resolve, reject) => { |
| var a, b; |
| if (!/https?:\/\/(www\.)?mediafire\.com/.test(url)) return resolve() |
| const data = await axios.get(url).catch(function (error) {}) |
| if (!data) { |
| resolve() |
| } else { |
| const $ = cheerio.load(data.data); |
| const Url = ($('#downloadButton').attr('href') || '').trim(); |
| const url2 = ($('#download_link > a.retry').attr('href') || '').trim(); |
| const $intro = $('div.dl-info > div.intro'); |
| const filename = $intro.find('div.filename').text().trim(); |
| const filetype = $intro.find('div.filetype > span').eq(0).text().trim(); |
| const ext = ((b = (a = /\(\.(.*?)\)/.exec($intro.find('div.filetype > span').eq(1).text())) === null || a === void 0 ? void 0 : a[1]) === null || b === void 0 ? void 0 : b.trim()) || 'bin'; |
| const $li = $('div.dl-info > ul.details > li'); |
| const aploud = $li.eq(1).find('span').text().trim(); |
| const filesize = $li.eq(0).find('span').text().trim(); |
| const filesizeB = (0, formatSize)(filesize); |
| const result = { |
| url: Url || url2, |
| url2, |
| filename, |
| filetype, |
| ext, |
| upload_date: aploud, |
| filesize, |
| filesizeB |
| }; |
| resolve(result) |
| } |
| }) |
| } |
|
|
|
|
| |
| async function igdl(query) { |
| url_dl = []; |
| let headers = { |
| 'Accept': '*/*', |
| 'Accept-Language': 'en-US,en;q=0.9', |
| 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', |
| 'Referer': 'https://saveig.app/', |
| 'Referrer-Policy': 'strict-origin-when-cross-origin', |
| 'X-Requested-With': 'XMLHttpRequest' |
| } |
| let options = { |
| method: 'POST', |
| uri: 'https://saveig.app/api/ajaxSearch', |
| headers: headers, |
| formData: { |
| q: query |
| } |
| } |
| ch = cheerio.load(JSON.parse(await cloudscraper(options)).data); |
| ch('.download-items__btn').each(function(a,b) { url_dl.push(ch(b).find('a').attr('href'))}) |
| return url_dl; |
| } |
|
|
| |
| async function fby2mate(url) { |
| try { |
| let form = new FormData() |
| form.append('q', url) |
| form.append('vt', 'facebook') |
| let data = await fetch(`https://y2mate.mx/api/ajaxSearch/facebook`, { |
| method: 'POST', |
| body: form, |
| headers: { |
| ...form.getHeaders() |
| } |
| }) |
| data = await data.json() |
| return data |
| } catch (e) { |
| return e |
| } |
| } |
|
|
| |
| async function uploadBuffer(buffer) { |
| return new Promise(async (resolve, reject) => { |
| let res = await axios.post('https://ilhamdev-up.hf.space/upload', { |
| file: buffer.toString('base64'), |
| headers: { |
| 'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0" |
| } |
| }).catch(e => reject(e)) |
| if (res.status !== 200) { |
| resolve(res?.statusText) |
| } else { |
| resolve(res?.data?.url) |
| } |
| }) |
| } |
| async function streamToBuffer(stream) { |
| const chunks = []; |
| const captureChunks = new Writable({ |
| write(chunk, encoding, callback) { |
| chunks.push(chunk); |
| callback(); |
| } |
| }); |
| |
| await util.promisify(pipeline)(stream, captureChunks); |
|
|
| return Buffer.concat(chunks); |
| } |
| function formatViews(viewCount) { |
| if (viewCount >= 1000000000) { |
| return (viewCount / 1000000000).toFixed(1) + 'B'; |
| } else if (viewCount >= 1000000) { |
| return (viewCount / 1000000).toFixed(1) + 'M'; |
| } else { |
| return viewCount >= 1000 |
| ? (viewCount / 1000).toFixed(1) + 'K' |
| : viewCount.toString(); |
| } |
| } |
|
|
| function formatDuration(durationInSeconds) { |
| const hours = Math.floor(durationInSeconds / 3600); |
| const minutes = Math.floor((durationInSeconds % 3600) / 60); |
| const seconds = durationInSeconds % 60; |
|
|
| return hours > 0 |
| ? hours + |
| ':' + |
| minutes.toString().padStart(2, '0') + |
| ':' + |
| seconds.toString().padStart(2, '0') |
| : minutes + ':' + seconds.toString().padStart(2, '0'); |
| } |
|
|
| function formatSize(bytes, si = false, dp = 2) { |
| const thresh = si ? 1000 : 1024; |
|
|
| if (Math.abs(bytes) < thresh) { |
| return `${bytes} B`; |
| } |
|
|
| const units = si |
| ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] |
| : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; |
| let u = -1; |
| const r = 10 ** dp; |
|
|
| do { |
| bytes /= thresh; |
| ++u; |
| } while ( |
| Math.round(Math.abs(bytes) * r) / r >= thresh && |
| u < units.length - 1 |
| ); |
|
|
| return `${bytes.toFixed(dp)} ${units[u]}`; |
| } |
|
|
| async function ytmp4(url, quality = 'highestvideo') { |
| try { |
| const ID = ytdl.getVideoID(url), |
| data = await ytdl.getInfo('https://www.youtube.com/watch?v=' + ID) |
| const videoStream = await ytdl(ID, { filter: 'videoandaudio', quality: 'highestvideo' }); |
| let buffer = await streamToBuffer(videoStream) |
| let upload = await uploadBuffer(buffer) |
| let format = ytdl.chooseFormat(data.formats, { filter: 'videoandaudio', quality: quality }); |
|
|
| if (format) { |
| return { |
| title: data.videoDetails.title, |
| description: data.videoDetails.description, |
| channel: data.videoDetails.ownerChannelName, |
| views: formatViews(data.videoDetails.viewCount), |
| publish: data.videoDetails.publishDate, |
| duration: formatDuration(data.videoDetails.lengthSeconds), |
| size: format.contentLength ? formatSize(format.contentLength) : 0, |
| quality: format.qualityLabel, |
| thumb: data.videoDetails.thumbnails[0].url, |
| dl_url: format.url, |
| url_v2: upload, |
| } |
| } else { |
| throw new Error('No suitable format found'); |
| } |
| } catch (error) { |
| console.error('Error occurred:', error); |
| return null; |
| } |
| } |
| async function ytmp3(url, bitrate = 'lowestaudio') { |
| try { |
| const ID = ytdl.getVideoID(url), |
| data = await ytdl.getInfo('https://www.youtube.com/watch?v=' + ID) |
| let audioStream = await ytdl(ID, { filter: 'audioonly', quality: 'lowestaudio', }); |
| let buffer = await streamToBuffer(audioStream) |
| let upload = await uploadBuffer(buffer) |
| let format = ytdl.chooseFormat(data.formats, { filter: 'audioonly', quality: bitrate }); |
|
|
| if (format) { |
| return { |
| title: data.videoDetails.title, |
| description: data.videoDetails.description, |
| channel: data.videoDetails.ownerChannelName, |
| views: formatViews(data.videoDetails.viewCount), |
| publish: data.videoDetails.publishDate, |
| duration: formatDuration(data.videoDetails.lengthSeconds), |
| size: format.contentLength ? formatSize(format.contentLength) : 0, |
| quality: format.audioQuality, |
| thumb: data.videoDetails.thumbnails[0].url, |
| dl_url: format.url, |
| url_v2: upload |
| } |
| } else { |
| throw new Error('No suitable format found'); |
| } |
| } catch (error) { |
| console.error('Error occurred:', error); |
| return null; |
| } |
| } |
|
|
| |
| const convert = async (url, v_id, ftype, fquality, fname, token, timeExpire) => { |
| let params = { |
| v_id, |
| ftype, |
| fquality, |
| fname, |
| token, |
| timeExpire, |
| client: 'yt5s.com' |
| }; |
|
|
| |
| let resServer = await (await post(url, params, { 'x-requested-key': 'de0cfuirtgf67a' })).json(); |
| let server = resServer.c_server; |
|
|
| |
| if (!server && ftype === 'mp3') return server || resServer.d_url || ''; |
|
|
| |
| let data = await (await post(`${server}/api/json/convert`, params)).json(); |
| let result; |
|
|
| |
| if (data.statusCode === 200) result = data.result; |
| while (!result) { |
| let json = await (await post(`${server}/api/json/convert`, params)).json(); |
| if (json.statusCode === 200) { |
| result = json.result; |
| break; |
| } |
| await new Promise(resolve => setTimeout(resolve, 2000)); |
| } |
| return result; |
| }; |
|
|
| |
| const youtubedl = async (url) => { |
| let html = await (await fetch('https://yt5s.com/en32')).text(); |
| let urlAjax = (html.match(/k_url_search="(.*?)"/) || [])[1]; |
| let urlConvert = (html.match(/k_url_convert="(.*?)"/) || [])[1]; |
| let json = await (await post(urlAjax, { q: url, vt: 'home' })).json(); |
| let video = {}, audio = {}; |
| if (!json?.links) throw json.mess; |
| Object.values(json.links.mp4).map(({ k, size }) => video[k] = { |
| quality: k, |
| fileSizeH: size, |
| fileSize: parseFloat(size) * (/MB$/.test(size) ? 1000 : 1), |
| download: convert.bind(null, urlConvert, json.vid, 'mp4', k, json.fn, json.token, parseInt(json.timeExpires)) |
| }); |
|
|
| Object.values(json.links.mp3).map(({ key, size }) => audio[key] = { |
| quality: key, |
| fileSizeH: size, |
| fileSize: parseFloat(size) * (/MB$/.test(size) ? 1000 : 1), |
| download: convert.bind(null, urlConvert, json.vid, 'mp3', key.replace(/kbps/i, ''), json.fn, json.token, parseInt(json.timeExpires)) |
| }); |
|
|
| return { |
| id: json.vid, |
| title: json.title, |
| thumbnail: `https://i.ytimg.com/vi/${json.vid}/0.jpg`, |
| video, |
| audio |
| }; |
| }; |
|
|
| |
| async function twitterDL(url) { |
| try { |
| let form = new FormData(); |
| form.append('q', url); |
| form.append('lang', 'en'); |
|
|
| let response = await fetch('https://x2twitter.com/api/ajaxSearch', { |
| method: 'POST', |
| body: form, |
| headers: form.getHeaders() |
| }); |
|
|
| let data = await response.json(); |
|
|
| const $ = cheerio.load(data?.data); |
| const downloads = []; |
| $('.dl-action a').each((index, element) => { |
| const format = $(element).text().trim(); |
| const url = $(element).attr('href'); |
| downloads.push({ format, url }); |
| }); |
|
|
| const convertToMP3 = { |
| url: $('.tw-middle a').attr('href') |
| }; |
|
|
| const result = { |
| downloads, |
| convert_to_mp3: convertToMP3 |
| }; |
|
|
| const hrefArray = []; |
|
|
| $('a').each((index, element) => { |
| const href = $(element).attr('href'); |
| if (href && href !== '/' && href !== '#') { |
| hrefArray.push(href); |
| } |
| }); |
|
|
| return { result, hrefArray }; |
| } catch (error) { |
| return error; |
| } |
| } |
|
|
| const app = express(); |
| app.set('json spaces', 4); |
| app.use(morgan('dev')); |
| app.use(express.json()); |
|
|
| app.all('/', (req, res) => { |
| const host = 'https://' + req.get('host'); |
| res.json({ |
| "List": [ |
| { |
| "title": "Tiktok Downloader", |
| "method": "GET", |
| "example": `${host}/tt?url=` |
| }, |
| { |
| "title": "Facebook Downloader", |
| "method": "GET", |
| "example": `${host}/fb?url=` |
| }, |
| { |
| "title": "Instagram Downloader", |
| "method": "GET", |
| "example": `${host}/ig?url=` |
| }, |
| { |
| "title": "Youtube Downloader", |
| "method": "GET", |
| "example": `${host}/ytdl?url=` |
| }, |
| { |
| "title": "Youtube Search", |
| "method": "GET", |
| "example": `${host}/ytsearch?q=` |
| }, |
| { |
| "title": "Pinterest Downloader", |
| "method": "GET", |
| "example": `${host}/pindl?url=` |
| }, |
| { |
| "title": "Mediafire Downloader", |
| "method": "GET", |
| "example": `${host}/mediafire?url=` |
| }, |
| { |
| "title": "Mega Downloader", |
| "method": "GET", |
| "example": `${host}/mega?url=`+ '${encodeURIComponent(${url})}', |
| }, |
| { |
| "title": "Twitter/X Downloader", |
| "method": "GET", |
| "example": `${host}/twitter?url=`, |
| } |
| ] |
| }); |
| }); |
| app.get('/yt', async (req, res) => { |
| const host = 'https://' + req.get('host'); |
| try { |
| let { url, type, quality, json } = req.query; |
| if (!ytIdRegex.test(url)) return res.json({ message: 'Invalid URL' }); |
| if (!!json) { |
| let ytId = ytIdRegex.exec(url)?.[1]; |
| if (!ytId) return res.json({ message: 'No video id found' }); |
| let data = await yts({ videoId: ytId }); |
| const downloadUrls = { |
| audio: `${host}/yt?url=${url}&type=audio&quality=128kbps`, |
| video: `${host}/yt?url=${url}&type=video&quality=`, |
| }; |
| return res.json({ |
| ...data, |
| download: downloadUrls |
| }); |
| } |
| if (!type || !/audio|video/i.test(type)) type = 'video'; |
| let data = await youtubedl(url).catch(e => console.log(e)); |
| if (!data) return res.json({ message: 'Error: link download not found' }); |
| type = type.toLowerCase(); |
| let result = quality ? Object.values(data[type]).find(x => x.quality == quality) : Object.values(data[type])[0]; |
| if (quality && !result) return res.json({ message: `Invalid quality: ${quality}, available quality (${Object.keys(data[type]).join('/')})` }); |
| if (!result) return res.json({ message: 'Error: can\'t download' }); |
| res.redirect(await result.download()); |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/ig', async (req,res) => { |
| try { |
| let {url} = req.query |
| let regex = /https?:\/\/(www\.)?instagram\.com\/(p|reel|tv)/; |
| if (!regex.test(url)) return res.json({ message: 'Invalid URL' }); |
| let data = await igdl(url) |
| return res.json(data) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/tt', async (req, res) => { |
| try { |
| let { url } = req.query |
| let regex = /https?:\/\/(www\.|v(t|m|vt)\.|t\.)?tiktok\.com/; |
| if (!regex.test(url)) return res.json({ message: 'Invalid URL' }); |
| let data = await fetch(`https://tikwm.com/api/?url=` + url) |
| data = await data.json() |
| if (!data) return res.json({ message: 'API TO API KOID:v' }); |
| return res.json(data) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/pindl', async (req, res) => { |
| try { |
| let { url } = req.query |
| let regex = /https:\/\/pin\.it\/\w+|https:\/\/[a-z]{2}\.pinterest\.com\/pin\/\d+/; |
| if (!regex.test(url)) return res.json({ message: 'Invalid URL' }); |
| let data = await fetch(`https://pinterestdownloader.io/id/frontendService/DownloaderService?url=` + url) |
| data = await data.json() |
| if (!data) return res.json({ message: 'API TO API KOID:v' }); |
| return res.json(data) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/fb', async (req, res) => { |
| try { |
| let {url} = req.query |
| let regex = /https?:\/\/(fb\.watch|(www\.|web\.|m\.)?facebook\.com)/; |
| if (!regex.test(url)) return res.json({ message: 'Invalid URL' }); |
| let data = await fby2mate(url) |
| return res.json(data) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/ytsearch', async (req, res) => { |
| try { |
| let q = req.query.q || req.query.query; |
| if (!q) return res.json({ message: 'Input parameter q' }); |
| let data = await yts(q); |
| if (!data.all[0]) return res.json({ message: 'Not found' }); |
| return res.json(data.all); |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/mediafire', async (req, res) => { |
| try { |
| let { url } = req.query |
| |
| if (!/https?:\/\/(www\.)?mediafire\.com\/(file|download)/i.test(url)) { |
| return res.json({ message: 'Invalid URL' }); |
| } |
| let data = await mediafire(url) |
| return res.json(data) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/ytdl', async (req, res) => { |
| try { |
| let { url } = req.query |
| if (!ytIdRegex.test(url)) return res.json({ message: 'Invalid URL' }); |
| let video = await ytmp4(url) |
| let audio = await ytmp3(url) |
| return res.json({ |
| video: video, |
| audio: audio |
| }) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.get('/twitter', async (req, res) => { |
| try { |
| let { url } = req.query; |
| url = url.replace('x.com', 'twitter.com'); |
| if (!/https?:\/\/(www\.)?(twitter|x)\.com\/.*\/status/.test(url)) { |
| return res.json({ message: 'Invalid URL' }); |
| } |
| let data = await twitterDL(url); |
| return res.json(data); |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
|
|
| app.get('/mega', async (req, res) => { |
| try { |
| let { url } = req.query; |
| if (!/https:\/\/mega\.nz\/file\/[a-zA-Z0-9]{8}#[a-zA-Z0-9-_]{43}/.test(url)) { |
| return res.json({ message: 'Invalid URL' }); |
| } |
| const file = File.fromURL(url); |
| await file.loadAttributes(); |
| let data = await file.downloadBuffer(); |
| return res.json({ |
| title: file.name, |
| size: formatSize(file.size), |
| base64: data.toString('base64') |
| }) |
| } catch (e) { |
| console.log(e); |
| return res.json({ message: e.message }); |
| } |
| }); |
| app.listen(7860, () => console.log('App running on port 7860')); |