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'));