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'; import fetch from 'node-fetch'; const require = createRequire(import.meta.url); const fs = require('fs'); const path = require('path'); const { google } = require('googleapis'); const puppeteer = require('puppeteer'); const PORT = process.env.PORT || 7860; const app = express(); const readFileAsync = promisify(fs.readFile); const tempDir = path.join(os.tmpdir(), "temp"); const fss = fs.promises; // Membuat direktori sementara jika belum ada (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); }); // Fungsi untuk menghasilkan IP acak const generateRandomIP = () => { const octet = () => Math.floor(Math.random() * 256); return `${octet()}.${octet()}.${octet()}.${octet()}`; }; // Fungsi untuk upload file 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(), }; } // Fungsi untuk mendapatkan URL thumbnail HD 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; } } // Fungsi untuk mendapatkan ID video dari URL 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"); } // Fungsi untuk menambahkan tag ID3 ke file audio async function addAudioTags(media, title, artist, year, imagecover) { try { let audioBuffer; if (typeof media === 'string') { const response = await axios.get(media, { responseType: 'arraybuffer', maxContentLength: -1 }); audioBuffer = Buffer.from(response.data); } else if (media instanceof Buffer) { audioBuffer = media; } else { throw new Error('Media harus berupa URL string atau Buffer.'); } const randomFilename = generateRandomName(10) + '.mp3'; const tmpFilePath = path.join(tempDir, randomFilename); fs.writeFileSync(tmpFilePath, audioBuffer); const tags = { title, artist, year }; if (typeof imagecover === 'string') { const response = await axios.get(imagecover, { responseType: 'arraybuffer' }); const coverBuffer = Buffer.from(response.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.'); } } // Fungsi untuk menghasilkan nama acak 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; } // Fungsi untuk mendapatkan URL audio MP3 dari video YouTube 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; let convert; await new Promise((resolve, reject) => { ffmpeg() .input(audioFormat.url) .outputOptions('-f mp3') .outputOptions('-acodec libmp3lame') .outputOptions('-ab 128k') .outputOptions('-ar 44100') .on('end', async () => { try { const buffer = fs.readFileSync(path_audio); const id_video = await GetId(videoUrl); const hd_thumbnail = await getHDThumbnailUrl(id_video); convert = await addAudioTags(buffer, info.videoDetails.title, info.videoDetails.ownerChannelName, 2024, hd_thumbnail); const buffer2 = fs.readFileSync(convert.path); fs.unlinkSync(path_audio); resolve(); } catch (error) { reject(error); } }) .on('error', (err) => { console.error('FFmpeg conversion error:', err); reject(err); }) .save(path_audio); }); return { status: 200, title: info.videoDetails.title, result: { url_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(convert.path)}`, curl_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(convert.path)}?download=1&filename=${info.videoDetails.title}`, path: convert.path } }; } catch (error) { console.error('Error:', error); throw new Error('Failed to process audio URL'); } } // Endpoint untuk mengunduh audio MP3 dari YouTube 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); // Menghapus file setelah 10 menit try { await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes await fss.unlink(result.result.path); console.log(`File ${result.result.path} deleted.`); } catch (error) { console.error(`Error deleting file ${result.result.path}:`, error); } } catch (error) { console.error('Error processing request:', error); res.status(500).json({ error: 'Failed to process request\n' + error }); } }); // Fungsi untuk ping website async function pingWebsite() { const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]"); await page.goto('https://huggingface.co/spaces/ArashiCode/api'); console.log("Ping"); await browser.close(); } // Ping website setiap 5 jam async function pingEvery5Hours() { await pingWebsite(); setInterval(async () => { await pingWebsite(); }, 5 * 60 * 60 * 1000); // 5 hours in milliseconds } // Mulai ping pingEvery5Hours(); app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });