"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const multer_1 = __importDefault(require("multer")); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const ytDlp_1 = require("../services/ytDlp"); const UPLOADS_DIR = path_1.default.resolve('./uploads'); const storage = multer_1.default.diskStorage({ destination: (_req, _file, cb) => { if (!fs_1.default.existsSync(UPLOADS_DIR)) { fs_1.default.mkdirSync(UPLOADS_DIR, { recursive: true }); } cb(null, UPLOADS_DIR); }, filename: (_req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); cb(null, uniqueSuffix + path_1.default.extname(file.originalname)); } }); const upload = (0, multer_1.default)({ storage, fileFilter: (_req, file, cb) => { const allowedMimes = [ 'video/mp4', 'video/webm', 'video/x-matroska', 'video/quicktime', 'video/x-msvideo', 'video/mpeg', 'video/x-ms-wmv', 'video/x-flv' ]; if (allowedMimes.includes(file.mimetype) || file.originalname.match(/\.(mp4|mkv|webm|mov|avi|mpg|mpeg|wmv|flv)$/i)) { cb(null, true); } else { cb(new Error('Invalid file type. Only video files are allowed.')); } }, limits: { fileSize: 10 * 1024 * 1024 * 1024 } // 10GB }); const router = (0, express_1.Router)(); router.post('/upload', upload.single('video'), (req, res) => { if (!req.file) { res.status(400).json({ error: 'No video file uploaded' }); return; } res.json({ filePath: req.file.path, filename: req.file.originalname, size: req.file.size }); }); router.get('/', (_req, res) => { if (!fs_1.default.existsSync(UPLOADS_DIR)) { res.json({ files: [] }); return; } const entries = fs_1.default.readdirSync(UPLOADS_DIR, { withFileTypes: true }); const files = entries .filter(e => e.isFile()) .map(e => ({ filename: e.name, filePath: path_1.default.join(UPLOADS_DIR, e.name), size: fs_1.default.statSync(path_1.default.join(UPLOADS_DIR, e.name)).size })) .sort((a, b) => b.filePath.localeCompare(a.filePath)); res.json({ files }); }); router.delete('/:filename', (req, res) => { const raw = req.params.filename; const requested = Array.isArray(raw) ? raw[0] : raw; if (!requested) { res.status(400).json({ error: 'filename is required' }); return; } const resolved = path_1.default.resolve(UPLOADS_DIR, requested); const uploadsWithSep = UPLOADS_DIR.endsWith(path_1.default.sep) ? UPLOADS_DIR : UPLOADS_DIR + path_1.default.sep; if (!resolved.startsWith(uploadsWithSep)) { res.status(400).json({ error: 'Invalid filename' }); return; } if (!fs_1.default.existsSync(resolved)) { res.status(404).json({ error: 'File not found' }); return; } try { fs_1.default.unlinkSync(resolved); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: `Failed to delete: ${err.message}` }); } }); // Stream yt-dlp download progress over SSE. // Returns events: {type:'progress', percent} ... {type:'done', filePath, filename, title} // or {type:'error', message} router.get('/youtube/stream', (req, res) => { const url = req.query.url || ''; if (!url) { res.status(400).json({ error: 'url query param is required' }); return; } if (!(0, ytDlp_1.isYtDlpAvailable)()) { res.status(400).json({ error: 'yt-dlp is not installed or not in PATH' }); return; } res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('X-Accel-Buffering', 'no'); res.flushHeaders?.(); const send = (data) => { res.write(`data: ${JSON.stringify(data)}\n\n`); }; let clientGone = false; req.on('close', () => { clientGone = true; }); (0, ytDlp_1.downloadVideo)(url, UPLOADS_DIR, (percent) => { if (clientGone) return; send({ type: 'progress', percent }); }).then((result) => { if (clientGone) return; send({ type: 'done', ...result }); res.end(); }).catch((err) => { if (clientGone) return; send({ type: 'error', message: err.message }); res.end(); }); }); exports.default = router; //# sourceMappingURL=files.js.map