import { NextRequest, NextResponse } from 'next/server'; import { downloadVideo } from '@/lib/youtube'; import { isValidYouTubeUrl } from '@/lib/utils'; import { getMimeType } from '@/lib/mime'; import type { DownloadRequest } from '@/lib/types'; import { createReadStream } from 'fs'; import { stat } from 'fs/promises'; import path from 'path'; import { Readable } from '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 } ); } }