Spaces:
Paused
Paused
| const express = require('express'); | |
| const yts = require('yt-search'); | |
| const { spawn, exec } = require('child_process'); | |
| const util = require('util'); | |
| const path = require('path'); | |
| const dns = require('dns'); | |
| // Fixes the ENOTFOUND error for yt-search inside Docker | |
| dns.setDefaultResultOrder('ipv4first'); | |
| const execPromise = util.promisify(exec); | |
| const app = express(); | |
| app.use(express.json()); | |
| app.get('/', (req, res, next) => { | |
| if (req.accepts('html')) next(); | |
| else res.json({ status: "Online", creator: "Silent Tech API" }); | |
| }); | |
| app.use(express.static(path.join(__dirname, 'public'))); | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| // π ENDPOINT 1: YT SEARCH (Using yts) | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| app.get('/api/ytsearch', async (req, res) => { | |
| try { | |
| const query = req.query.q; | |
| if (!query) return res.status(400).json({ success: false, error: 'Missing parameter: q' }); | |
| const search = await yts(query); | |
| const videos = search.videos.slice(0, 10).map(v => ({ | |
| title: v.title, | |
| url: v.url, | |
| duration: v.timestamp, | |
| views: v.views.toLocaleString(), | |
| thumbnail: v.thumbnail, | |
| author: v.author.name | |
| })); | |
| res.json({ creator: 'Silent Tech', success: true, results: videos }); | |
| } catch (e) { | |
| res.status(500).json({ success: false, error: "Search failed: " + e.message }); | |
| } | |
| }); | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| // π΅ ENDPOINT 2: METADATA & STREAM LINKS | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| async function getVideoMeta(url) { | |
| // Removed the broken IP flag, standard yt-dlp only | |
| const { stdout } = await execPromise(`yt-dlp -J "${url.replace(/(["'$`\\])/g, '\\$1')}"`); | |
| return JSON.parse(stdout); | |
| } | |
| app.get('/api/ytmp3', async (req, res) => { | |
| try { | |
| const url = req.query.url; | |
| const meta = await getVideoMeta(url); | |
| const host = req.headers['x-forwarded-proto'] ? `${req.headers['x-forwarded-proto']}://${req.get('host')}` : `http://${req.get('host')}`; | |
| res.json({ success: true, title: meta.title, thumbnail: meta.thumbnail, download_url: `${host}/api/stream?url=${encodeURIComponent(url)}&type=mp3` }); | |
| } catch (e) { res.status(500).json({ success: false, error: e.message }); } | |
| }); | |
| app.get('/api/ytmp4', async (req, res) => { | |
| try { | |
| const url = req.query.url; | |
| const meta = await getVideoMeta(url); | |
| const host = req.headers['x-forwarded-proto'] ? `${req.headers['x-forwarded-proto']}://${req.get('host')}` : `http://${req.get('host')}`; | |
| res.json({ success: true, title: meta.title, thumbnail: meta.thumbnail, download_url: `${host}/api/stream?url=${encodeURIComponent(url)}&type=mp4` }); | |
| } catch (e) { res.status(500).json({ success: false, error: e.message }); } | |
| }); | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| // π‘οΈ INTERNAL STREAMER (Bypasses Bot IP Bans) | |
| // ββββββββββββββββββββββββββββββββββββββββββββ | |
| app.get('/api/stream', (req, res) => { | |
| const { url, type } = req.query; | |
| if (!url || !type) return res.status(400).send('Missing parameters'); | |
| const format = type === 'mp4' ? 'best[ext=mp4]' : 'bestaudio'; | |
| res.header('Content-Disposition', `attachment; filename="SilentTech.${type}"`); | |
| if (type === 'mp4') res.header('Content-Type', 'video/mp4'); | |
| if (type === 'mp3') res.header('Content-Type', 'audio/mpeg'); | |
| const ytdlp = spawn('yt-dlp', ['-f', format, '-o', '-', url]); | |
| ytdlp.stdout.pipe(res); | |
| }); | |
| app.listen(7860, "0.0.0.0", () => console.log('Silent Tech Multi-API running on port 7860')); |