import { Response } from 'express'; import { VideoInfo, SpotifyMetadata, FinalResponse, } from '../../types/index.js'; import { FinalResponseSchema } from '../../../../shared/schemas/media.schema.js'; import { processVideoFormats, processAudioFormats, } from '../media/format.util.js'; import { normalizeTitle, normalizeArtist, getBestThumbnail, proxyThumbnailIfNeeded, } from '../../services/social.service.js'; async function _resolveThumbnail( info: VideoInfo, isSpotify: boolean, spotifyData: SpotifyMetadata | null, videoURL: string ): Promise { const spotifyImg = spotifyData?.cover || spotifyData?.thumbnail || info?.thumbnail || info?.cover; let finalThumbnail = getBestThumbnail(info); if (isSpotify && spotifyImg) { finalThumbnail = await proxyThumbnailIfNeeded(spotifyImg, videoURL); } else { finalThumbnail = await proxyThumbnailIfNeeded(finalThumbnail, videoURL); } return finalThumbnail || '/logo.webp'; } function _getSpotifyPayload( info: VideoInfo, spotifyData: SpotifyMetadata, videoURL: string ) { return { id: info.id || spotifyData.id || videoURL, title: spotifyData.title || info.title, artist: spotifyData.artist || info.artist || 'Unknown', uploader: spotifyData.artist || info.artist || info.uploader, album: spotifyData.album || info.album || '', previewUrl: spotifyData.previewUrl || info.previewUrl, }; } function _mapFinalMetadata( info: VideoInfo, spotifyData: SpotifyMetadata | null, finalTitle: string, finalArtist: string, finalThumbnail: string, isSpotify: boolean, videoURL: string ): FinalResponse { const isPartial = Boolean(info.isPartial); const isIsrcMatch = Boolean(info.isIsrcMatch); const isJsInfo = Boolean(info.isJsInfo); // youtube keeps raw title; social normalized const isYouTube = videoURL.includes('youtube.com') || videoURL.includes('youtu.be'); const base = isSpotify && spotifyData ? _getSpotifyPayload(info, spotifyData, videoURL) : { id: info.id || videoURL, title: isYouTube ? info.title || finalTitle : finalTitle || info.title, artist: finalArtist || info.artist || 'Unknown', uploader: finalArtist || info.artist || info.uploader, album: info.album || '', previewUrl: info.previewUrl || null, }; const payload = { ...base, cover: finalThumbnail, thumbnail: finalThumbnail, duration: info.duration, formats: processVideoFormats(info), // keep audio split out by normalizers audioFormats: info.audioFormats?.length ? info.audioFormats : processAudioFormats(info), spotifyMetadata: spotifyData ? { ...spotifyData, type: 'spotify' as const } : undefined, isPartial, isrc: spotifyData?.isrc || info.isrc, isIsrcMatch, isJsInfo, webpageUrl: videoURL, }; return FinalResponseSchema.parse(payload); } export async function prepareFinalResponse( info: VideoInfo, isSpotify: boolean, spotifyData: SpotifyMetadata | null, videoURL: string ): Promise { const finalThumbnail = await _resolveThumbnail( info, isSpotify, spotifyData, videoURL ); const finalTitle = normalizeTitle(info); const finalArtist = normalizeArtist(info); if (isSpotify) { const preview = spotifyData?.previewUrl || info.previewUrl; if (preview) { console.log(`[Response] Sending Preview: ${preview.substring(0, 50)}...`); } else { console.log( `[Response] No Preview found for ${spotifyData?.title || info.title}` ); } } return _mapFinalMetadata( info, spotifyData, finalTitle, finalArtist, finalThumbnail, isSpotify, videoURL ); } export function prepareBrainResponse(spotifyData: SpotifyMetadata) { const duration = spotifyData.duration || (spotifyData.audioFeatures?.duration_ms ? spotifyData.audioFeatures.duration_ms / 1000 : 0); return { title: spotifyData.title, artist: spotifyData.artist, album: spotifyData.album, cover: spotifyData.cover || '/logo.webp', thumbnail: spotifyData.thumbnail || '/logo.webp', duration, previewUrl: spotifyData.previewUrl, formats: spotifyData.formats ?? [], audioFormats: spotifyData.audioFormats ?? [], spotifyMetadata: spotifyData, }; } export function setupConvertResponse( res: Response, filename: string, format: string, _size = 0 ) { const mimeTypes: Record = { mp3: 'audio/mpeg', m4a: 'audio/mp4', mp4: 'video/mp4', opus: 'audio/opus', ogg: 'audio/ogg', jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', }; const safeName = encodeURIComponent(filename); const asciiName = filename.replaceAll(/[^\u0020-\u007E]/gu, ''); res.setHeader( 'Content-Disposition', `attachment; filename="${asciiName.replaceAll('"', '')}"; filename*=UTF-8''${safeName}` ); res.setHeader( 'Content-Type', mimeTypes[format] || 'application/octet-stream' ); res.setHeader( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' ); res.setHeader('Accept-Ranges', 'bytes'); }