removed reel.mp4
This commit is contained in:
parent
90e730c2fe
commit
a2c67c3fb9
BIN
public/reel.mp4
BIN
public/reel.mp4
Binary file not shown.
94
src/app/api/media/[...path]/route.ts
Normal file
94
src/app/api/media/[...path]/route.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
request: NextRequest,
|
||||||
|
{ params }: { params: { path: string[] } }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const path = params.path.join('/');
|
||||||
|
|
||||||
|
// @ts-ignore - MEDIA is bound via wrangler.toml and available in the Cloudflare context
|
||||||
|
const cloudflareContext = (globalThis as any)[Symbol.for('__cloudflare-context__')];
|
||||||
|
const MEDIA = cloudflareContext?.env?.MEDIA;
|
||||||
|
|
||||||
|
if (!MEDIA) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Media bucket not configured' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the object from R2
|
||||||
|
const object = await MEDIA.get(path);
|
||||||
|
|
||||||
|
if (!object) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: `File not found: ${path}` },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get range header for video streaming support
|
||||||
|
const range = request.headers.get('range');
|
||||||
|
|
||||||
|
// Get the full object body to handle range requests properly
|
||||||
|
const body = await object.body.arrayBuffer();
|
||||||
|
const totalLength = body.byteLength;
|
||||||
|
|
||||||
|
let start = 0;
|
||||||
|
let end = totalLength - 1;
|
||||||
|
let status = 200;
|
||||||
|
|
||||||
|
if (range) {
|
||||||
|
// Extract start and end positions from range header
|
||||||
|
const match = range.match(/bytes=(\d+)-(\d+)?/);
|
||||||
|
if (match) {
|
||||||
|
start = parseInt(match[1], 10);
|
||||||
|
end = match[2] ? parseInt(match[2], 10) : end;
|
||||||
|
|
||||||
|
// Ensure end is within the bounds
|
||||||
|
if (end >= totalLength) {
|
||||||
|
end = totalLength - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = 206; // Partial content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the length for the response
|
||||||
|
const contentLength = end - start + 1;
|
||||||
|
const slicedBody = body.slice(start, end + 1);
|
||||||
|
|
||||||
|
// Set headers for the response
|
||||||
|
const headers = new Headers();
|
||||||
|
object.writeHttpMetadata(headers);
|
||||||
|
headers.set('etag', object.httpEtag);
|
||||||
|
headers.set('cache-control', 'public, max-age=31536000, immutable');
|
||||||
|
|
||||||
|
// Add CORS headers to allow video requests from the same origin
|
||||||
|
headers.set('access-control-allow-origin', '*');
|
||||||
|
headers.set('access-control-allow-headers', 'range, content-type, accept');
|
||||||
|
headers.set('access-control-allow-methods', 'GET, HEAD, OPTIONS');
|
||||||
|
headers.set('access-control-expose-headers', 'content-range, accept-ranges, content-length, content-encoding');
|
||||||
|
|
||||||
|
// Add range response headers if needed
|
||||||
|
if (range) {
|
||||||
|
headers.set('content-range', `bytes ${start}-${end}/${totalLength}`);
|
||||||
|
headers.set('accept-ranges', 'bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
headers.set('content-length', contentLength.toString());
|
||||||
|
headers.set('content-type', path.endsWith('.mp4') ? 'video/mp4' : object.httpMetadata?.contentType || 'application/octet-stream');
|
||||||
|
|
||||||
|
return new NextResponse(slicedBody, {
|
||||||
|
status,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error serving media:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to serve media file' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user