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

410 lines (356 loc) 14.2 kB
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 new Uint8Array(matches.map(byte => parseInt(byte, 16))); }, decrypt: async (enc) => { try { const secretKey = 'C5D58EF67A7584E4A29F6C35BBC4EB12'; const data = new Uint8Array(atob(enc).split('').map(c => c.charCodeAt(0))); const iv = data.slice(0, 16); const content = data.slice(16); const key = savetube.crypto.hexToBuffer(secretKey); const cryptoKey = await crypto.subtle.importKey( 'raw', key, { name: 'AES-CBC' }, false, ['decrypt'] ); const decrypted = await crypto.subtle.decrypt( { name: 'AES-CBC', iv: iv }, cryptoKey, content ); const decryptedText = new TextDecoder().decode(decrypted); return JSON.parse(decryptedText); } catch (error) { throw new Error(`Decryption failed: ${error.message}`); } } }, isUrl: (str) => { try { new URL(str); return true; } catch (_) { return false; } }, youtube: (url) => { if (!url) return null; const patterns = [ /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 pattern of patterns) { if (pattern.test(url)) return url.match(pattern)[1]; } return null; }, request: async (endpoint, data = {}, method = 'POST') => { try { const url = endpoint.startsWith('http') ? endpoint : `${savetube.api.base}${endpoint}`; const options = { method, headers: savetube.headers }; if (method === 'POST') { options.body = JSON.stringify(data); } const response = await fetch(url, options); const responseData = await response.json(); return { status: response.ok, code: response.status, data: responseData }; } catch (error) { return { status: false, code: 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: "URL is required" }; } if (!savetube.isUrl(link)) { return { status: false, code: 400, error: "Invalid YouTube URL" }; } 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: "Cannot extract YouTube video ID" }; } 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 || "Unknown", 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 search(query) { try { const searchUrl = `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}`; const response = await fetch(searchUrl); const html = await response.text(); const videoDataRegex = /var ytInitialData = ({.+?});/; const match = html.match(videoDataRegex); if (!match) { throw new Error('Could not parse search results'); } const data = JSON.parse(match[1]); const contents = data?.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents?.[0]?.itemSectionRenderer?.contents || []; const videos = contents .filter(item => item.videoRenderer) .map(item => { const video = item.videoRenderer; const videoId = video.videoId; const title = video.title?.runs?.[0]?.text || video.title?.simpleText || 'Unknown Title'; const author = video.ownerText?.runs?.[0]?.text || 'Unknown Channel'; const duration = video.lengthText?.simpleText || '0:00'; const views = video.viewCountText?.simpleText || '0 views'; const thumbnail = video.thumbnail?.thumbnails?.[0]?.url || `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`; const url = `https://www.youtube.com/watch?v=${videoId}`; return { type: 'video', videoId, url, title, description: video.descriptionSnippet?.runs?.map(r => r.text).join('') || '', thumbnail, duration: { text: duration }, ago: video.publishedTimeText?.simpleText || '', views: parseInt(views.replace(/[^\d]/g, '')) || 0, author: { name: author, url: video.ownerText?.runs?.[0]?.navigationEndpoint?.commandMetadata?.webCommandMetadata?.url || '' } }; }) .slice(0, 20); return { author: "Herza", status: 200, data: videos }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function transcript(link) { try { const videoId = getYouTubeVideoId(link); if (!videoId) { return { author: "Herza", status: 400, data: "Invalid YouTube URL" }; } const response = await fetch("https://ytb2mp4.com/api/fetch-transcript", { method: 'GET', 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" } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { author: "Herza", status: 200, data: data.transcript }; } catch (error) { return { author: "Herza", status: 500, data: error.message }; } } async function ytMp3(link) { const videoId = getYouTubeVideoId(link); if (!videoId) return { author: "Herza", status: 400, data: "Invalid YouTube URL" }; try { const saveTubeResult = await savetube.download(link, "mp3"); if (!saveTubeResult.status) { return { author: "Herza", status: 400, data: saveTubeResult.error || "Failed to get audio" }; } let audioUrl = saveTubeResult.result.download; return { author: "Herza", status: 200, data: { metadata: { title: saveTubeResult.result.title, duration: saveTubeResult.result.duration, thumbnail: saveTubeResult.result.thumbnail }, download: { url: audioUrl, filename: `${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" }; if (!savetube.formats.includes(resolution) || resolution === "mp3") { return { author: "Herza", status: 400, data: `Invalid resolution. Choose from: ${savetube.formats.filter(f => f !== "mp3").join(", ")}` }; } try { 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: saveTubeResult.result.title, duration: saveTubeResult.result.duration, thumbnail: saveTubeResult.result.thumbnail }, download: { url: saveTubeResult.result.download, filename: `${saveTubeResult.result.title}.mp4`, resolution: resolution } } }; } 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: "Available resolutions", 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 };