1
- import { decodeHeaders } from './utils/handler' ;
1
+ import { handleRequest } from '. ./utils/handler' ;
2
2
3
3
const m3u8ContentTypes = [
4
4
'application/vnd.apple.mpegurl' ,
@@ -11,17 +11,30 @@ const m3u8ContentTypes = [
11
11
'application/x-apple-hls' ,
12
12
] ;
13
13
14
- const videoContentTypes = [
15
- 'video/mp4' ,
16
- 'video/webm' ,
17
- 'video/ogg' ,
18
- 'video/quicktime' ,
19
- 'video/MP2T' ,
20
- 'application/mp4' ,
21
- 'video/x-m4v' ,
22
- ...m3u8ContentTypes ,
23
- ] ;
24
-
14
+ function processM3U8Content ( content , mediaUrl , origin ) {
15
+ return content
16
+ . split ( '\n' )
17
+ . map ( ( line ) => {
18
+ // Process URI attributes in tags
19
+ const uriMatch = line . match ( / ( U R I = ) ( [ " ' ] ) (?< uri > .* ?) \2/ ) ;
20
+ if ( uriMatch ) {
21
+ const [ fullMatch , prefix , quote ] = uriMatch ;
22
+ const resolvedUrl = new URL ( uriMatch . groups . uri , mediaUrl ) . toString ( ) ;
23
+ const proxyUrl = `${ origin } /proxy?url=${ encodeURIComponent ( resolvedUrl ) } ` ;
24
+ return line . replace ( fullMatch , `${ prefix } ${ quote } ${ proxyUrl } ${ quote } ` ) ;
25
+ }
26
+
27
+ // Process segment URLs
28
+ if ( ! line . startsWith ( '#' ) && line . trim ( ) ) {
29
+ const resolvedUrl = new URL ( line . trim ( ) , mediaUrl ) . toString ( ) ;
30
+ const proxyUrl = `${ origin } /proxy?url=${ encodeURIComponent ( resolvedUrl ) } ` ;
31
+ return line . replace ( line . trim ( ) , proxyUrl ) ;
32
+ }
33
+
34
+ return line ;
35
+ } )
36
+ . join ( '\n' ) ;
37
+ }
25
38
async function proxy ( request ) {
26
39
if ( request . method === 'OPTIONS' ) {
27
40
return new Response ( null , {
@@ -36,36 +49,8 @@ async function proxy(request) {
36
49
}
37
50
38
51
try {
39
- const url = new URL ( request . url ) ;
40
- const urlParams = url . searchParams ;
41
- const encodedUrl = urlParams . get ( 'url' ) ;
42
- const headersBase64 = urlParams . get ( 'headers' ) ;
52
+ let [ mediaUrl , decodedHeaders , origin ] = handleRequest ( request ) ;
43
53
44
- if ( ! encodedUrl ) {
45
- return new Response ( '"url" query parameters are required' , {
46
- status : 400 ,
47
- headers : {
48
- 'Access-Control-Allow-Origin' : '*' ,
49
- } ,
50
- } ) ;
51
- }
52
-
53
- const mediaUrl = atob ( decodeURIComponent ( encodedUrl ) ) ;
54
- const decodedHeaders = decodeHeaders ( headersBase64 ) ;
55
-
56
- if ( ! decodedHeaders ) {
57
- return new Response ( 'Invalid headers format. Must be valid base64-encoded JSON.' , {
58
- status : 400 ,
59
- headers : {
60
- 'Access-Control-Allow-Origin' : '*' ,
61
- } ,
62
- } ) ;
63
- }
64
-
65
- const baseUrl = new URL ( mediaUrl ) ;
66
- const basePath = `${ baseUrl . protocol } //${ baseUrl . host } ${ baseUrl . pathname . substring ( 0 , baseUrl . pathname . lastIndexOf ( '/' ) + 1 ) } ` ;
67
-
68
- // Pass through any Range header from the original request
69
54
const rangeHeader = request . headers . get ( 'Range' ) ;
70
55
const fetchHeaders = {
71
56
...decodedHeaders ,
@@ -85,7 +70,7 @@ async function proxy(request) {
85
70
throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
86
71
}
87
72
88
- const contentType = response . headers . get ( 'content-type' ) || 'application/octet-stream' ;
73
+ const contentType = response . headers . get ( 'content-type' ) ;
89
74
const isM3U8 = m3u8ContentTypes . some ( ( type ) => contentType . includes ( type ) ) ;
90
75
91
76
if ( ! isM3U8 ) {
@@ -102,27 +87,8 @@ async function proxy(request) {
102
87
}
103
88
104
89
let responseContent = await response . text ( ) ;
105
- responseContent = responseContent . replace ( / U R I = [ ' " ] ( .* ?) [ ' " ] / , ( _ , url ) => {
106
- const fullUrl = url . startsWith ( 'http' )
107
- ? url
108
- : url . startsWith ( '/' )
109
- ? `${ baseUrl . protocol } //${ baseUrl . host } ${ url } `
110
- : `${ basePath } ${ url } ` ;
111
- return `URI="${ new URL ( request . url ) . origin } /proxy?url=${ encodeURIComponent ( btoa ( fullUrl ) ) } &headers=${ encodeURIComponent (
112
- headersBase64
113
- ) } "`;
114
- } ) ;
115
-
116
- const modifiedBody = responseContent . replace ( / ^ (? ! # ) ( [ ^ \s ] + ) $ / gm, ( match ) => {
117
- const fullUrl = match . startsWith ( 'http' )
118
- ? match
119
- : match . startsWith ( '/' )
120
- ? `${ baseUrl . protocol } //${ baseUrl . host } ${ match } `
121
- : `${ basePath } ${ match } ` ;
122
- return `${ new URL ( request . url ) . origin } /proxy?url=${ encodeURIComponent ( btoa ( fullUrl ) ) } &headers=${ encodeURIComponent ( headersBase64 ) } ` ;
123
- } ) ;
124
-
125
- return new Response ( modifiedBody , {
90
+ responseContent = processM3U8Content ( responseContent , mediaUrl , origin ) ;
91
+ return new Response ( responseContent , {
126
92
headers : {
127
93
'Content-Type' : 'application/vnd.apple.mpegurl' ,
128
94
'Access-Control-Allow-Origin' : '*' ,
0 commit comments