Nexchan's picture
Update index.js
8bb3cd6 verified
raw
history blame
19.2 kB
import axios from 'axios';
import cheerio from 'cheerio';
import { createRequire } from 'module';
import os from 'os';
import express from 'express';
import { promisify } from 'util';
import { fileTypeFromBuffer } from 'file-type';
import ffmpeg from 'fluent-ffmpeg';
import nodeID3 from 'node-id3';
import ytdl from 'ytdl-core';
import FormData from 'form-data';
const require = createRequire(import.meta.url);
const fs = require('fs');
const path = require('path');
const { google } = require('googleapis');
const PORT = process.env.PORT || 7860;
const app = express();
const readFileAsync = promisify(fs.readFile);
import fetch from 'node-fetch';
const tempDir = path.join(os.tmpdir(), "temp");
const fss = fs.promises;
(async () => {
if (!fs.existsSync(tempDir)) {
await fss.mkdir(tempDir, { recursive: true });
}
})();
const youtube = google.youtube({ version: 'v3', auth: 'AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg' });
app.use('/temp', express.static(tempDir));
app.use(express.json());
app.get("/", (req, res) => {
res.type("json");
const keluaran = {
success: true,
author: "Nex",
data: {
igdl: "/igdl",
twdl: "/twdl"
},
};
res.send(keluaran);
});
const generateRandomIP = () => {
const octet = () => Math.floor(Math.random() * 256);
return `${octet()}.${octet()}.${octet()}.${octet()}`;
};
async function igdl1(url) {
const apiEndpoint = 'https://v3.igdownloader.app/api/ajaxSearch';
const requestOptions = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;]',
'Referer': 'https://igdownloader.app/en',
'X-Forwarded-For': generateRandomIP()
},
};
const postData = `recaptchaToken=&q=${encodeURIComponent(url)}&t=media&lang=en`;
try {
const response = await axios.post(apiEndpoint, postData, requestOptions);
const $ = cheerio.load(response.data.data);
const downloadLinks = $('div.download-items__btn > a');
return await Promise.all(downloadLinks.map(async (index, element) => $(element).attr('href')));
} catch (error) {
console.error('Instagram Downloader 1 - Error:', error.message);
return null;
}
}
async function igdl2(url) {
try {
const response = await axios.post('https://fastdl.app/c/', {
url: url,
lang_code: 'en',
token: ''
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
'Referer': 'https://fastdl.app/'
},
responseType: 'arraybuffer'
});
const html = response.data.toString('utf-8');
const $ = cheerio.load(html);
$('img').remove();
const links = [];
$('a').each((index, element) => links.push($(element).attr('href')));
return links;
} catch (error) {
console.error('Error downloading Instagram post:', error);
return null;
}
}
async function igdl3(url) {
const apiEndpoint = 'https://co.wuk.sh/api/json';
const requestData = { url, aFormat: 'mp3', filenamePattern: 'classic', dubLang: false, vQuality: '720' };
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
'Referer': 'https://cobalt.tools/',
};
try {
const response = await axios.post(apiEndpoint, requestData, { headers });
const array_res = [];
if (response.data.status === 'redirect') {
array_res.push(response.data.url);
} else if (response.data.status === 'picker') {
response.data.picker.forEach(item => array_res.push(item.url));
}
return array_res;
} catch (error) {
console.error('Instagram Downloader 3 - Error:', error.message);
return null;
}
}
async function igdl4(url) {
try {
const apiEndpoint = 'https://v3.saveig.app/api/ajaxSearch';
const requestOptions = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;]',
'Referer': 'https://saveig.app/en',
},
};
const postData = `recaptchaToken=&q=${encodeURIComponent(url)}&t=media&lang=en`;
const response = await axios.post(apiEndpoint, postData, requestOptions);
const $ = cheerio.load(response.data.data);
const downloadLinks = $('div.download-items__btn > a');
return await Promise.all(downloadLinks.map(async (index, element) => $(element).attr('href')));
} catch (error) {
console.error('Instagram Downloader 4 - Error:', error.message);
return null;
}
}
async function twdl1(url) {
const apiUrl = 'https://savetwitter.net/api/ajaxSearch';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;]',
'Referer': 'https://x2twitter.com/id',
'X-Forwarded-For': generateRandomIP(),
};
const data = `q=${encodeURIComponent(url)}&lang=id`;
try {
const response = await axios.post(apiUrl, data, {
headers
});
if (!response.data.hasOwnProperty('data')) {
throw new Error('Data tidak ditemukan di response');
}
const $ = cheerio.load(response.data.data);
$('a[onclick="showAd()"][href="#"]').remove();
$('a[href="/"]').remove();
$('a[href="#"]').remove();
const hrefs = [];
$('.dl-action').each((index, element) => {
const firstAnchor = $(element).find('a').first();
hrefs.push(firstAnchor.attr('href'));
});
return hrefs;
} catch (error) {
throw new Error('Failed to fetch Twitter image: ' + error);
}
}
async function twdl2(url) {
const apiUrl = 'https://x2twitter.com/api/ajaxSearch';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;]',
'Referer': 'https://x2twitter.com/id',
'X-Forwarded-For': generateRandomIP(),
};
const data = `q=${encodeURIComponent(url)}&lang=id`;
try {
const response = await axios.post(apiUrl, data, {
headers
});
if (!response.data.hasOwnProperty('data')) {
throw new Error('Data tidak ditemukan di response');
}
const $ = cheerio.load(response.data.data);
$('a[onclick="showAd()"][href="#"]').remove();
$('a[href="/"]').remove();
const hrefs = [];
$('.dl-action').each((index, element) => {
const firstAnchor = $(element).find('a').first();
hrefs.push(firstAnchor.attr('href'));
});
return hrefs;
} catch (error) {
throw new Error('Failed to fetch Twitter image: ' + error);
}
}
async function twdl3(url) {
const apiUrl = 'https://twtube.app/en/download?url=';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;]',
'Referer': 'https://savetwitter.net/id/twitter-image-downloader',
'X-Forwarded-For': generateRandomIP(),
};
try {
const response = await axios.get(apiUrl + url, {
headers
});
const $ = cheerio.load(response.data);
// Mendapatkan semua href dari elemen a dalam div dengan kelas 'square-box-btn'
const allHrefs = [];
// Menggunakan map untuk mengambil href dan mengembalikan array promise
const promises = $('.square-box-btn a').map(async (index, element) => {
let link = $(element).attr('href');
return link;
}).get();
// Menunggu semua promise selesai dan mengumpulkan hasilnya
return Promise.all(promises);
} catch (error) {
throw new Error('Failed to fetch Twitter image: ' + error);
}
}
async function DownloadFile(url) {
try {
const response = await axios.get(url, { responseType: 'arraybuffer' });
const mimeType = response.headers['content-type'];
const buffer = response.data;
const fileExtension = (await fileTypeFromBuffer(buffer)).ext;
const filename = `downloaded_file_${Date.now()}.${fileExtension}`;
const filePath = path.join(tempDir, filename);
await fss.writeFile(filePath, buffer);
console.log(`File berhasil diunduh dan disimpan sebagai: ${filePath}`);
return { mimeType, filePath };
} catch (error) {
console.error('Error saat mengunduh file:', error);
return null;
}
}
const getInstagramDownloadLinks = async (url) => {
let result = await igdl1(url);
if (!result || result.length === 0) {
result = await igdl2(url);
}
if (!result || result.length === 0) {
result = await igdl3(url);
}
if (!result || result.length === 0) {
result = await igdl4(url);
}
if (!result || result.length === 0) {
result = {
message: "all server error"
};
}
return result;
};
const Twitter = async (url) => {
let result = await twdl3(url);
if (!result || result.length === 0) {
result = await twdl2(url);
}
if (!result || result.length === 0) {
result = await twdl1(url);
}
if (!result || result.length === 0) {
result = {
message: "all server error"
};
}
return result;
};
app.get('/igdl', async (req, res) => {
try {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'Parameter url is required' });
if (!/https?:\/\/(www\.)?instagram\.com\/(p|reel|tv)/.test(url)) return res.status(400).json({ error: "Example: https://www.instagram.com/p/Cz1fTwMJFpx/?igsh=MXRrY2g4eWNucGoyZg==" });
let result = await getInstagramDownloadLinks(url);
let result_upload = {
media: []
}
for (let item of result) {
let unduh = await DownloadFile(item);
result_upload.media.push({
type: unduh.mimeType,
path: unduh.filePath,
url_path: `https://arashicode-api.hf.space/temp/${path.basename(unduh.filePath)}`
});
}
res.json(result_upload);
for (let item of result_upload.media) {
try {
await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
await fss.unlink(item.path);
console.log(`File ${item.path} deleted.`);
} catch (error) {
console.error(`Error deleting file ${item.path}:`, error);
}
}
} catch (error) {
console.error('Error processing request:', error);
res.status(500).json({
error: 'Failed to process request\n' + error
});
}
});
app.get('/twdl', async (req, res) => {
try {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'Parameter url is required' });
let result = await Twitter(url);
let result_upload = {
media: []
}
for (let item of result) {
let unduh = await DownloadFile(item);
result_upload.media.push({
type: unduh.mimeType,
path: unduh.filePath,
url_path: `https://arashicode-api.hf.space/temp/${path.basename(unduh.filePath)}`,
url_path2: `http://${os.hostname()}:${PORT}/temp/${path.basename(unduh.filePath)}`
});
}
res.json(result_upload);
for (let item of result_upload.media) {
try {
await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
await fss.unlink(item.path);
console.log(`File ${item.path} deleted.`);
} catch (error) {
console.error(`Error deleting file ${item.path}:`, error);
}
}
} catch (error) {
console.error('Error processing request:', error);
res.status(500).json({
error: 'Failed to process request\n' + error
});
}
});
/****
YTMP3
YTMP3
YTMP3
YTMP3
*****/
async function uploader(buffer) {
const { ext } = await fileTypeFromBuffer(buffer);
const bodyForm = new FormData();
bodyForm.append('file', buffer, `file.${ext}`);
const response = await fetch('https://aemt.me/api/upload.php', {
method: 'POST',
body: bodyForm,
});
return {
status: response.status,
creator: 'Nex',
result: await response.json(),
};
}
async function getHDThumbnailUrl(videoId) {
try {
const response = await youtube.videos.list({ part: 'snippet', id: videoId });
return response.data.items[0].snippet.thumbnails.maxres.url;
} catch (error) {
console.error('Error fetching HD thumbnail URL:', error.message);
return null;
}
}
async function GetId(data) {
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtu(?:be\.com\/(?:watch\?(?:v=|vi=)|v\/|vi\/)|\.be\/|be\.com\/embed\/|be\.com\/shorts\/)|youtube\.com\/\?(?:v=|vi=))([\w-]{11})/;
const res = regex.exec(data);
if (res && res[1]) return res[1];
throw new Error("Please check the URL you have entered");
}
async function addAudioTags(media, title, artist, year, imagecover) {
try {
let audioBuffer = (typeof media === 'string') ? Buffer.from((await axios.get(media, { responseType: 'arraybuffer', maxContentLength: -1 })).data) : (media instanceof Buffer) ? media : (() => { throw new Error('Media harus berupa URL string atau Buffer.'); })();
const randomFilename = title.replace(/[^\w\s\#\$\&\-\+\(\)\/\[\]\`\×\{\}\\\\\~\•]/g, '') + '.mp3';
const tmpFilePath = path.join(tempDir, randomFilename);
fs.writeFileSync(tmpFilePath, audioBuffer);
const tags = { title, artist, year };
if (typeof imagecover === 'string') {
const coverBuffer = Buffer.from((await axios.get(imagecover, { responseType: 'arraybuffer' })).data);
tags.image = { mime: 'image/jpeg', type: { id: 3, name: 'Front Cover' }, description: 'Cover', imageBuffer: coverBuffer };
} else if (imagecover instanceof Buffer) {
tags.image = { mime: 'image/jpeg', type: { id: 3, name: 'Front Cover' }, description: 'Cover', imageBuffer: imagecover };
}
const success = nodeID3.write(tags, tmpFilePath);
console[success ? 'log' : 'error'](success ? 'Tag ID3 berhasil diubah!' : 'Gagal mengubah tag ID3.');
return { msg: `Audio berhasil diubah.`, path: `${tmpFilePath}` };
} catch (error) {
console.error('Terjadi kesalahan:', error);
throw new Error('Terjadi kesalahan saat mengubah audio.');
}
}
function generateRandomName(length) {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let randomName = '';
for (let i = 0; i < length; i++) {
randomName += characters.charAt(Math.floor(Math.random() * characters.length));
}
return randomName;
}
async function getAudioMP3Url(videoUrl) {
try {
const info = await ytdl.getInfo(videoUrl);
const audioFormat = ytdl.chooseFormat(info.formats, { filter: 'audioonly', quality: 'highestaudio' });
const path_audio = path.join(tempDir, generateRandomName(10) + '.mp3');
let uploadResult;
await new Promise((resolve, reject) => {
ffmpeg()
.input(audioFormat.url)
.outputOptions('-f mp3')
.outputOptions('-acodec libmp3lame')
.outputOptions('-ab 128k')
.outputOptions('-ar 44100')
.on('end', async () => {
const buffer = fs.readFileSync(path_audio);
const id_video = await GetId(videoUrl);
const hd_thumbnail = await getHDThumbnailUrl(id_video);
const convert = await addAudioTags(buffer, info.videoDetails.title, info.videoDetails.ownerChannelName, 2024, hd_thumbnail);
const buffer2 = fs.readFileSync(convert.path);
uploadResult = await uploader(buffer2);
console.log('Upload result:', uploadResult);
fs.unlinkSync(path_audio);
fs.unlinkSync(convert.path);
resolve(uploadResult);
})
.on('error', (err) => {
console.error('FFmpeg conversion error:', err);
reject(err);
})
.save(path_audio);
});
return uploadResult;
} catch (error) {
console.error('Error:', error);
throw new Error('Failed to process audio URL');
}
}
app.get('/ytmp3', async (req, res) => {
try {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'Parameter url is required' });
let result = await getAudioMP3Url(url);
res.json(result);
} catch (error) {
console.error('Error processing request:', error);
res.status(500).json({
error: 'Failed to process request\n' + error
});
}
});
app.listen(PORT, () => {
console.log(`Server is running on port https://localhost:${PORT}`);
});