UNPKG

notmebotz-tools

Version:

Sebuah Tools yang berfungsi untuk mendownload Video atau Foto dari media sosial, serta sebagai tools yang berguna untuk aplikasi kamu seperti untuk BOT

358 lines (316 loc) 11.8 kB
const axios = require("axios"); const yts = require("yt-search"); const crypto = require("crypto"); function getYouTubeVideoId(url) { const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|v\/|embed\/|user\/[^\/\n\s]+\/)?(?:watch\?v=|v%3D|embed%2F|video%2F)?|youtu\.be\/|youtube\.com\/watch\?v=|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/shorts\/|youtube\.com\/playlist\?list=)([a-zA-Z0-9_-]{11})/; const match = url.match(regex); return match ? match[1] : null; } const savetube = { api: { base: "https://media.savetube.me/api", cdn: "/random-cdn", info: "/v2/info", download: "/download" }, headers: { 'accept': '*/*', 'content-type': 'application/json', 'origin': 'https://yt.savetube.me', 'referer': 'https://yt.savetube.me/', 'user-agent': 'Postify/1.0.0' }, formats: ['144', '240', '360', '480', '720', '1080', 'mp3'], crypto: { hexToBuffer: (hexString) => { const matches = hexString.match(/.{1,2}/g); return Buffer.from(matches.join(''), 'hex'); }, decrypt: async (enc) => { try { const secretKey = 'C5D58EF67A7584E4A29F6C35BBC4EB12'; const data = Buffer.from(enc, 'base64'); const iv = data.slice(0, 16); const content = data.slice(16); const key = savetube.crypto.hexToBuffer(secretKey); const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv); let decrypted = decipher.update(content); decrypted = Buffer.concat([decrypted, decipher.final()]); return JSON.parse(decrypted.toString()); } catch (error) { throw new Error(`${error.message}`); } } }, isUrl: (str) => { try { new URL(str); return true; } catch (_) { return false; } }, youtube: (url) => { if (!url) return null; const a = [ /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 b of a) { if (b.test(url)) return url.match(b)[1]; } return null; }, request: async (endpoint, data = {}, method = 'post') => { try { const { data: response } = await axios({ method, url: `${endpoint.startsWith('http') ? '' : savetube.api.base}${endpoint}`, data: method === 'post' ? data : undefined, params: method === 'get' ? data : undefined, headers: savetube.headers }); return { status: true, code: 200, data: response }; } catch (error) { return { status: false, code: error.response?.status || 500, error: error.message }; } }, getCDN: async () => { const response = await savetube.request(savetube.api.cdn, {}, 'get'); if (!response.status) return response; return { status: true, code: 200, data: response.data.cdn }; }, download: async (link, format) => { if (!link) { return { status: false, code: 400, error: "Linknya mana? Yakali download kagak ada linknya 🗿" }; } if (!savetube.isUrl(link)) { return { status: false, code: 400, error: "Lu masukin link apaan sih 🗿 Link Youtube aja bree, kan lu mau download youtube 👍🏻" }; } if (!format || !savetube.formats.includes(format)) { return { status: false, code: 400, error: "Format Is Unavailable", available_fmt: savetube.formats }; } const id = savetube.youtube(link); if (!id) { return { status: false, code: 400, error: "Kagak bisa ekstrak link youtubenya nih, btw link youtubenya yang bener yak.. biar kagak kejadian begini lagi 😂" }; } try { const cdnx = await savetube.getCDN(); if (!cdnx.status) return cdnx; const cdn = cdnx.data; const result = await savetube.request(`https://${cdn}${savetube.api.info}`, { url: `https://www.youtube.com/watch?v=${id}` }); if (!result.status) return result; const decrypted = await savetube.crypto.decrypt(result.data.data); const dl = await savetube.request(`https://${cdn}${savetube.api.download}`, { id: id, downloadType: format === 'mp3' ? 'audio' : 'video', quality: format === 'mp3' ? '128' : format, key: decrypted.key }); return { status: true, code: 200, result: { title: decrypted.title || "Gak tau 🤷🏻", type: format === 'mp3' ? 'audio' : 'video', format: format, thumbnail: decrypted.thumbnail || `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`, download: dl.data.data.downloadUrl, id: id, key: decrypted.key, duration: decrypted.duration, quality: format === 'mp3' ? '128' : format, downloaded: dl.data.data.downloaded || false } }; } catch (error) { return { status: false, code: 500, error: error.message }; } } }; async function ytMp3(link) { const videoId = getYouTubeVideoId(link); if (!videoId) return { author: "Herza", status: 400, data: "Invalid YouTube URL" }; try { const searchResult = await yts("https://youtube.com/watch?v=" + videoId); const metadata = searchResult.all[0]; const saveTubeResult = await savetube.download(link, "mp3"); if (!saveTubeResult.status) { return { author: "Herza", status: 400, data: saveTubeResult.error || "Failed to get audio" }; } // Langsung menggunakan URL audio dari savetube, tidak perlu mengkonversi dengan ffmpeg let audioUrl = saveTubeResult.result.download; return { author: "Herza", status: 200, data: { metadata: { title: metadata.title || saveTubeResult.result.title, description: metadata.description || "", duration: saveTubeResult.result.duration || metadata.duration, views: metadata.views, author: metadata.author?.name || "", timestamp: metadata.timestamp, ago: metadata.ago, thumbnail: metadata.thumbnail || saveTubeResult.result.thumbnail }, download: { url: audioUrl, filename: `${metadata.title || saveTubeResult.result.title}.mp3` } } }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function ytMp4(link, resolution = "480") { const videoId = getYouTubeVideoId(link); if (!videoId) return { author: "Herza", status: 400, data: "Invalid YouTube URL" }; // Validasi resolusi if (!savetube.formats.includes(resolution) || resolution === "mp3") { return { author: "Herza", status: 400, data: `Resolusi tidak valid. Pilih dari: ${savetube.formats.filter(f => f !== "mp3").join(", ")}` }; } try { const searchResult = await yts("https://youtube.com/watch?v=" + videoId); const metadata = searchResult.all[0]; const saveTubeResult = await savetube.download(link, resolution); if (!saveTubeResult.status) { return { author: "Herza", status: 400, data: saveTubeResult.error || "Failed to get video" }; } return { author: "Herza", status: 200, data: { metadata: { title: metadata.title || saveTubeResult.result.title, description: metadata.description || "", duration: saveTubeResult.result.duration || metadata.duration, views: metadata.views, author: metadata.author?.name || "", timestamp: metadata.timestamp, ago: metadata.ago, thumbnail: metadata.thumbnail || saveTubeResult.result.thumbnail }, download: { url: saveTubeResult.result.download, filename: `${metadata.title || saveTubeResult.result.title}.mp4`, resolution: resolution } } }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function search(teks) { try { let data = await yts(teks); return { author: "Herza", status: 200, data: data.all }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function transcript(link) { try { const response = await axios.get("https://ytb2mp4.com/api/fetch-transcript", { params: { url: link }, headers: { "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36", "Referer": "https://ytb2mp4.com/youtube-transcript" } }); return { author: "Herza", status: 200, data: response.data.transcript }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function getAvailableResolutions(link) { const videoId = getYouTubeVideoId(link); if (!videoId) return { author: "Herza", status: 400, data: "Invalid YouTube URL" }; return { author: "Herza", status: 200, data: { message: "Resolusi yang tersedia", resolutions: savetube.formats.filter(f => f !== "mp3") } }; } async function ytdl(type, ...args) { switch (type.toLowerCase()) { case "ytmp4": if (args.length < 1) return { author: "Herza", status: 400, data: "Missing arguments. Usage: ytdl('ytmp4', 'url', 'resolution')" }; return await ytMp4(args[0], args[1] || "480"); case "ytmp3": if (args.length < 1) return { author: "Herza", status: 400, data: "Missing arguments. Usage: ytdl('ytmp3', 'url')" }; return await ytMp3(args[0]); case "search": if (args.length < 1) return { author: "Herza", status: 400, data: "Missing arguments. Usage: ytdl('search', 'query')" }; return await search(args[0]); case "transcript": if (args.length < 1) return { author: "Herza", status: 400, data: "Missing arguments. Usage: ytdl('transcript', 'url')" }; return await transcript(args[0]); case "resolutions": if (args.length < 1) return { author: "Herza", status: 400, data: "Missing arguments. Usage: ytdl('resolutions', 'url')" }; return await getAvailableResolutions(args[0]); default: return { author: "Herza", status: 400, data: { message: "Invalid type. Available types: ytmp4, ytmp3, search, transcript, resolutions", usage: { ytmp4: "ytdl('ytmp4', 'url', 'resolution')", ytmp3: "ytdl('ytmp3', 'url')", search: "ytdl('search', 'query')", transcript: "ytdl('transcript', 'url')", resolutions: "ytdl('resolutions', 'url')" } } }; } } module.exports = { ytdl };