|
|
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; |
|
|
|
|
|
|
|
|
(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 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; |
|
|
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.'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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; |
|
|
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'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
try { |
|
|
await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); |
|
|
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 |
|
|
}); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
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(); |
|
|
} |
|
|
|
|
|
|
|
|
async function pingEvery5Hours() { |
|
|
await pingWebsite(); |
|
|
setInterval(async () => { |
|
|
await pingWebsite(); |
|
|
}, 5 * 60 * 60 * 1000); |
|
|
} |
|
|
|
|
|
|
|
|
pingEvery5Hours(); |
|
|
|
|
|
app.listen(PORT, () => { |
|
|
console.log(`Server is running on port ${PORT}`); |
|
|
}); |