@warren-bank/hls-proxy 3.4.0 → 3.4.2

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 CHANGED
@@ -136,6 +136,8 @@ options:
136
136
  --tls-cert <filepath>
137
137
  --tls-key <filepath>
138
138
  --tls-pass <filepath>
139
+ --manifest-extension <ext>
140
+ --segment-extension <ext>
139
141
  ```
140
142
 
141
143
  #### Options:
@@ -147,11 +149,15 @@ options:
147
149
  * _--tls-pass_
148
150
  * the values assigned to these options enable the use of a self-signed security certificate that is included in both the git repo and npm package, within the directory:
149
151
  * [`./hls-proxy/servers/cert`](https://github.com/warren-bank/HLS-Proxy/tree/master/hls-proxy/servers/cert)
152
+ * when all of these option are properly specified:
153
+ * the `https:` protocol is used by all URLs in modified HLS manifests
150
154
  * _--host_ is an IP or hostname with an optional port number that can be resolved and is reachable by clients
151
155
  * ex: `192.168.0.100:8080`
152
156
  * used to modify URLs in .m3u8 files
153
157
  * when this option is specified without a port number:
154
158
  * the value of the _--port_ option is appended
159
+ * when this option is specified and the port number is `443`:
160
+ * the `https:` protocol is used by all URLs in modified HLS manifests
155
161
  * when this option is not specified:
156
162
  * the value of the ["Host"](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) HTTP request header is used
157
163
  * _--port_ is the port number that the server listens on
@@ -361,6 +367,10 @@ options:
361
367
  * _--tls-key_ is the filepath to the private key for the _--tls-cert_ security certificate
362
368
  * _--tls-pass_ is the filepath to a text file containing the security passphrase for the _--tls-key_ private key
363
369
  * optional, not required when the _--tls-key_ private key was created without a security passphrase
370
+ * _--manifest-extension_ is the file extension associated with HLS manifests
371
+ * default value: `m3u8`
372
+ * _--segment-extension_ is the file extension associated with media segments
373
+ * default value: `ts`
364
374
 
365
375
  #### Examples:
366
376
 
@@ -595,8 +605,10 @@ curl --silent --insecure "$URL"
595
605
  * m3u8 manifest parser uses regex patterns to identify all URL patterns without any special knowledge of the m3u8 manifest specification
596
606
  * internal `proxy` module exports a function that accepts an instance of [`http.Server`](https://nodejs.org/api/http.html#class-httpserver) and adds event listeners to process requests
597
607
  - system requirements:
598
- * Node.js v6.4.0 and higher
599
- - 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)
608
+ * Node.js version: v8.6.0 (and higher)
609
+ - transitive [dependency](https://github.com/warren-bank/HLS-Proxy/blob/v1.0.1/package.json#L13-L14) requirements:
610
+ * v8.06.00+: [`@warren-bank/node-process-argv`](https://github.com/warren-bank/node-process-argv#requirements)
611
+ * v8.06.00+: [`@warren-bank/node-request`](https://github.com/warren-bank/node-request#requirements)
600
612
  * `v2.x`
601
613
  - commit history is in branch: [`v02`](https://github.com/warren-bank/HLS-Proxy/commits/v02)
602
614
  - summary:
@@ -606,8 +618,10 @@ curl --silent --insecure "$URL"
606
618
  - added to an [`Express.js`](https://github.com/expressjs/express) application as middleware to handle a custom route
607
619
  * important limitation: since `/` is a valid character in a base64 encoded URL, the path for a custom route needs to end with a character that is not allowed in base64 encoding (ex: `'/proxy_/*'`)
608
620
  - system requirements:
609
- * Node.js v6.4.0 and higher
610
- - 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)
621
+ * Node.js version: v8.6.0 (and higher)
622
+ - transitive [dependency](https://github.com/warren-bank/HLS-Proxy/blob/v2.0.3/package.json#L13-L14) requirements:
623
+ * v8.06.00+: [`@warren-bank/node-process-argv`](https://github.com/warren-bank/node-process-argv#requirements)
624
+ * v8.06.00+: [`@warren-bank/node-request`](https://github.com/warren-bank/node-request#requirements)
611
625
  * `v3.x`
612
626
  - commit history is in branch: [`v03`](https://github.com/warren-bank/HLS-Proxy/commits/v03)
613
627
  - summary:
@@ -618,8 +632,12 @@ curl --silent --insecure "$URL"
618
632
  * 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/*'`)
619
633
  * the use of nested routers is supported
620
634
  - system requirements:
