Spaces:
Running
Running
Proxy remote admin videos locally
Browse files
src/app/admin/reviews/page.tsx
CHANGED
|
@@ -62,14 +62,6 @@ function remoteRecorderHref() {
|
|
| 62 |
}
|
| 63 |
}
|
| 64 |
|
| 65 |
-
function absolutizePreviewUrl(previewUrl: string, sourceUrl: string) {
|
| 66 |
-
try {
|
| 67 |
-
return new URL(previewUrl, sourceUrl).toString();
|
| 68 |
-
} catch {
|
| 69 |
-
return previewUrl;
|
| 70 |
-
}
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
async function listReviewsForAdminPage() {
|
| 74 |
const remote = remoteAdminConfig();
|
| 75 |
if (!remote) {
|
|
@@ -97,7 +89,7 @@ async function listReviewsForAdminPage() {
|
|
| 97 |
return {
|
| 98 |
submissions: submissions.map((submission) => ({
|
| 99 |
...submission,
|
| 100 |
-
previewUrl:
|
| 101 |
})),
|
| 102 |
sourceLabel: 'hugging face',
|
| 103 |
};
|
|
|
|
| 62 |
}
|
| 63 |
}
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
async function listReviewsForAdminPage() {
|
| 66 |
const remote = remoteAdminConfig();
|
| 67 |
if (!remote) {
|
|
|
|
| 89 |
return {
|
| 90 |
submissions: submissions.map((submission) => ({
|
| 91 |
...submission,
|
| 92 |
+
previewUrl: `/api/admin/remote-video/${encodeURIComponent(submission.submissionId)}`,
|
| 93 |
})),
|
| 94 |
sourceLabel: 'hugging face',
|
| 95 |
};
|
src/app/api/admin/remote-video/[submissionId]/route.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from 'next/server';
|
| 2 |
+
|
| 3 |
+
export const dynamic = 'force-dynamic';
|
| 4 |
+
export const runtime = 'nodejs';
|
| 5 |
+
|
| 6 |
+
type Params = { params: { submissionId: string } };
|
| 7 |
+
|
| 8 |
+
function remoteBaseUrl() {
|
| 9 |
+
const explicitRecorder = process.env.REMOTE_PUBLIC_RECORDER_URL;
|
| 10 |
+
const adminUrl = process.env.REMOTE_ADMIN_REVIEWS_URL;
|
| 11 |
+
const source = explicitRecorder || adminUrl;
|
| 12 |
+
|
| 13 |
+
if (!source) return null;
|
| 14 |
+
|
| 15 |
+
try {
|
| 16 |
+
return new URL(source).origin;
|
| 17 |
+
} catch {
|
| 18 |
+
return null;
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
function responseHeaders(upstream: Response) {
|
| 23 |
+
const headers = new Headers();
|
| 24 |
+
for (const [key, value] of upstream.headers.entries()) {
|
| 25 |
+
const lower = key.toLowerCase();
|
| 26 |
+
if (
|
| 27 |
+
lower === 'connection' ||
|
| 28 |
+
lower === 'content-encoding' ||
|
| 29 |
+
lower === 'transfer-encoding'
|
| 30 |
+
) {
|
| 31 |
+
continue;
|
| 32 |
+
}
|
| 33 |
+
headers.set(key, value);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
headers.set('Cache-Control', 'no-store');
|
| 37 |
+
headers.set('Cross-Origin-Resource-Policy', 'same-origin');
|
| 38 |
+
return headers;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
export async function GET(req: NextRequest, { params }: Params) {
|
| 42 |
+
const baseUrl = remoteBaseUrl();
|
| 43 |
+
if (!baseUrl) {
|
| 44 |
+
return NextResponse.json(
|
| 45 |
+
{ error: 'Remote admin video source is not configured' },
|
| 46 |
+
{ status: 404 },
|
| 47 |
+
);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
const target = new URL(
|
| 51 |
+
`/api/public/reviews/video/${encodeURIComponent(params.submissionId)}`,
|
| 52 |
+
baseUrl,
|
| 53 |
+
);
|
| 54 |
+
const headers = new Headers();
|
| 55 |
+
const range = req.headers.get('range');
|
| 56 |
+
if (range) headers.set('range', range);
|
| 57 |
+
|
| 58 |
+
const upstream = await fetch(target, {
|
| 59 |
+
headers,
|
| 60 |
+
cache: 'no-store',
|
| 61 |
+
});
|
| 62 |
+
|
| 63 |
+
return new NextResponse(upstream.body, {
|
| 64 |
+
status: upstream.status,
|
| 65 |
+
headers: responseHeaders(upstream),
|
| 66 |
+
});
|
| 67 |
+
}
|