import { NextRequest, NextResponse } from 'next/server'; import { downloadVideo } from '@/lib/youtube'; import { isValidYouTubeUrl } from '@/lib/utils'; import type { DownloadRequest, AudioFormat, VideoFormat, FormatType } from '@/lib/types'; import { createReadStream } from 'fs'; import { stat } from 'fs/promises'; import path from 'path'; import { Readable } from 'stream'; const VIDEO_MIME: Record = { mp4: 'video/mp4', webm: 'video/webm', mkv: 'video/x-matroska', avi: 'video/x-msvideo', }; const AUDIO_MIME: Record = { mp3: 'audio/mpeg', wav: 'audio/wav', m4a: 'audio/mp4', opus: 'audio/ogg', }; function getMimeType(formatType: FormatType, format: VideoFormat | AudioFormat): string { if (formatType === 'video') { return VIDEO_MIME[format as VideoFormat] || 'application/octet-stream'; } return AUDIO_MIME[format as AudioFormat] || 'application/octet-stream'; } async function resolveDownloadPath(downloadUrl: string) { const sanitized = downloadUrl.startsWith('/') ? downloadUrl.slice(1) : downloadUrl; const filePath = path.join(process.cwd(), 'public', sanitized); const fileInfo = await stat(filePath); return { filePath, size: fileInfo.size }; } export async function POST(request: NextRequest) { try { const body: DownloadRequest = await request.json(); const { url, format, formatType } = body; if (!url || !format || !formatType) { return NextResponse.json( { success: false, error: 'Missing required fields' }, { status: 400 } ); } if (!isValidYouTubeUrl(url)) { return NextResponse.json( { success: false, error: 'Invalid YouTube URL' }, { status: 400 } ); } const result = await downloadVideo(body); if (!result.success || !result.downloadUrl || !result.filename) { return NextResponse.json( { success: false, error: result.error || 'Failed to process download' }, { status: 500 } ); } const { filePath, size } = await resolveDownloadPath(result.downloadUrl); const nodeStream = createReadStream(filePath); const webStream = Readable.toWeb(nodeStream) as unknown as ReadableStream; const headers = new Headers(); headers.set('Content-Type', getMimeType(formatType, format)); headers.set('Content-Length', size.toString()); headers.set('Content-Disposition', `attachment; filename="${result.filename}"`); return new NextResponse(webStream, { status: 200, headers }); } catch (error: any) { console.error('Direct download error:', error); return NextResponse.json( { success: false, error: error.message || 'Internal server error' }, { status: 500 } ); } }