From 146f3a0b423c6704ec3410ffa20278d694adc4e7 Mon Sep 17 00:00:00 2001 From: Pas <74743263+Pasithea0@users.noreply.github.com> Date: Wed, 14 May 2025 17:40:05 -0600 Subject: [PATCH] fix parsing --- src/routes/m3u8-proxy.ts | 116 +++++++++++++++++++++++---------------- src/routes/ts-proxy.ts | 47 ++++++++++------ 2 files changed, 101 insertions(+), 62 deletions(-) diff --git a/src/routes/m3u8-proxy.ts b/src/routes/m3u8-proxy.ts index 1a6d948..fa2cf52 100644 --- a/src/routes/m3u8-proxy.ts +++ b/src/routes/m3u8-proxy.ts @@ -5,37 +5,29 @@ // Helper function to parse URLs function parseURL(req_url: string, baseUrl?: string) { - if (baseUrl) { - return new URL(req_url, baseUrl).href; - } - - const match = req_url.match(/^(?:(https?:)?\/\/)?(([^\/?]+?)(?::(\d{0,5})(?=[\/?]|$))?)([\/?][\S\s]*|$)/i); - - if (!match) { - return null; - } - - if (!match[1]) { - if (/^https?:/i.test(req_url)) { - return null; + try { + if (baseUrl) { + return new URL(req_url, baseUrl).toString(); } - // Scheme is omitted - if (req_url.lastIndexOf("//", 0) === -1) { - // "//" is omitted - req_url = "//" + req_url; + // If it's already a fully qualified URL + if (/^https?:\/\//i.test(req_url)) { + return new URL(req_url).toString(); } - req_url = (match[4] === "443" ? "https:" : "http:") + req_url; - } - - try { - const parsed = new URL(req_url); - if (!parsed.hostname) { - // "http://:1/" and "http:/notenoughslashes" could end up here - return null; + + // If it starts with // (protocol-relative URL) + if (req_url.startsWith('//')) { + return new URL(`https:${req_url}`).toString(); } - return parsed.href; + + // If it's a relative URL and we have a base URL + if (baseUrl) { + return new URL(req_url, baseUrl).toString(); + } + + return null; } catch (error) { + console.error("URL parsing error:", error, "for URL:", req_url, "with base:", baseUrl); return null; } } @@ -117,21 +109,40 @@ export default async function(request: Request, env: any, ctx: any) { if (line.startsWith("#")) { if (line.startsWith("#EXT-X-KEY:")) { // Proxy the key URL - const regex = /https?:\/\/[^\""\s]+/g; - const keyUrl = regex.exec(line)?.[0]; + const regex = /URI="([^"]+)"/g; + const match = regex.exec(line); + const keyUrl = match ? match[1] : null; + if (keyUrl) { - const proxyKeyUrl = `${baseProxyUrl}/ts-proxy?url=${encodeURIComponent(keyUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; - newLines.push(line.replace(keyUrl, proxyKeyUrl)); + let fullKeyUrl; + try { + // Try to get the full URL + fullKeyUrl = keyUrl.startsWith('http') ? keyUrl : new URL(keyUrl, targetUrl).toString(); + const proxyKeyUrl = `${baseProxyUrl}/ts-proxy?url=${encodeURIComponent(fullKeyUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; + newLines.push(line.replace(keyUrl, proxyKeyUrl)); + } catch (error) { + console.error("Error processing key URL:", keyUrl, error); + newLines.push(line); // Keep original if error + } } else { newLines.push(line); } } else if (line.startsWith("#EXT-X-MEDIA:")) { // Proxy alternative media URLs (like audio streams) - const regex = /https?:\/\/[^\""\s]+/g; - const mediaUrl = regex.exec(line)?.[0]; + const regex = /URI="([^"]+)"/g; + const match = regex.exec(line); + const mediaUrl = match ? match[1] : null; + if (mediaUrl) { - const proxyMediaUrl = `${baseProxyUrl}/m3u8-proxy?url=${encodeURIComponent(mediaUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; - newLines.push(line.replace(mediaUrl, proxyMediaUrl)); + try { + // Try to get the full URL + const fullMediaUrl = mediaUrl.startsWith('http') ? mediaUrl : new URL(mediaUrl, targetUrl).toString(); + const proxyMediaUrl = `${baseProxyUrl}/m3u8-proxy?url=${encodeURIComponent(fullMediaUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; + newLines.push(line.replace(mediaUrl, proxyMediaUrl)); + } catch (error) { + console.error("Error processing media URL:", mediaUrl, error); + newLines.push(line); // Keep original if error + } } else { newLines.push(line); } @@ -140,11 +151,13 @@ export default async function(request: Request, env: any, ctx: any) { } } else if (line.trim()) { // This is a quality variant URL - const variantUrl = parseURL(line, targetUrl); - if (variantUrl) { + try { + // Try to create a full URL + const variantUrl = line.startsWith('http') ? line : new URL(line, targetUrl).toString(); newLines.push(`${baseProxyUrl}/m3u8-proxy?url=${encodeURIComponent(variantUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`); - } else { - newLines.push(line); + } catch (error) { + console.error("Error processing variant URL:", line, error); + newLines.push(line); // Keep original if error } } else { // Empty line, preserve it @@ -164,11 +177,20 @@ export default async function(request: Request, env: any, ctx: any) { if (line.startsWith("#")) { if (line.startsWith("#EXT-X-KEY:")) { // Proxy the key URL - const regex = /https?:\/\/[^\""\s]+/g; - const keyUrl = regex.exec(line)?.[0]; + const regex = /URI="([^"]+)"/g; + const match = regex.exec(line); + const keyUrl = match ? match[1] : null; + if (keyUrl) { - const proxyKeyUrl = `${baseProxyUrl}/ts-proxy?url=${encodeURIComponent(keyUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; - newLines.push(line.replace(keyUrl, proxyKeyUrl)); + try { + // Try to get the full URL + const fullKeyUrl = keyUrl.startsWith('http') ? keyUrl : new URL(keyUrl, targetUrl).toString(); + const proxyKeyUrl = `${baseProxyUrl}/ts-proxy?url=${encodeURIComponent(fullKeyUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`; + newLines.push(line.replace(keyUrl, proxyKeyUrl)); + } catch (error) { + console.error("Error processing key URL:", keyUrl, error); + newLines.push(line); // Keep original if error + } } else { newLines.push(line); } @@ -177,11 +199,13 @@ export default async function(request: Request, env: any, ctx: any) { } } else if (line.trim() && !line.startsWith("#")) { // This is a segment URL (.ts file) - const segmentUrl = parseURL(line, targetUrl); - if (segmentUrl) { + try { + // Try to create a full URL + const segmentUrl = line.startsWith('http') ? line : new URL(line, targetUrl).toString(); newLines.push(`${baseProxyUrl}/ts-proxy?url=${encodeURIComponent(segmentUrl)}&headers=${encodeURIComponent(JSON.stringify(customHeaders))}`); - } else { - newLines.push(line); + } catch (error) { + console.error("Error processing segment URL:", line, error); + newLines.push(line); // Keep original if error } } else { // Comment or empty line, preserve it diff --git a/src/routes/ts-proxy.ts b/src/routes/ts-proxy.ts index 31a53de..8508456 100644 --- a/src/routes/ts-proxy.ts +++ b/src/routes/ts-proxy.ts @@ -16,23 +16,34 @@ export default async function(request: Request, env: any, ctx: any) { }); } - // Parse URL parameters - const url = new URL(request.url); - const targetUrl = url.searchParams.get('url'); - const headersParam = url.searchParams.get('headers'); - - if (!targetUrl) { - return new Response('URL parameter is required', { status: 400 }); - } - - let customHeaders = {}; - try { - customHeaders = headersParam ? JSON.parse(headersParam) : {}; - } catch (e) { - return new Response('Invalid headers format', { status: 400 }); - } - try { + // Parse URL parameters + const url = new URL(request.url); + const targetUrl = url.searchParams.get('url'); + const headersParam = url.searchParams.get('headers'); + + if (!targetUrl) { + return new Response('URL parameter is required', { status: 400 }); + } + + let customHeaders = {}; + try { + customHeaders = headersParam ? JSON.parse(headersParam) : {}; + } catch (e) { + return new Response('Invalid headers format', { status: 400 }); + } + + // Validate the URL + try { + new URL(targetUrl); + } catch (error) { + console.error('Invalid target URL:', targetUrl, error); + return new Response('Invalid target URL', { + status: 400, + headers: { 'Access-Control-Allow-Origin': '*' } + }); + } + // Create request headers const requestHeaders = new Headers({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36', @@ -41,6 +52,10 @@ export default async function(request: Request, env: any, ctx: any) { ...customHeaders }); + console.log('Fetching TS from:', targetUrl); + console.log('With headers:', JSON.stringify(Object.fromEntries(requestHeaders.entries()))); + + // Fetch the TS file const response = await fetch(targetUrl, { method: 'GET', headers: requestHeaders