Fix: Audio player skip behavior and range requests
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { readFile, stat } from 'fs/promises';
|
||||
import { stat } from 'fs/promises';
|
||||
import { createReadStream } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export async function GET(
|
||||
@@ -30,24 +31,59 @@ export async function GET(
|
||||
return new NextResponse('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
try {
|
||||
await stat(filePath);
|
||||
} catch {
|
||||
return new NextResponse('File not found', { status: 404 });
|
||||
const stats = await stat(filePath);
|
||||
const fileSize = stats.size;
|
||||
const range = request.headers.get('range');
|
||||
|
||||
if (range) {
|
||||
const parts = range.replace(/bytes=/, "").split("-");
|
||||
const start = parseInt(parts[0], 10);
|
||||
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
|
||||
const chunksize = (end - start) + 1;
|
||||
|
||||
const stream = createReadStream(filePath, { start, end });
|
||||
|
||||
// Convert Node stream to Web stream
|
||||
const readable = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on('data', (chunk: any) => controller.enqueue(chunk));
|
||||
stream.on('end', () => controller.close());
|
||||
stream.on('error', (err: any) => controller.error(err));
|
||||
}
|
||||
});
|
||||
|
||||
return new NextResponse(readable, {
|
||||
status: 206,
|
||||
headers: {
|
||||
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Content-Length': chunksize.toString(),
|
||||
'Content-Type': 'audio/mpeg',
|
||||
'Cache-Control': 'public, max-age=3600, must-revalidate',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const stream = createReadStream(filePath);
|
||||
|
||||
// Convert Node stream to Web stream
|
||||
const readable = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on('data', (chunk: any) => controller.enqueue(chunk));
|
||||
stream.on('end', () => controller.close());
|
||||
stream.on('error', (err: any) => controller.error(err));
|
||||
}
|
||||
});
|
||||
|
||||
return new NextResponse(readable, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Length': fileSize.toString(),
|
||||
'Content-Type': 'audio/mpeg',
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Cache-Control': 'public, max-age=3600, must-revalidate',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Read file
|
||||
const fileBuffer = await readFile(filePath);
|
||||
|
||||
// Return with proper headers
|
||||
return new NextResponse(fileBuffer, {
|
||||
headers: {
|
||||
'Content-Type': 'audio/mpeg',
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Cache-Control': 'public, max-age=3600, must-revalidate',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error serving audio file:', error);
|
||||
return new NextResponse('Internal Server Error', { status: 500 });
|
||||
|
||||
Reference in New Issue
Block a user