mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-14 16:23:43 +08:00
feat: Enhance proxy to forward client headers and control caching, and simplify video player's source handling by removing internal proxy URL construction.
This commit is contained in:
+11
-1
@@ -15,7 +15,16 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetchWithRetry({ url, request });
|
||||
// Extract headers to forward (Cookies, Accept-Language, etc.)
|
||||
const requestHeaders: Record<string, string> = {};
|
||||
const forwardHeaders = ['cookie', 'accept', 'accept-language'];
|
||||
|
||||
forwardHeaders.forEach(key => {
|
||||
const value = request.headers.get(key);
|
||||
if (value) requestHeaders[key] = value;
|
||||
});
|
||||
|
||||
const response = await fetchWithRetry({ url, request, headers: requestHeaders });
|
||||
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
|
||||
@@ -68,6 +77,7 @@ export async function GET(request: NextRequest) {
|
||||
headers.set('Access-Control-Allow-Origin', '*');
|
||||
headers.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
||||
headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
||||
|
||||
return new NextResponse(response.body, {
|
||||
status: response.status,
|
||||
|
||||
@@ -30,14 +30,8 @@ export function MobileVideoPlayer({
|
||||
const { refs, state } = useMobilePlayerState();
|
||||
const { currentTime } = state;
|
||||
|
||||
// Ensure src goes through proxy to avoid CORS/IP issues on Vercel
|
||||
// But don't double-proxy if already proxied
|
||||
const proxySrc = src.includes('/api/proxy')
|
||||
? src
|
||||
: `${typeof window !== 'undefined' ? window.location.origin : ''}/api/proxy?url=${encodeURIComponent(src)}`;
|
||||
|
||||
// Preload HLS segments
|
||||
useHLSPreloader({ src: proxySrc, currentTime, videoRef: refs.videoRef, isLoading: state.isLoading });
|
||||
useHLSPreloader({ src, currentTime, videoRef: refs.videoRef, isLoading: state.isLoading });
|
||||
|
||||
const {
|
||||
videoRef,
|
||||
@@ -60,7 +54,7 @@ export function MobileVideoPlayer({
|
||||
} = state;
|
||||
|
||||
const logic = useMobilePlayerLogic({
|
||||
src: proxySrc,
|
||||
src,
|
||||
initialTime,
|
||||
shouldAutoPlay,
|
||||
onError,
|
||||
@@ -104,7 +98,7 @@ export function MobileVideoPlayer({
|
||||
<video
|
||||
ref={videoRef}
|
||||
className="w-full h-full object-contain touch-none"
|
||||
src={proxySrc}
|
||||
src={src}
|
||||
poster={poster}
|
||||
onPlay={handlePlay}
|
||||
onPause={handlePause}
|
||||
@@ -133,7 +127,7 @@ export function MobileVideoPlayer({
|
||||
/>
|
||||
|
||||
<MobileControlsWrapper
|
||||
src={proxySrc}
|
||||
src={src}
|
||||
state={state}
|
||||
logic={logic}
|
||||
refs={refs}
|
||||
|
||||
@@ -20,11 +20,6 @@ export function useHlsPlayer({
|
||||
const video = videoRef.current;
|
||||
if (!video || !src) return;
|
||||
|
||||
// Ensure src goes through proxy to avoid CORS/IP issues on Vercel
|
||||
const proxySrc = src.includes('/api/proxy')
|
||||
? src
|
||||
: `${window.location.origin}/api/proxy?url=${encodeURIComponent(src)}`;
|
||||
|
||||
// Cleanup previous HLS instance
|
||||
if (hlsRef.current) {
|
||||
hlsRef.current.destroy();
|
||||
@@ -54,7 +49,7 @@ export function useHlsPlayer({
|
||||
});
|
||||
hlsRef.current = hls;
|
||||
|
||||
hls.loadSource(proxySrc);
|
||||
hls.loadSource(src);
|
||||
hls.attachMedia(video);
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
@@ -122,12 +117,12 @@ export function useHlsPlayer({
|
||||
} else {
|
||||
console.log('[HLS] Using native HLS support');
|
||||
// Native HLS support
|
||||
video.src = proxySrc;
|
||||
video.src = src;
|
||||
}
|
||||
} else if (isNativeHlsSupported) {
|
||||
// Fallback for environments where Hls.js is not supported but native is (e.g. iOS without MSE?)
|
||||
console.log('[HLS] Using native HLS support (Hls.js not supported)');
|
||||
video.src = proxySrc;
|
||||
video.src = src;
|
||||
} else {
|
||||
console.error('[HLS] HLS not supported in this browser');
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@ import { NextRequest } from 'next/server';
|
||||
interface FetchWithRetryOptions {
|
||||
url: string;
|
||||
request: NextRequest;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): Promise<Response> {
|
||||
export async function fetchWithRetry({ url, request, headers = {} }: FetchWithRetryOptions): Promise<Response> {
|
||||
// User-Agent rotation for better compatibility
|
||||
const userAgents = [
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
@@ -20,10 +21,8 @@ export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): P
|
||||
// Optional IP forwarding (default: Beijing IP)
|
||||
const forwardedIP = request.nextUrl.searchParams.get('ip') || '202.108.22.5';
|
||||
|
||||
// Vercel serverless functions have a 10s default timeout
|
||||
const isVercel = process.env.VERCEL === '1';
|
||||
const MAX_RETRIES = isVercel ? 2 : 5;
|
||||
const TIMEOUT_MS = isVercel ? 8000 : 30000; // 8s for Vercel, 30s for others
|
||||
const MAX_RETRIES = 5;
|
||||
const TIMEOUT_MS = 30000; // 30 seconds
|
||||
let lastError: unknown = null;
|
||||
let response: Response | null = null;
|
||||
|
||||
@@ -44,6 +43,7 @@ export async function fetchWithRetry({ url, request }: FetchWithRetryOptions): P
|
||||
'X-Forwarded-For': forwardedIP,
|
||||
'Client-IP': forwardedIP,
|
||||
'Referer': referer,
|
||||
...headers, // Merge custom headers (Cookie, Accept, etc.)
|
||||
},
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user