621
- * Node.js v16.0.0 and higher
622
- - 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-)
635
+ * Node.js version: v16.0.0 (and higher)
636
+ - transitive [dependency](https://github.com/warren-bank/HLS-Proxy/blob/v3.4.0/package.json#L13-L14) requirements:
637
+ * v8.06.00+: [`@warren-bank/node-process-argv`](https://github.com/warren-bank/node-process-argv#requirements)
638
+ * v8.06.00+: [`@warren-bank/node-request`](https://github.com/warren-bank/node-request#requirements)
639
+ - [ES6 support](http://node.green/)
640
+ * v16.00.00+: [`RegExp` 'd' flag](https://node.green/#ES2022-features-RegExp-Match-Indices---hasIndices-----d--flag-)
623
641
 
624
642
  - - - -
625
643
 
@@ -45,7 +45,9 @@ const middleware = require('../proxy')({
45
45
  cache_storage_fs_dirpath: argv_vals["--cache-storage-fs-dirpath"],
46
46
  debug_level: argv_vals["-v"],
47
47
  acl_whitelist: argv_vals["--acl-whitelist"],
48
- http_proxy: argv_vals["--http-proxy"]
48
+ http_proxy: argv_vals["--http-proxy"],
49
+ manifest_extension: argv_vals["--manifest-extension"],
50
+ segment_extension: argv_vals["--segment-extension"]
49
51
  })
50
52
 
51
53
  if (middleware.connection)
@@ -32,6 +32,8 @@ options:
32
32
  --tls-cert <filepath>
33
33
  --tls-key <filepath>
34
34
  --tls-pass <filepath>
35
+ --manifest-extension <ext>
36
+ --segment-extension <ext>
35
37
  `
36
38
 
37
39
  module.exports = help
@@ -38,7 +38,10 @@ const argv_flags = {
38
38
 
39
39
  "--tls-cert": {file: "path-exists"},
40
40
  "--tls-key": {file: "path-exists"},
41
- "--tls-pass": {file: "path-exists"}
41
+ "--tls-pass": {file: "path-exists"},
42
+
43
+ "--manifest-extension": {},
44
+ "--segment-extension": {}
42
45
  }
43
46
 
44
47
  const argv_flag_aliases = {
@@ -110,7 +110,7 @@ const parse_HHMMSS_to_seconds = function(str) {
110
110
  // prefetch_urls: [],
111
111
  // modified_m3u8: ''
112
112
  // }
113
- const parse_manifest = function(m3u8_content, m3u8_url, referer_url, hooks, cache_segments, debug, vod_start_at_ms, redirected_base_url, should_prefetch_url) {
113
+ const parse_manifest = function(m3u8_content, m3u8_url, referer_url, hooks, cache_segments, debug, vod_start_at_ms, redirected_base_url, should_prefetch_url, manifest_extension, segment_extension) {
114
114
  const m3u8_lines = m3u8_content.split(regexs.m3u8_line_separator)
115
115
  m3u8_content = null
116
116
 
@@ -123,7 +123,7 @@ const parse_manifest = function(m3u8_content, m3u8_url, referer_url, hooks, cach
123
123
  redirect_embedded_url(embedded_url, hooks, m3u8_url, debug)
124
124
  if (validate_embedded_url(embedded_url)) {
125
125
  finalize_embedded_url(embedded_url, vod_start_at_ms, debug)
126
- encode_embedded_url(embedded_url, redirected_base_url, debug)
126
+ encode_embedded_url(embedded_url, redirected_base_url, debug, manifest_extension, segment_extension)
127
127
  get_prefetch_url(embedded_url, should_prefetch_url, prefetch_urls)
128
128
  modify_m3u8_line(embedded_url, m3u8_lines)
129
129
  }
@@ -330,13 +330,23 @@ const finalize_embedded_url = function(embedded_url, vod_start_at_ms, debug) {
330
330
  }
331
331
  }
332
332
 
333
- const encode_embedded_url = function(embedded_url, redirected_base_url, debug) {
334
- embedded_url.encoded_url = (embedded_url.unencoded_url)
335
- ? `${redirected_base_url}/${ utils.base64_encode(embedded_url.unencoded_url) }.${embedded_url.url_type || 'other'}`
336
- : ''
333
+ const encode_embedded_url = function(embedded_url, redirected_base_url, debug, manifest_extension, segment_extension) {
334
+ if (embedded_url.unencoded_url) {
335
+ let file_extension = embedded_url.url_type
336
+ if (file_extension) {
337
+ if (manifest_extension && (file_extension === 'm3u8'))
338
+ file_extension = manifest_extension
339
+ if (segment_extension && (file_extension === 'ts'))
340
+ file_extension = segment_extension
341
+ }
342
+
343
+ embedded_url.encoded_url = `${redirected_base_url}/${ utils.base64_encode(embedded_url.unencoded_url) }.${file_extension || 'other'}`
337
344
 
338
- if (embedded_url.encoded_url)
339
345
  debug(3, 'redirecting (proxied):', embedded_url.encoded_url)
346
+ }
347
+ else {
348
+ embedded_url.encoded_url = ''
349
+ }
340
350
  }
341
351
 
342
352
  const get_prefetch_url = function(embedded_url, should_prefetch_url, prefetch_urls = []) {
@@ -362,7 +372,7 @@ const modify_m3u8_line = function(embedded_url, m3u8_lines) {
362
372
  }
363
373
 
364
374
  const modify_m3u8_content = function(params, segment_cache, m3u8_content, m3u8_url, referer_url, redirected_base_url) {
365
- const {hooks, cache_segments, max_segments, debug_level} = params
375
+ const {hooks, cache_segments, max_segments, debug_level, manifest_extension, segment_extension} = params
366
376
 
367
377
  const {has_cache, get_time_since_last_access, is_expired, prefetch_segment} = segment_cache
368
378
 
@@ -419,7 +429,7 @@ const modify_m3u8_content = function(params, segment_cache, m3u8_content, m3u8_u
419
429
  : null
420
430
 
421
431
  {
422
- const parsed_manifest = parse_manifest(m3u8_content, m3u8_url, referer_url, hooks, cache_segments, debug, vod_start_at_ms, redirected_base_url, should_prefetch_url)
432
+ const parsed_manifest = parse_manifest(m3u8_content, m3u8_url, referer_url, hooks, cache_segments, debug, vod_start_at_ms, redirected_base_url, should_prefetch_url, manifest_extension, segment_extension)
423
433
  is_vod = !!parsed_manifest.meta_data.is_vod // default: false => hls live stream
424
434
  seg_duration_ms = parsed_manifest.meta_data.seg_duration_ms || 10000 // default: 10 seconds in ms
425
435
  prefetch_urls = parsed_manifest.prefetch_urls
@@ -1,56 +1,56 @@
1
- const crypto = require('crypto')
2
- const fs = require('fs')
3
- const path = require('path')
4
-
5
- const {denodeify} = require('@warren-bank/node-request')
6
-
7
- const $fs = {
8
- writeFile: denodeify(fs.writeFile),
9
- readFile: denodeify(fs.readFile),
10
- rm: denodeify(fs.rm)
11
- }
12
-
13
- module.exports = function(dirpath) {
14
-
15
- // synchronous (private)
16
- const get_random_filename = (state) => {
17
- let random_bytes, fname, fpath
18
-
19
- while (true) {
20
- random_bytes = get_random_bytes()
21
- fname = convert_random_bytes_to_filename(random_bytes)
22
- fpath = path.join(dirpath, fname)
23
-
24
- if (!fs.existsSync(fpath)) {
25
- state.fpath = fpath
26
- return
27
- }
28
- }
29
- }
30
-
31
- // synchronous (private)
32
- const get_random_bytes = () => crypto.randomBytes(30)
33
-
34
- // synchronous (private)
35
- const convert_random_bytes_to_filename = (buffer) => buffer.toString('base64').replaceAll('/', '_')
36
-
37
- // async
38
- const set = async (state, blob) => {
39
- get_random_filename(state)
40
-
41
- await $fs.writeFile(state.fpath, blob)
42
- }
43
-
44
- // async
45
- const get = async (state) => {
46
- return await $fs.readFile(state.fpath, {encoding: null})
47
- }
48
-
49
- // async
50
- const remove = async (state) => {
51
- await $fs.rm(state.fpath, {force: true})
52
- delete state.fpath
53
- }
54
-
55
- return {set, get, remove}
56
- }
1
+ const crypto = require('crypto')
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+
5
+ const {denodeify} = require('@warren-bank/node-request')
6
+
7
+ const $fs = {
8
+ writeFile: denodeify(fs.writeFile),
9
+ readFile: denodeify(fs.readFile),
10
+ rm: denodeify(fs.rm)
11
+ }
12
+
13
+ module.exports = function(dirpath) {
14
+
15
+ // synchronous (private)
16
+ const get_random_filename = (state) => {
17
+ let random_bytes, fname, fpath
18
+
19
+ while (true) {
20
+ random_bytes = get_random_bytes()
21
+ fname = convert_random_bytes_to_filename(random_bytes)
22
+ fpath = path.join(dirpath, fname)
23
+
24
+ if (!fs.existsSync(fpath)) {
25
+ state.fpath = fpath
26
+ return
27
+ }
28
+ }
29
+ }
30
+
31
+ // synchronous (private)
32
+ const get_random_bytes = () => crypto.randomBytes(30)
33
+
34
+ // synchronous (private)
35
+ const convert_random_bytes_to_filename = (buffer) => buffer.toString('base64').replaceAll('/', '_')
36
+
37
+ // async
38
+ const set = async (state, blob) => {
39
+ get_random_filename(state)
40
+
41
+ await $fs.writeFile(state.fpath, blob)
42
+ }
43
+
44
+ // async
45
+ const get = async (state) => {
46
+ return await $fs.readFile(state.fpath, {encoding: null})
47
+ }
48
+
49
+ // async
50
+ const remove = async (state) => {
51
+ await $fs.rm(state.fpath, {force: true})
52
+ delete state.fpath
53
+ }
54
+
55
+ return {set, get, remove}
56
+ }
@@ -1,14 +1,14 @@
1
- module.exports = function(params) {
2
- const {cache_storage, cache_storage_fs_dirpath} = params
3
-
4
- if (cache_storage) {
5
- if (cache_storage === 'memory')
6
- return require('./memory')()
7
-
8
- if ((cache_storage === 'filesystem') && cache_storage_fs_dirpath)
9
- return require('./filesystem')(cache_storage_fs_dirpath)
10
- }
11
-
12
- // default
13
- return require('./memory')()
14
- }
1
+ module.exports = function(params) {
2
+ const {cache_storage, cache_storage_fs_dirpath} = params
3
+
4
+ if (cache_storage) {
5
+ if (cache_storage === 'memory')
6
+ return require('./memory')()
7
+
8
+ if ((cache_storage === 'filesystem') && cache_storage_fs_dirpath)
9
+ return require('./filesystem')(cache_storage_fs_dirpath)
10
+ }
11
+
12
+ // default
13
+ return require('./memory')()
14
+ }
@@ -1,17 +1,17 @@
1
- module.exports = function() {
2
-
3
- // async
4
- const set = async (state, blob) => {
5
- state.databuffer = blob
6
- }
7
-
8
- // async
9
- const get = async (state) => state.databuffer
10
-
11
- // async
12
- const remove = async (state) => {
13
- delete state.databuffer
14
- }
15
-
16
- return {set, get, remove}
17
- }
1
+ module.exports = function() {
2
+
3
+ // async
4
+ const set = async (state, blob) => {
5
+ state.databuffer = blob
6
+ }
7
+
8
+ // async
9
+ const get = async (state) => state.databuffer
10
+
11
+ // async
12
+ const remove = async (state) => {
13
+ delete state.databuffer
14
+ }
15
+
16
+ return {set, get, remove}
17
+ }
@@ -17,18 +17,25 @@ const base64_decode = function(str) {
17
17
  }
18
18
 
19
19
  const parse_req_url = function(params, req) {
20
- const {is_secure, host} = params
20
+ const {is_secure, host, manifest_extension, segment_extension} = params
21
21
 
22
22
  const result = {redirected_base_url: '', url_type: '', url: '', referer_url: ''}
23
23
 
24
24
  const matches = regexs.req_url.exec( expressjs.get_proxy_req_url(req) )
25
25
 
26
26
  if (matches) {
27
- result.redirected_base_url = `${ is_secure ? 'https' : 'http' }://${host || req.headers.host}${expressjs.get_base_req_url(req) || matches[1] || ''}`
27
+ result.redirected_base_url = `${ (is_secure || (host && host.endsWith(':443'))) ? 'https' : 'http' }://${host || req.headers.host}${expressjs.get_base_req_url(req) || matches[1] || ''}`
28
28
 
29
- if (matches[3])
29
+ if (matches[3]) {
30
30
  result.url_type = matches[3].toLowerCase().trim()
31
31
 
32
+ if (manifest_extension && (result.url_type === manifest_extension))
33
+ result.url_type = 'm3u8'
34
+
35
+ if (segment_extension && (result.url_type === segment_extension))
36
+ result.url_type = 'ts'
37
+ }
38
+
32
39
  let url, url_lc, index
33
40
 
34
41
  url = base64_decode( decodeURIComponent( matches[2] ) ).trim()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@warren-bank/hls-proxy",
3
3
  "description": "Node.js server to proxy HLS video streams",
4
- "version": "3.4.0",
4
+ "version": "3.4.2",
5
5
  "scripts": {
6
6
  "start": "node hls-proxy/bin/hlsd.js",
7
7
  "sudo": "sudo node hls-proxy/bin/hlsd.js"