import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; // skipcq: JS-C1003 import { addClient, removeClient, sendEvent, } from '../utils/network/sse.util.js'; import { isSupportedUrl, isValidSpotifyUrl, decodeUrlIfNeeded, } from '../utils/network/validation.util.js'; import { pipeWebStream } from '../utils/network/proxy.util.js'; import { verifyProxyParams } from '../utils/network/secrets.util.js'; import { recordFailure } from '../utils/infra/metrics.util.js'; import { detectService, getSanitizedFilename, } from '../utils/media/video.util.js'; import { prepareFinalResponse } from '../utils/api/response.util.js'; import { getCookieArgs, initializeSession } from '../utils/api/controller.util.js'; import { processBackgroundTracks, resolveSeedTracks, type SeedTrack, } from '../services/seeder.service.js'; import { fetchMediaInfo, handleSpotifyRegistry, } from '../services/video/info.js'; import { parseRequestParams, resolveManifests, buildStreamResponse, } from '../services/video/stream-resolver.js'; import { executeDownload, streamViaYtdlp, } from '../services/video/download.js'; import { SpotifyMetadata } from '../types/index.js'; export const streamEvents = async ( req: Request, res: Response ): Promise => { const id = (req.query.id as string) || undefined; console.log(`[SSE] Client connecting: ${id}`); if (!id) { res.status(400).end(); return; } await addClient(id, res); }; export const getVideoInformation = async ( req: Request, res: Response ): Promise => { res.setHeader( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' ); let videoURL = decodeUrlIfNeeded(req.query.url as string); const clientId = (req.query.id as string) || undefined; if (videoURL) { videoURL = videoURL.split('&id=')[0].split('?id=')[0]; } if (!videoURL || !isSupportedUrl(videoURL)) { res.status(400).json({ error: 'No valid URL provided' }); return; } const serviceName = detectService(videoURL); await initializeSession(clientId); try { const cookieArgs = await getCookieArgs(videoURL, clientId); const isSpotify = videoURL.includes('spotify.com'); const info = await fetchMediaInfo( videoURL, clientId, serviceName, cookieArgs ); // fast partial hit if (!info || (!info.formats?.length && !info.isPartial)) { res.json({ title: info?.title || 'Unknown', thumbnail: info?.thumbnail || '', formats: [], audioFormats: [], }); return; } const spotifyData = isSpotify ? ({ ...info, type: 'spotify' } as unknown as SpotifyMetadata) : null; const targetURL = isSpotify ? info.targetUrl || videoURL : videoURL; const finalResponse = await prepareFinalResponse( info, isSpotify, spotifyData, videoURL ); if (isSpotify) { handleSpotifyRegistry(info, finalResponse, videoURL, targetURL); } res.json(finalResponse); } catch (error: unknown) { recordFailure('info'); console.error('[VideoInfo] Error:', (error as Error).message); Sentry.captureException(error); if (clientId) removeClient(clientId); if (!res.headersSent) res.status(500).json({ error: 'Failed to fetch video info' }); } }; export const getStreamUrls = async ( req: Request, res: Response ): Promise => { const { videoURL, clientId, formatId } = parseRequestParams(req); const timestamp = new Date().toLocaleTimeString('en-US', { hour12: true, hour: 'numeric', minute: '2-digit', second: '2-digit', }); if (!videoURL || !isSupportedUrl(videoURL)) { res.status(400).json({ error: 'No valid URL provided' }); return; } console.log(`[${timestamp}] [EME] Resolving manifests for Edge Muxing...`); try { const { info, videoTunnel, audioTunnel, isAudioOnly, filename, totalSize, outputMeta, } = await resolveManifests(req, videoURL, clientId, formatId); res.json( buildStreamResponse( info, videoTunnel, audioTunnel, isAudioOnly, filename, totalSize, outputMeta as Record ) ); } catch (error: unknown) { recordFailure('stream_urls'); console.error('[StreamUrls] Error:', (error as Error).message); Sentry.captureException(error); if (!res.headersSent) res.status(500).json({ error: 'Failed to resolve stream URLs' }); } }; export const proxyStream = async ( req: Request, res: Response ): Promise => { const queryData = req.query as Record; let { targetUrl, formatId, url: rawFallbackUrl, filename } = queryData; if (Array.isArray(targetUrl)) targetUrl = targetUrl[0]; if (Array.isArray(formatId)) formatId = formatId[0]; if (Array.isArray(rawFallbackUrl)) rawFallbackUrl = rawFallbackUrl[0]; if (Array.isArray(filename)) filename = filename[0]; let rawUrl = queryData.rawUrl; if (Array.isArray(rawUrl)) rawUrl = rawUrl[0]; // refuse forged or expired signed links if ( !verifyProxyParams({ targetUrl: targetUrl as string | undefined, rawUrl: rawUrl as string | undefined, formatId: formatId as string | undefined, exp: Number(req.query.exp), sig: req.query.sig as string | undefined, }) ) { res.status(403).json({ error: 'Invalid or expired proxy signature' }); return; } const urlToFetch = rawFallbackUrl || (req.query.rawUrl as string); if (urlToFetch) { const abortController = new AbortController(); req.on('close', () => abortController.abort()); try { await pipeWebStream( urlToFetch, res, filename as string, req.headers as unknown as Record, 0, abortController.signal ); return; } catch (error: unknown) { recordFailure('proxy'); console.error('[Proxy] Raw Pipe Error:', (error as Error).message); Sentry.captureException(error); if (!res.headersSent) res.status(500).json({ error: 'Proxy fetch failed' }); res.end(); return; } } if (targetUrl && formatId) { await streamViaYtdlp(req, res, targetUrl, formatId, filename); return; } res.status(400).end(); }; export const reportTelemetry = (req: Request, res: Response): void => { const { event } = req.body; const timestamp = new Date().toLocaleTimeString('en-US', { hour12: true, hour: 'numeric', minute: '2-digit', second: '2-digit', }); const safeEvent = String(event || 'unknown').replaceAll(/[^\w]/gu, '_'); console.log(`[${timestamp}] [EME] Client-Side Handshake: ${safeEvent}`); res.status(204).end(); }; export const convertVideo = (req: Request, res: Response): void => { if (req.method === 'HEAD') { res.status(200).end(); return; } res.setHeader( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' ); const requestData = { ...req.query, ...req.body } as { url?: string; id?: string; format?: string; formatId?: string; token?: string; title?: string; artist?: string; targetUrl?: string; }; const { url: videoURL, id: clientIdStr, format = 'mp4', formatId, } = requestData; const clientId = clientIdStr || undefined; console.log(`[Convert] Request received for: ${videoURL} (ID: ${clientId})`); if (!videoURL || !isSupportedUrl(videoURL)) { console.warn(`[Convert] Invalid URL: ${videoURL}`); res.status(400).json({ error: 'No valid URL provided' }); return; } const token = requestData.token || clientId; if (token) { res.setHeader('Set-Cookie', `download_token=${token}; Path=/; Max-Age=60`); } const isSpotifyRequest = videoURL.includes('spotify.com'); const timestamp = new Date().toLocaleTimeString('en-US', { hour12: true, hour: 'numeric', minute: '2-digit', second: '2-digit', }); let finalFormat = format; if (formatId?.startsWith('photo')) finalFormat = 'jpg'; const filename = getSanitizedFilename( requestData.title || 'video', requestData.artist, finalFormat, isSpotifyRequest ); console.log( `[${timestamp}] [Turbo] Starting Server-Side muxing for: ${filename}` ); if (clientId) { sendEvent(clientId, { status: 'initializing', progress: 5, subStatus: 'syncing core...', text: 'initiating jump', }); } (async () => { const result = await executeDownload( res, clientId, videoURL as string, requestData, timestamp, filename, format, formatId, isSpotifyRequest ); if (result) { const { videoProcess, hardTimeoutId } = result; req.on('close', () => { clearTimeout(hardTimeoutId); if (typeof videoProcess.kill === 'function') { console.log( `[${timestamp}] [Turbo] Client disconnected. Cleaning up stream for: ${clientId}` ); videoProcess.kill(); } if (!res.writableEnded) res.end(); }); } })().catch((error) => { console.error( `[${timestamp}] [ConvertVideo] Unhandled exception in download workflow:`, error ); Sentry.captureException(error); if (!res.headersSent) res .status(500) .json({ error: 'Internal server error during processing' }); if (!res.writableEnded) res.end(); }); }; export const seedIntelligence = async ( req: Request, res: Response ): Promise => { const { url, id: clientIdStr } = req.query as { url: string; id: string }; const clientId = clientIdStr || 'admin-seeder'; if (!url || !isValidSpotifyUrl(url)) { res .status(400) .json({ error: 'Invalid Spotify Artist/Album URL provided' }); return; } try { const tracks = await resolveSeedTracks(url); if (!tracks || tracks.length === 0) throw new Error('No tracks found.'); res.json({ message: 'Intelligence Gathering Started in Background', trackCount: tracks.length, target: url, }); processBackgroundTracks(tracks as SeedTrack[], clientId).catch( (error: Error) => { console.error('[Seeder] Background Process Crashed:', error.message); Sentry.captureException(error); } ); } catch (error: unknown) { if (!res.headersSent) { Sentry.captureException(error); res .status(500) .json({ error: (error as Error).message || 'An unknown error occurred', }); } } };