@warren-bank/hls-proxy 3.2.3 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/hls-proxy/expressjs_utils.js +32 -0
- package/hls-proxy/manifest_parser.js +59 -49
- package/hls-proxy/utils.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -600,7 +600,8 @@ curl --silent --insecure "$URL"
|
|
|
600
600
|
* internal `proxy` module exports an Object containing event listeners to process requests that can be either:
|
|
601
601
|
- added to an instance of [`http.Server`](https://nodejs.org/api/http.html#class-httpserver)
|
|
602
602
|
- added to an [`Express.js`](https://github.com/expressjs/express) application as middleware to handle a custom route
|
|
603
|
-
* important
|
|
603
|
+
* important requirement: the path for a custom route needs to include exactly one unnamed [parameter](https://expressjs.com/en/guide/routing.html#route-parameters) that matches the base64 encoded URL and (optionally) a file extension (ex: `'/proxy/*'`)
|
|
604
|
+
* the use of nested routers is supported
|
|
604
605
|
- system requirements:
|
|
605
606
|
* Node.js v16.0.0 and higher
|
|
606
607
|
- required features: [`Proxy` constructor](https://node.green/#ES2015-built-ins-Proxy-constructor-requires-new), [`Proxy` 'apply' handler](https://node.green/#ES2015-built-ins-Proxy--apply--handler), [`Reflect.apply`](https://node.green/#ES2015-built-ins-Reflect-Reflect-apply), [`RegExp` 'd' flag](https://node.green/#ES2022-features-RegExp-Match-Indices---hasIndices-----d--flag-)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const get_full_req_url = function(req) {
|
|
2
|
+
return req.originalUrl || req.url
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const has_req_param = function(req, key) {
|
|
6
|
+
return (req.params && (typeof req.params === 'object') && req.params[key])
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const get_proxy_req_url = function(req) {
|
|
10
|
+
const key = "0"
|
|
11
|
+
return has_req_param(req, key)
|
|
12
|
+
? `/${req.params[key]}`
|
|
13
|
+
: req.url
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const get_base_req_url = function(req) {
|
|
17
|
+
let base_url = ''
|
|
18
|
+
const key = "0"
|
|
19
|
+
|
|
20
|
+
if (req.path && has_req_param(req, key)) {
|
|
21
|
+
base_url = req.baseUrl || ''
|
|
22
|
+
base_url += req.path.substring(0, (req.path.length - req.params[key].length - 1))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return base_url
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
get_full_req_url,
|
|
30
|
+
get_proxy_req_url,
|
|
31
|
+
get_base_req_url
|
|
32
|
+
}
|
|
@@ -16,9 +16,6 @@ const url_location_landmarks = {
|
|
|
16
16
|
'#EXT-X-RENDITION-REPORT:',
|
|
17
17
|
'#EXT-X-DATERANGE:',
|
|
18
18
|
'#EXT-X-CONTENT-STEERING:'
|
|
19
|
-
],
|
|
20
|
-
next_line: [
|
|
21
|
-
'#EXT-X-STREAM-INF:'
|
|
22
19
|
]
|
|
23
20
|
},
|
|
24
21
|
ts: {
|
|
@@ -26,26 +23,20 @@ const url_location_landmarks = {
|
|
|
26
23
|
'#EXT-X-MAP:',
|
|
27
24
|
'#EXT-X-PART:',
|
|
28
25
|
'#EXT-X-PRELOAD-HINT:'
|
|
29
|
-
],
|
|
30
|
-
next_line: [
|
|
31
|
-
'#EXTINF:'
|
|
32
26
|
]
|
|
33
27
|
},
|
|
34
28
|
json: {
|
|
35
29
|
same_line: [
|
|
36
30
|
'#EXT-X-SESSION-DATA:'
|
|
37
|
-
]
|
|
38
|
-
next_line: []
|
|
31
|
+
]
|
|
39
32
|
},
|
|
40
33
|
key: {
|
|
41
34
|
same_line: [
|
|
42
35
|
'#EXT-X-KEY:'
|
|
43
|
-
]
|
|
44
|
-
next_line: []
|
|
36
|
+
]
|
|
45
37
|
},
|
|
46
38
|
other: {
|
|
47
|
-
same_line: []
|
|
48
|
-
next_line: []
|
|
39
|
+
same_line: []
|
|
49
40
|
}
|
|
50
41
|
}
|
|
51
42
|
|
|
@@ -148,63 +139,82 @@ const parse_manifest = function(m3u8_content, m3u8_url, referer_url, hooks, cach
|
|
|
148
139
|
const extract_embedded_urls = function(m3u8_lines, m3u8_url, referer_url, meta_data) {
|
|
149
140
|
const embedded_urls = []
|
|
150
141
|
|
|
151
|
-
|
|
142
|
+
// one of: ['master','media']
|
|
143
|
+
// determined by the detection of either: ['#EXT-X-STREAM-INF','#EXTINF'], respectively
|
|
144
|
+
// until the type is determined, URI lines are ignored (as per the HLS spec)
|
|
145
|
+
let manifest_type = null
|
|
146
|
+
|
|
147
|
+
let m3u8_line, matches, matching_landmark, matching_url
|
|
152
148
|
|
|
153
149
|
for (let i=0; i < m3u8_lines.length; i++) {
|
|
154
|
-
m3u8_line
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
for (let url_type in url_location_landmarks) {
|
|
170
|
-
if (matching_url && (url_location_landmarks[url_type]['same_line'].indexOf(matching_landmark) >= 0)) {
|
|
171
|
-
embedded_urls.push({
|
|
172
|
-
line_index: i,
|
|
173
|
-
url_indices: matches.indices[1],
|
|
174
|
-
url_type: url_type,
|
|
175
|
-
original_match_url: matching_url,
|
|
176
|
-
resolved_match_url: (new URL(matching_url, m3u8_url)).href,
|
|
177
|
-
redirected_url: null,
|
|
178
|
-
referer_url: referer_url,
|
|
179
|
-
encoded_url: null
|
|
180
|
-
})
|
|
181
|
-
break
|
|
150
|
+
m3u8_line = m3u8_lines[i]
|
|
151
|
+
|
|
152
|
+
if (is_m3u8_line_a_blank(m3u8_line) || is_m3u8_line_a_comment(m3u8_line))
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
if (is_m3u8_line_a_tag(m3u8_line)) {
|
|
156
|
+
matches = regexs.m3u8_line_landmark.exec(m3u8_line)
|
|
157
|
+
if (!matches) continue
|
|
158
|
+
matching_landmark = matches[1]
|
|
159
|
+
|
|
160
|
+
if (manifest_type === null) {
|
|
161
|
+
if (matching_landmark === '#EXT-X-STREAM-INF:')
|
|
162
|
+
manifest_type = 'master'
|
|
163
|
+
else if (matching_landmark === '#EXTINF:')
|
|
164
|
+
manifest_type = 'media'
|
|
182
165
|
}
|
|
183
|
-
if (has_next_m3u8_line && (url_location_landmarks[url_type]['next_line'].indexOf(matching_landmark) >= 0)) {
|
|
184
|
-
next_m3u8_line = m3u8_lines[i+1].trim()
|
|
185
166
|
|
|
186
|
-
|
|
187
|
-
|
|
167
|
+
if (meta_data !== null)
|
|
168
|
+
extract_meta_data(meta_data, m3u8_line, matching_landmark)
|
|
188
169
|
|
|
170
|
+
matches = regexs.m3u8_line_url.exec(m3u8_line)
|
|
171
|
+
if (!matches) continue
|
|
172
|
+
matching_url = matches[1]
|
|
173
|
+
|
|
174
|
+
for (let url_type in url_location_landmarks) {
|
|
175
|
+
if (url_location_landmarks[url_type]['same_line'].indexOf(matching_landmark) >= 0) {
|
|
189
176
|
embedded_urls.push({
|
|
190
177
|
line_index: i,
|
|
191
|
-
url_indices:
|
|
178
|
+
url_indices: matches.indices[1],
|
|
192
179
|
url_type: url_type,
|
|
193
|
-
original_match_url:
|
|
194
|
-
resolved_match_url: (new URL(
|
|
180
|
+
original_match_url: matching_url,
|
|
181
|
+
resolved_match_url: (new URL(matching_url, m3u8_url)).href,
|
|
195
182
|
redirected_url: null,
|
|
196
183
|
referer_url: referer_url,
|
|
197
184
|
encoded_url: null
|
|
198
185
|
})
|
|
186
|
+
break
|
|
199
187
|
}
|
|
200
|
-
break
|
|
201
188
|
}
|
|
202
189
|
}
|
|
190
|
+
else {
|
|
191
|
+
// line is a URI
|
|
192
|
+
if (manifest_type === null) continue
|
|
193
|
+
|
|
194
|
+
const url_type = (manifest_type === 'master') ? 'm3u8' : 'ts'
|
|
195
|
+
|
|
196
|
+
embedded_urls.push({
|
|
197
|
+
line_index: i,
|
|
198
|
+
url_indices: null,
|
|
199
|
+
url_type: url_type,
|
|
200
|
+
original_match_url: m3u8_line,
|
|
201
|
+
resolved_match_url: (new URL(m3u8_line, m3u8_url)).href,
|
|
202
|
+
redirected_url: null,
|
|
203
|
+
referer_url: referer_url,
|
|
204
|
+
encoded_url: null
|
|
205
|
+
})
|
|
206
|
+
}
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
return embedded_urls
|
|
206
210
|
}
|
|
207
211
|
|
|
212
|
+
const is_m3u8_line_a_blank = (line) => (!line || !line.trim())
|
|
213
|
+
|
|
214
|
+
const is_m3u8_line_a_comment = (line) => ((line.indexOf('#') === 0) && !is_m3u8_line_a_tag(line))
|
|
215
|
+
|
|
216
|
+
const is_m3u8_line_a_tag = (line) => (line.indexOf('#EXT') === 0)
|
|
217
|
+
|
|
208
218
|
const extract_meta_data = function(meta_data, m3u8_line, matching_landmark) {
|
|
209
219
|
for (let meta_data_key in meta_data_location_landmarks) {
|
|
210
220
|
if (meta_data_location_landmarks[meta_data_key]['same_line'].indexOf(matching_landmark) >= 0) {
|
package/hls-proxy/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const parse_url = require('@warren-bank/url').parse
|
|
2
|
+
const expressjs = require('./expressjs_utils')
|
|
2
3
|
|
|
3
4
|
const regexs = {
|
|
4
5
|
req_url: new RegExp('^(.*?)/([a-zA-Z0-9\\+/=%]+)(?:[\\._]([^/\\?#]*))?(?:[\\?#].*)?$'),
|
|
@@ -20,10 +21,10 @@ const parse_req_url = function(params, req) {
|
|
|
20
21
|
|
|
21
22
|
const result = {redirected_base_url: '', url_type: '', url: '', referer_url: ''}
|
|
22
23
|
|
|
23
|
-
const matches = regexs.req_url.exec(req
|
|
24
|
+
const matches = regexs.req_url.exec( expressjs.get_proxy_req_url(req) )
|
|
24
25
|
|
|
25
26
|
if (matches) {
|
|
26
|
-
result.redirected_base_url = `${ is_secure ? 'https' : 'http' }://${host || req.headers.host}${matches[1] || ''}`
|
|
27
|
+
result.redirected_base_url = `${ is_secure ? 'https' : 'http' }://${host || req.headers.host}${expressjs.get_base_req_url(req) || matches[1] || ''}`
|
|
27
28
|
|
|
28
29
|
if (matches[3])
|
|
29
30
|
result.url_type = matches[3].toLowerCase().trim()
|
package/package.json
CHANGED