Coder Social home page Coder Social logo

hls-proxy's Introduction

HLS Proxy : HTTP Live Streaming Proxy

Basic Functionality:

  • proxy .m3u8 files, and the video segments (.ts files) they internally reference
  • to all proxied files:
    • add permissive CORS response headers
  • to .m3u8:
    • modify contents such that URLs in the playlist will also pass through the proxy

Advanced Features:

  • inject custom HTTP headers in all outbound proxied requests
  • prefetch video segments (.ts files)
  • use a hook function to conditionally decide which video segments to prefetch
  • use a hook function to conditionally redirect URLs in the playlist (before and/or after they're modified to pass through the proxy)
  • use a hook function to conditionally rewrite URLs after they're received by the proxy

Benefits:

  • any video player (on the LAN) can access the proxied video stream
    • including Chromecast
  • prefetch and caching of video segments ahead-of-time makes playback of the video stream very stable
    • solves buffering problems
  • the proxy can easily be configured to bypass many of the security measures used by video servers to restrict access:
    • CORS response headers (to XHR requests)
      • used by web browsers to enforce a security policy that limits which website(s) may access the content
    • HTTP request headers
      • Origin and Referer are often inspected by the server
        • when these headers don't match the site hosting the content, a 403 Forbidden response is returned (in lieu of the requested data)
    • restricted access to encryption keys
      • often times the encrypted video segments (.ts files) are readily available, but the encryption keys are well protected
        • if the keys can be obtained from another source, then a hook function can be used to redirect only those URL requests

URL Format:

  • [example Javascript]: construction of URL to HLS Proxy for video stream
      {
        const proxy_url      = 'http://127.0.0.1:8080'
        const video_url      = 'https://example.com/video/master.m3u8'
        const file_extension = '.m3u8'
    
        const hls_proxy_url  = `${proxy_url}/${ btoa(video_url) }${file_extension}`
      }
  • [example Javascript]: construction of URL to HLS Proxy for video stream w/ "Referer" request header
      {
        const proxy_url      = 'http://127.0.0.1:8080'
        const video_url      = 'https://example.com/video/master.m3u8'
        const referer_url    = 'https://example.com/videos.html'
        const file_extension = '.m3u8'
    
        const hls_proxy_url  = `${proxy_url}/${ btoa(`${video_url}|${referer_url}`) }${file_extension}`
      }
  • [example Bash]: construction of URL to HLS Proxy for video stream
      proxy_url='http://127.0.0.1:8080'
      video_url='https://example.com/video/master.m3u8'
      file_extension='.m3u8'
    
      hls_proxy_url="${proxy_url}/"$(echo -n "$video_url" | base64 --wrap=0)"$file_extension"
  • [example Bash]: construction of URL to HLS Proxy for video stream w/ "Referer" request header
      proxy_url='http://127.0.0.1:8080'
      video_url='https://example.com/video/master.m3u8'
      referer_url='https://example.com/videos.html'
      file_extension='.m3u8'
    
      hls_proxy_url="${proxy_url}/"$(echo -n "${video_url}|${referer_url}" | base64 --wrap=0)"$file_extension"
notes:
  • adding a file extension to the base64 encoded video URL is highly recommended
    • the following file extension values have important significance to indicate the type of file being requested:
      • .m3u8
        HLS manifest
      • .ts
        media segment
      • .key
        encryption key
      • .json
        JSON data
    • though currently,
      • .m3u8
        is the only file extension that receives special treatment
      • all other file types (including those without any file extension) are piped directly to the HTTP response
high-level tools that automate this task:

Installation and Usage: Globally

How to: Install:

npm install --global "@warren-bank/hls-proxy"

How to: Run the server(s):

hlsd <options>

options:
========
--help
--version
--tls
--host <host>
--port <number>
--copy-req-headers
--req-headers <filepath>
--origin <header>
--referer <header>
--useragent <header>
--header <name=value>
--req-options <filepath>
--req-insecure
--req-secure-honor-server-cipher-order
--req-secure-ciphers <string>
--req-secure-protocol <string>
--req-secure-curve <string>
--hooks <filepath>
--prefetch
--max-segments <number>
--cache-timeout <number>
--cache-key <number>
--cache-storage <adapter>
--cache-storage-fs-dirpath <dirpath>
-v <number>
--acl-ip <ip_address_list>
--acl-pass <password_list>
--http-proxy <http[s]://[user:pass@]hostname:port>
--tls-cert <filepath>
--tls-key <filepath>
--tls-pass <filepath>
--manifest-extension <ext>
--segment-extension <ext>

Options:

  • --tls is a flag to start HTTPS proxy, rather than HTTP
    • used as shorthand to automatically configure the following options:
      • --tls-cert
      • --tls-key
      • --tls-pass
    • 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:
    • when all of these option are properly specified:
      • the https: protocol is used by all URLs in modified HLS manifests
  • --host is an IP or hostname with an optional port number that can be resolved and is reachable by clients
    • ex: 192.168.0.100:8080
    • used to modify URLs in .m3u8 files
    • when this option is specified without a port number:
      • the value of the --port option is appended
    • when this option is specified and the port number is 443:
      • the https: protocol is used by all URLs in modified HLS manifests
    • when this option is not specified:
      • the value of the "Host" HTTP request header is used
  • --port is the port number that the server listens on
    • ex: 8080
    • when this option is not specified:
      • HTTP proxy binds to: 80
      • HTTPS proxy binds to: 443
  • --copy-req-headers is a flag to enable the duplication of all HTTP request headers sent to the proxy → to the request made by the proxy to the video server
  • --req-headers is the filepath to a JSON data Object containing key:value pairs
    • each key is the name of an HTTP header to send in every outbound request
  • --origin is the value of the corresponding HTTP request header
  • --referer is the value of the corresponding HTTP request header
  • --useragent is the value of the corresponding HTTP request header
  • --header is a single name:value pair
    • this option can be used multiple times to include several HTTP request headers
    • the pair can be written:
      • "name: value"
      • "name=value"
      • "name = value"
  • --req-options is the filepath to a JSON data Object
  • --req-insecure is a flag to override the following environment variable to disable certificate validation for secure https requests:
  • --req-secure-honor-server-cipher-order is a flag to set the following key in the request options Object to configure the context for secure https requests:
    • {honorCipherOrder: true}
  • --req-secure-ciphers is the value to assign to the following key in the request options Object to configure the context for secure https requests:
    • {ciphers: value}
  • --req-secure-protocol is the value to assign to the following key in the request options Object to configure the context for secure https requests:
    • {secureProtocol: value}
  • --req-secure-curve is the value to assign to the following key in the request options Object to configure the context for secure https requests:
    • {ecdhCurve: value}
  • --hooks is the filepath to a CommonJS module that exports a single JSON Object
    • each key is the name of a hook function
    • each value is the implementation of the corresponding Function
    • hook function signatures:
      • "add_request_options": (url, is_m3u8) => request_options
        • conditionally add HTTP request options
        • inputs:
          • url
            • string URL
          • is_m3u8
            • boolean that indicates whether url will request an HLS manifest
        • return value:
          • Object having attributes that are combined with --req-options and used to send the outbound request to url
      • "add_request_headers": (url, is_m3u8) => request_headers
        • conditionally add HTTP request headers
        • return value:
          • Object containing key:value pairs that are combined with --req-headers
            • each key is the name of an HTTP header to send in the outbound request to url
      • "modify_m3u8_content": (m3u8_content, m3u8_url) => new_m3u8_content
        • conditionally modify the content of .m3u8 files before they are parsed to extract URLs
      • "redirect": (url) => new_url
        • conditionally redirect the URLs encountered in .m3u8 files before they are modified to pass through the proxy
      • "redirect_final": (url) => new_url
        • conditionally redirect the URLs encountered in .m3u8 files after they are modified to pass through the proxy
      • "rewrite": (url) => new_url
        • conditionally rewrite the URLs requested by clients before they are proxied
      • "prefetch": (url) => boolean
        • conditionally decide whether to prefetch video segments on a per-URL basis
        • return value must be a strict boolean type (ie: true or false)
        • otherwise, the default behavior supersedes
          • to only prefetch .ts files
      • "prefetch_segments": (prefetch_urls, max_segments, is_vod, seg_duration_ms, perform_prefetch) => new_prefetch_urls
        • conditionally filter the list of video segment URLs that are pending prefetch, when more than --max-segments are contained in an HLS manifest
        • inputs:
          • prefetch_urls
            • array of string video segment URLs
          • max_segments
            • integer that denotes the max length of the return value
          • is_vod
            • boolean that indicates whether the HLS manifest is for video-on-demand
              • if true:
                • the video is not a live stream
                • the HLS manifest is complete and contains URLs for every video segment that would be needed to play the entire stream from start to finish
          • seg_duration_ms
            • integer that represents the duration (ms) of each video segment in the HLS manifest
          • perform_prefetch
            • function that accepts an array of string video segment URLs, and immediately begins to prefetch all corresponding segments
        • return value:
          • array of string video segment URLs that is a subset of prefetch_urls
            • can be emtpy (ex: when using perform_prefetch)
        • pre-conditions:
          • the length of prefetch_urls is > max_segments
        • post-conditions:
          • the length of the return value array is <= max_segments
      • "request_intervals": (add_request_interval) => {}
        • enables the use of a cookie jar for all outbound HTTP requests
        • adds any number of timers that each execute at individually specified intervals
        • when each timer executes, it is passed an HTTP request client that is preconfigured to:
          • include the request headers that are specified by other relevant options
          • utilize the same cookie jar as all other outbound HTTP requests
            • this allows the implementation of custom logic that may be required by one or more video hosts to periodically refresh or update session cookies
        • an example would better illustrate usage:
            module.exports = {
              request_intervals: (add_request_interval) => {
          
                add_request_interval(
                  0, // run timer once at startup to initialize cookies
                  (request) => {
                    request('https://example.com/login', {username: 'me', password: '12345'})
                  }
                )
          
                add_request_interval(
                  (1000 * 60 * 5), // run timer at 5 minute interval to refresh cookies
                  (request) => {
                    request('https://example.com/heart-beat')
                  }
                )
          
              }
            }
        • more advanced configuration of the call to the HTTP request client is possible
          • the 1st parameter is required, and must be a URL string
          • the 2nd parameter is optional, and can contain POST data
          • the 3rd parameter is optional, and can be used for more advanced configuration options
        • usage of this HTTP request client is documented here
          • specifically, pay careful attention to the signatures for:
            • the latter two input parameters
            • the attributes of the Object that is resolved by the Promise in the return value (if the content of the response is needed)
  • --prefetch is a flag to enable the prefetch and caching of video segments
    • when .m3u8 files are downloaded and modified inflight, all of the URLs in the playlist are known
    • at this time, it is possible to prefetch the video segments (.ts files)
    • when the video segments (.ts files) are requested at a later time, the data is already cached (in memory) and can be returned immediately
  • --max-segments is the maximum number of video segments (.ts files) to hold in each cache
    • this option is only meaningful when --prefetch is enabled
    • a cache is created for each unique HLS manifest URL
      • all of the video segments (.ts files) associated with each distinct video stream are stored in isolation
    • when any cache grows larger than this size, the oldest data is removed to make room to store new data
    • when this option is not specified:
      • default value: 20
  • --cache-timeout is the maximum number of seconds that any segment cache can remain unused before its contents are cleared (to reduce wasted space in memory)
    • this option is only meaningful when --prefetch is enabled
    • when this option is not specified:
      • default value: 60
  • --cache-key sets the type of string used to represent keys in the cache hashtable when logged
    • this option is only meaningful when --prefetch is enabled
    • scope:
      • v0.16.0 and earlier
        • keys in the cache hashtable used this string representation
      • v0.16.1 and later
        • keys in the cache hashtable are full URLs
          • the data structure to cache video segments (.ts files) was updated
          • each unique HLS manifest is associated with a distinct FIFO list that holds --max-segments
          • when a video segment is requested
            • the proxy needs to search every FIFO list for a match
            • when keys in the cache hashtable lose fidelity, collisions can occur and the wrong video segment can be returned
            • full URLs are unique and guarantee correct behavior
    • 0 (default):
      • sequence number of .ts file w/ .ts file extension (ex: "123.ts")
        • pros:
          • shortest type of string
          • makes the log output easiest to read
        • cons:
          • in the wild, I've encountered video servers that assign each .ts file a unique filename that always terminate with the same static sequence number
            • this is a strange edge case, but this option provides an easy workaround
    • 1:
      • full filename of .ts file
    • 2:
      • full URL of .ts file
  • --cache-storage selects a storage adapter that is used to hold the cache of prefetched video segments
    • this option is only meaningful when --prefetch is enabled
    • memory (default):
      • uses RAM
    • filesystem:
      • each video segment is written to a new file within a specified directory
      • filenames are random and unique
  • --cache-storage-fs-dirpath specifies the directory in which to save video segments when using a filesystem-based cache storage adapter
    • this option is only meaningful when --prefetch is enabled and --cache-storage is filesystem
  • -v sets logging verbosity level:
    • -1:
      • silent
    • 0 (default):
      • show errors only
    • 1:
      • show an informative amount of information
    • 2:
      • show technical details
    • 3:
      • show an enhanced technical trace (useful while debugging unexpected behavior)
    • 4:
      • show the content of .m3u8 files (both before and after URLs are modified)
  • --acl-ip restricts proxy server access to clients at IP addresses in whitelist
    • ex: "192.168.1.100,192.168.1.101,192.168.1.102"
  • --acl-pass restricts proxy server access to requests that include a password querystring parameter having a value in whitelist
    • ex: "1111,2222,3333,4444,5555"
  • --http-proxy enables all outbound HTTP and HTTPS requests from HLS-Proxy to be tunnelled through an additional external web proxy server
  • --tls-cert is the filepath to a security certificate to use for HTTPS
  • --tls-key is the filepath to the private key for the --tls-cert security certificate
  • --tls-pass is the filepath to a text file containing the security passphrase for the --tls-key private key
    • optional, not required when the --tls-key private key was created without a security passphrase
  • --manifest-extension is the file extension associated with HLS manifests
    • default value: m3u8
  • --segment-extension is the file extension associated with media segments
    • default value: ts

Examples:

  1. print help
    hlsd --help

  2. print version
    hlsd --version

  3. start HTTP proxy at default host:port
    hlsd

  4. start HTTP proxy at default host and specific port
    hlsd --port "8080"

  5. start HTTP proxy at specific host:port
    hlsd --host "192.168.0.100" --port "8080"

  6. start HTTPS proxy at default host:port
    hlsd --tls

  7. start HTTPS proxy at specific host:port
    hlsd --tls --host "192.168.0.100" --port "8081"

  8. start HTTPS proxy at default host:port and send specific HTTP headers
    hlsd --tls --req-headers "/path/to/request/headers.json"

  9. start HTTPS proxy at default host:port and enable prefetch of 10 video segments
    hlsd --tls --prefetch --max-segments 10

  10. start HTTPS proxy using a non-generic security certificate
    hlsd --tls-cert "/path/to/cert.pem" --tls-key "/path/to/key.pem" --tls-pass "/path/to/pass.phrase"


Installation and Usage: Working with a Local git Repo

How to: Install:

git clone "https://github.com/warren-bank/HLS-Proxy.git"
cd "HLS-Proxy"
npm install

How to: Run the server(s):

# ----------------------------------------------------------------------
# If using a port number >= 1024 on Linux, or
# If using Windows:
# ----------------------------------------------------------------------
npm start [-- <options>]

# ----------------------------------------------------------------------
# https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html
#
# Linux considers port numbers < 1024 to be privileged.
# Use "sudo":
# ----------------------------------------------------------------------
npm run sudo [-- <options>]

Options:

Examples:

  1. print help
    npm start -- --help

  2. start HTTP proxy at specific host:port
    npm start -- --host "192.168.0.100" --port "8080"

  3. start HTTPS proxy at specific host:port
    npm start -- --host "192.168.0.100" --port "8081" --tls

  4. start HTTP proxy at default host:port with escalated privilege
    npm run sudo -- --port "80"

  5. start HTTPS proxy at default host:port with escalated privilege
    npm run sudo -- --port "443" --tls

  6. start HTTP proxy at specific port and send custom "Referer" request header for specific video stream

npm start -- --port "8080"

h_referer='http://XXX:80/page.html'

URL='https://httpbin.org/headers'
URL="${URL}|${h_referer}"
URL=$(echo -n "$URL" | base64 --wrap=0)
URL="http://127.0.0.1:8080/${URL}.json"
# URL='http://127.0.0.1:8080/aHR0cHM6Ly9odHRwYmluLm9yZy9oZWFkZXJzfGh0dHA6Ly9YWFg6ODAvcGFnZS5odG1s.json'
curl --silent "$URL"
  1. start HTTP proxy at specific port and send custom request headers
headers_file="${TMPDIR}/headers.json"
echo '{"Origin" : "http://XXX:80", "Referer": "http://XXX:80/page.html"}' > "$headers_file"
npm start -- --port "8080" --req-headers "$headers_file"

URL='https://httpbin.org/headers'
URL=$(echo -n "$URL" | base64 --wrap=0)
URL="http://127.0.0.1:8080/${URL}.json"
# URL='http://127.0.0.1:8080/aHR0cHM6Ly9odHRwYmluLm9yZy9oZWFkZXJz.json'
curl --silent "$URL"
  1. start HTTPS proxy at specific port and send custom request headers
headers_file="${TMPDIR}/headers.json"
echo '{"Origin" : "http://XXX:80", "Referer": "http://XXX:80/page.html"}' > "$headers_file"
npm start -- --port "8081" --req-headers "$headers_file" --tls -v 1

URL='https://127.0.0.1:8081/aHR0cHM6Ly9odHRwYmluLm9yZy9oZWFkZXJz.json'
curl --silent --insecure "$URL"
  1. start HTTPS proxy at specific port and send custom request headers
h_origin='http://XXX:80'
h_referer='http://XXX:80/page.html'
h_useragent='Chromium'
h_custom_1='X-Foo: 123'
h_custom_2='X-Bar: baz'
npm start -- --port "8081" --origin "$h_origin" --referer "$h_referer" --useragent "$h_useragent" --header "$h_custom_1" --header "$h_custom_2" --tls -v 1

URL='https://127.0.0.1:8081/aHR0cHM6Ly9odHRwYmluLm9yZy9oZWFkZXJz.json'
curl --silent --insecure "$URL"

Observations:

  • when playing the proxied HLS video stream in an HTML5 player in a Chromium web browser (ex: THEOplayer)
    • if the page hosting the HTML5 video player is served from HTTPS:
      • when running only the HTTP proxy server:
        • the XHR requests from the player to the HTTP proxy server raise a security warning (insecure content)
        • the XHR requests get elevated to HTTPS, which are unanswered (since the HTTPS proxy server isn't running)
      • when running only the HTTPS proxy server:
        • the XHR requests from the player to the HTTPS proxy server will silently fail
        • this is because the HTTPS proxy server is using a self-signed security certificate
        • this certificate needs to be (temporarily) allowed
        • once it is, the video stream works perfectly
          • to allow the certificate:
            • browse to a URL hosted by the proxy server ( example )
            • you should see the warning: NET::ERR_CERT_AUTHORITY_INVALID Your connection is not private
            • click: Advanced
            • click: Proceed to 127.0.0.1 (unsafe)
            • done
  • when playing the proxied HLS video stream on a Chromecast
    • the HTTP proxy server works perfectly
    • the HTTPS proxy server doesn't begin playback
      • not sure why..
      • probably has something to do with the Chromecast's browser security policies
      • a more respectable security certificate (ie: more expensive) would probably fix it

Summary of (Rarely) Observed OpenSSL Connection Errors:

  • error:
    ssl3_check_cert_and_algorithm:dh key too small

    1. attempted fix:
      --req-secure-ciphers "AES128-SHA"
  • error:
    SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

    1. attempted fix:
      --req-secure-protocol "SSLv3_method"
      • result:
        Error: SSLv3 methods disabled
      • issue:
    2. attempted fix:
      --req-secure-curve "auto"

Other Projects:

(directly related, but very loosely coupled)
  • Webcast-Reloaded
    • consists of 2 parts:
      1. a Chromium web browser extension (.crx)
        • on each browser tab, it's silently watching the URL of all outbound requests
        • every requested URL matching a regex pattern that identifies it to be a video file is displayed in the modal window that toggles open when the extension's icon is clicked
        • links in this modal window open to URLs of component #2
      2. a static website
        • there is a selection of several HTML5 videos players
          • each is better at some things and worse at others
          • each integrates with a different Chromecast receiver app
        • there is a page to help redirect the intercepted video URL through a local instance of HLS Proxy

Other Projects:

(unrelated, but somewhat similar in scope and purpose)
  • Streamlink
    • notes:
      • this project has way more features, and is way more polished
      • though its main purpose is to transcode online video with ffmpeg and pipe the output into another program, it can be configured to not load a video player and instead start a web server
      • it can strongly support individual websites through single-purpose plugins
      • it can also support streams via direct URLs
        • using URLs from the wild will have mixed results, since cookies and headers and authentication aren't being managed by any plugin
    • docs:
    • binaries:
      • Windows portable
        • minimum system requirements:
          • Windows 7 SP1
          • .NET Framework 4.5
    • usage test:
      • streamlink --player-external-http --player-external-http-port 8080 --default-stream best --http-ignore-env --http-no-ssl-verify --url "https://XXX/video.m3u8"
    • usage test result:

Major Versions:

  • v1.x
    • commit history is in branch: v01
    • summary:
      • m3u8 manifest parser uses regex patterns to identify all URL patterns without any special knowledge of the m3u8 manifest specification
      • internal proxy module exports a function that accepts an instance of http.Server and adds event listeners to process requests
    • system requirements:
  • v2.x
    • commit history is in branch: v02
    • summary:
      • m3u8 manifest parser uses regex patterns to identify all URL patterns without any special knowledge of the m3u8 manifest specification
      • internal proxy module exports an Object containing event listeners to process requests that can be either:
        • added to an instance of http.Server
        • added to an Express.js application as middleware to handle a custom route
          • 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_/*')
    • system requirements:
  • v3.x
    • commit history is in branch: v03
    • summary:
      • m3u8 manifest parser uses special knowledge of the m3u8 manifest specification to contextually identify URLs
      • internal proxy module exports an Object containing event listeners to process requests that can be either:
        • added to an instance of http.Server
        • added to an Express.js application as middleware to handle a custom route
          • important requirement: the path for a custom route needs to include exactly one unnamed parameter that matches the base64 encoded URL and (optionally) a file extension (ex: '/proxy/*')
          • the use of nested routers is supported
    • system requirements:

Legal:

hls-proxy's People

Contributors

warren-bank avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hls-proxy's Issues

Proxy configured to be on a domain, the port blocks further requests

I've setup the proxy to run on port 8080 and the host is targeted at a subdomain.

I can nicely load the manifest file, but every url that it points to after that includes the port in the URL. So instead of proxy.mydomain.com it becomes proxy.mydomain.com:8080 which is an invalid request.

I did a really dirty workaround for now, which was that I modified the host value in start_http.js just to replace the :8080 out of there.

New Install On Ubuntu 18.04

I am getting this error trying to run any commands.
/usr/bin/env: ‘node\r’: No such file or directory

This page isn’t working HTTP ERROR 500

hi sir hope u are will be fine
im getting this issue i cant figure out how to solve
This page isn’t working
192.168.8.100 is currently unable to handle this request.
HTTP ERROR 500

and on the second site i am getting
when i opened in browser
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:770769428
#EXT-X-TARGETDURATION:4
#EXTINF:4.000, no desc
dad0-1313565080_MDL_ap-singapore_634E5F8E000072F08E6D-p0_tmpl360p_360p-1670677956020.ts?utc=1670677956020&pts=371141281800&txl=1670677958764
#EXTINF:4.000, no desc
dad0-1313565080_MDL_ap-singapore_634E5F8E000072F08E6D-p0_tmpl360p_360p-1670677960020.ts?utc=1670677960020&pts=371141641800&txl=1670677962813
#EXTINF:4.000, no desc
dad0-1313565080_MDL_ap-singapore_634E5F8E000072F08E6D-p0_tmpl360p_360p-1670677964020.ts?utc=1670677964020&pts=371142001800&txl=1670677966848
#EXTINF:4.000, no desc
dad0-1313565080_MDL_ap-singapore_634E5F8E000072F08E6D-p0_tmpl360p_360p-1670677968020.ts?utc=1670677968020&pts=371142361800&txl=1670677970844
#EXTINF:4.000, no desc
dad0-1313565080_MDL_ap-singapore_634E5F8E000072F08E6D-p0_tmpl360p_360p-1670677972020.ts?utc=1670677972020&pts=371142721800&txl=1670677974847

when i tried to play its play and stopped immediately

Can you please take a look on my issue

How to deploy this to production

Hi, I have used this Proxy for a couple of days now and works fine with me, But when I try to host it or deploy it into a real word application it doesn't seem to work, I'm using Github Action and Yml to start the proxy using npm start but when I make my Github page and try to navigate to it or test the Proxy with an m3u8 file It redirects me to a notFound page Aka 404.
How can I get it to work on my Github actions what I'm doing wrong and how can I fix the Problem?
Thank you.

Content for Youtube live m3u8 does not pass thru HLS-Proxy

I seen several similar issues reported and tried all the answers but nothing seems to work, so here the following:

I am trying to stream a live Youtube channel and managed to fetch the m3u8 URL for it, and created a HLS-Proxy URL for it like this:

proxy_url='http://localhost:8081'
video_url='https://manifest.googlevideo.com/api/.....some very long url..---.QFbPavapnNEKuwk61I%3D/file/index.m3u8'
file_extension='.m3u8'
hls_proxy_url="${proxy_url}/"$(echo -n "$video_url" | base64 --wrap=0)"$file_extension"

This URL plays well in VLC for example but not Clappr.

When I use it as a src for a HTML5 video element using NPM hls.js library, the content remains pointing to Youtube (googlevideo). Here is how I create/assign the video src:

      if (Hls.isSupported()) {
        var hls = new Hls();
        hls.loadSource(videoSrc); // HLS-Proxy like http://localhost:8081/....
        hls.attachMedia(videodom); // HTML5 video
      }

Once it starts playing, the outgoing connections all point to googlevideo, and I get a CORS error.

What am I doing wrong? I was assuming the content is all going thru the proxy by default. Or is hls.js to blaim?

Server start command:

npm start -- --port "8081" --host "localhost" --prefetch --max-segments 10 -v 4

  • output attached-

Curl response YT URL https://manifest.googlevideo.com/api/manifest/hls_variant/....

curl -I "$hls_proxy_url"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
Content-Type: application/x-mpegURL

Connection: keep-alive
Keep-Alive: timeout=5

Also attached the master m3u8 for reference.

Thank you! Great project and documentation ! Perfect to learn the game.

SkyNewsLive-index.zip

out.log

protection feature for generateing hls proxy playlist.

I hope there is a protection feature so that other people cannot generate their own construction to proxy HLS. I installed hls proxy on the internet webserver. for example, there is password verification when running construction to generate hls proxy. Is it possible?

403 forbidden when requesting video with same YT ID multiple times

Hi, when I request a video multiple times it happens 'often', not always, the response is a 403 forbidden.

I am not sure where the cause or the solution lies. Can someone please shine some light and if possible locate where to patch this mf?

Opening proxy URL pure in browser seems to be ok always. Is there some cleanup to be done in HLS-proxy? Example video ID = 9xwazD5SyVg

Thank so much!

CORS problem

Hello,

I'm trying to make a webpage where im using HLS.js in the browser to play live streams from different URLS on the webpage.

The problem is that if the user enters a URL to a live stream that is on a different server from my website, i get a CORS error.

Lets say i want to watch a live YouTube video (just an example). I give HLS.js in the browser the link to the YouTube stream. HLS.js will go directly to YouTube causing a CORS error immediately because the browser its not on YouTube website its on my site at the moment.

Do you have any idea how to fix this problem with the proxy? Or using some other way?
Thanks

Use in React Native mobile project

Do you think it possible to use this in a React Native project for mobile? I've tried embedding this project using nodejs-mobile-react-native but it doesn't seem to work. Any advice/guidance would be greatly appreciated.

Run proxy from a subfolder

I would like to use this proxy on an existing website. I'm not allowed to open additional ports. So I was thinking to proxy incoming requests via our webserver to this HLS proxy. This seems to be possible by specifying the host and port in the --host option (as said here).

As I want to offer the website and the HLS proxy on the same host:port, I would need to run this HLS proxy from a sub folder.

https://host:443/proxy/* --> webserver --> HLS proxy on port 8080
https://host:443/* --> webserver --> website

Is this possible?

(request for feature) Option to prefetch data into disk (instead of memory)

First of all, thanks a lot for all your great job, it's awesome and I use it everyday ;-)

This issue is just a request for feature about the prefetch option.
The prefetch option works fine by using the memory but I have some case in which I'm limited with the memory but want to benefit from the prefetch option.
So I think it would be great to have an option to be able to prefetch on disk

Using HTTPS - key/cert file

Hi there,

First off - thanks so much for this project! It comes in very handy! 👍💯

Can you kindly provide an example of how to pass a key/cert for HTTPS?

I need to use --req-options and give it a filename of a JS file that modifies the options object, right?

I'm trying...

--tls --host "myhost.hostname.com:443" --port "3005" --req-options "/path/to/the/file/options.js"

And in options.js I have...

var options = {
  key: fs.readFileSync('/path/to/privkey.pem'),
  cert: fs.readFileSync('/path/to/cert.pem')
};

I think I missing something though, as this does not work?

Thank you very much. :-)

How to make this work in website?

As mentioned in the repo, "host must be an IP address of the server on the LAN". Is it possible to configure secured host(SSL domains) and use this feature for live streaming on own website? I have very little idea on how everything works here. Any suggestions?

How to limit segment on playlist.

sometimes live video streaming has 2k segments in the playlist. The advantage is that the video can be rewinded. however the m3u gets very large at around 1MB. I want it to only have 5 or 6 segments, is that possible?

Proxy retrieves parent HLS file but redirects none of the children

Hi, when working with your proxy I've come across a issue...

Lets use the playlist from #8 for an example

So lets say I were to try to get https://www.cbsnews.com/common/video/cbsn_header_prod.m3u8 from CBS news through the proxy...
The URL I get is: http://127.0.0.1:8000/aHR0cHM6Ly93d3cuY2JzbmV3cy5jb20vY29tbW9uL3ZpZGVvL2Nic25faGVhZGVyX3Byb2QubTN1OA==.m3u8

Now when fetching this... I get the response back

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=581169,RESOLUTION=640x360,FRAME-RATE=29.970,CODECS="avc1.4D401E,mp4a.40.2"
http://127.0.0.8:8000/aHR0cHM6Ly9jYnNuLXVzLmNic25zdHJlYW0uY2JzbmV3cy5jb20vb3V0L3YxLzU1YTg2NDhlOGYxMzRlODJhNDcwZjgzZDU2MmRlZWNhL21hc3Rlcl8xMS5tM3U4.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=264369,RESOLUTION=320x180,FRAME-RATE=29.970,CODECS="avc1.4D400D,mp4a.40.2"
http://127.0.0.8:8000/aHR0cHM6Ly9jYnNuLXVzLmNic25zdHJlYW0uY2JzbmV3cy5jb20vb3V0L3YxLzU1YTg2NDhlOGYxMzRlODJhNDcwZjgzZDU2MmRlZWNhL21hc3Rlcl8xMi5tM3U4.m3u8

This all works fine... but, when trying to request any of the other URLs inside the playlist I just receive connection timeouts
image
image
I've tried turning on debugging mode 3, and received this in my console:

HTTP server is listening at: 127.0.0.8:8000
proxying (raw): /aHR0cHM6Ly93d3cuY2JzbmV3cy5jb20vY29tbW9uL3ZpZGVvL2Nic25faGVhZGVyX3Byb2QubTN1OA==.m3u8

proxying: https://www.cbsnews.com/common/video/cbsn_header_prod.m3u8

m3u8: true

modify (raw): {
  match: '\n' +
    'https://cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/master_11.m3u8\n',
  head: '\n',
  abs_path: 'https://',
  rel_path: 'cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/',
  file_name: 'master_11',
  file_ext: '.m3u8',
  tail: '\n'
}

redirecting: https://cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/master_11.m3u8

redirecting (proxied): http://127.0.0.8:8000/aHR0cHM6Ly9jYnNuLXVzLmNic25zdHJlYW0uY2JzbmV3cy5jb20vb3V0L3YxLzU1YTg2NDhlOGYxMzRlODJhNDcwZjgzZDU2MmRlZWNhL21hc3Rlcl8xMS5tM3U4.m3u8

modify (raw): {
  match: '\n' +
    'https://cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/master_12.m3u8',
  head: '\n',
  abs_path: 'https://',
  rel_path: 'cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/',
  file_name: 'master_12',
  file_ext: '.m3u8',
  tail: ''
}

redirecting: https://cbsn-us.cbsnstream.cbsnews.com/out/v1/55a8648e8f134e82a470f83d562deeca/master_12.m3u8

redirecting (proxied): http://127.0.0.8:8000/aHR0cHM6Ly9jYnNuLXVzLmNic25zdHJlYW0uY2JzbmV3cy5jb20vb3V0L3YxLzU1YTg2NDhlOGYxMzRlODJhNDcwZjgzZDU2MmRlZWNhL21hc3Rlcl8xMi5tM3U4.m3u8

Do you have any idea why this is happening? Does it have something to do with the fact that I'm using hls.js? Or is this an internal error? Or maybe its just me. Any help is appreciated, thanks.

Handling reauth of a channel m3u that redirects to a CDN back-end?

You seem to be open to exploring new use cases, how about this one? I'm currently using https://www.hls-proxy.com/ and looking for an alternative since it can't handle this.

I've been doing some testing and noticed that my provider requires regular re-auth of the stream to keep it alive.

The channel M3U URL looks like this inside the master playlist:
https://tvnow.best/api/stream/username/password/livetv.epg/channel.name.m3u8

When you GET it you receive a 301 redirect to something like this which is hosted on cloudflare:
https://183-81-168-251.servers.party:5052/live22/DnUJ1vfuNxq-KIzI2GFbvw/312330/1706784248/3041567.m3u8

After an amount of time, the cloudflare servers throw a 410 error or 403 error when you try to GET the M3U or the .ts files and the stream drops. If you re-call the channel level m3u you are happily redirected to the content and can resume playing it.

Any chance you would be interested in adding this type of error handling / channel source resume functionality into your proxy?

Access controls

Thanks for this project! I'm trying it out as a proxy for geogated TV streams (so that I can watch free TV channels from my home country while living abroad) and it's working quite well for that use case.

I was wondering if there's currently any option for access controls, such as being able to use Basic authentication (username + password) or restrict connections so they can only come from particular IP addresses. I'd like to restrict my instance so that only I can connect to it.

I'm happy to look through the code and send a pull request if this is not currently available, just wanted to check first :)

Also, can you confirm that the proxy doesn't use any bandwidth if it's not actively being used (assuming prefetching is disabled)? I'd like to leave it running 24/7 but don't want it to keep consuming streams after I disconnect my client.

Thanks!

HLS with mp4 media segment

The program work fine on HLS with .ts media segment

But it not work on HLS using .mp4 media segment. How to handle this?

Thanks.

Fails to modify m3u8 content when server doesn't response with a "content-encoding" header

Firstly, thanks for such an excellent package and all the work you have put into this @warren-bank

After spending some time (and failing!) to get my my m3u8 file to proxy correctly, I spent some time debugging it and found that if a response doesn't include a content-encoding header the response just returns empty, This empty response then stops the modify_m3u8_content function from modifying the contents to prepend the proxied URL.

I was hoping to fix it myself, but alas my node stream skills aren't very good so I have spent a few hours failing.

The issue isn't your library really, just poorly implemented server responses. But the issue occurs here in your request package

Update
Things I tried when fixing myself:

  • if the response has no content-encoding, return data.toString('utf-8'). This however just resulted in the data printing [object Object]
  • Creating a transform stream as an decoder (default in the case statement if the content-encoding is emtpy). But this just seemed to output the Transform stream object when attempting to get the data out

Dedicated bandwidth downstream to improve player experience

Warren - Thank you for the code and detailed readme. I am briefly exploring proxies and wanted to ask whether this repository addresses what I am looking for:
I am pushing adaptive .ts chunks to a browser via cdn.
I want to further improve the player experience through dedicating bandwidth to the downstream connection from server to client player. I.e. less drop outs, less buffering.
Especially with multiple parallel .ts streams.
Will this proxy help?

prefetch vs. adaptive bitrate

lets use an example to describe this interesting conundrum..

  • master.m3u8 includes sub-manifests for various video resolutions:
    • 320x180.m3u8
    • 384x216.m3u8
    • 512x288.m3u8
    • 640x360.m3u8
    • 960x540.m3u8
    • 1280x720.m3u8
  • --prefetch is enabled, --max-segments is some integer N
    • each sub-manifest is requested, downloaded, and parsed
      • each contains a list of video segments (.ts files)
      • the newest N segments are prefetched and stored in cache
    • if there are X sub-manifests, then a maximum of X*N video segments will begin to download
    • only N segments can be held in cache
      • (X-1)*N video segments will be added-to and very quickly ejected-from cache, as subsequent downloads complete
        • when requested, these URLs will miss the cache

what to do?..

  • a better video player might provide the option to choose a particular video resolution
    • the player should refrain from ever downloading sub-manifests that correspond to the other available but unwanted resolutions
    • HLS-Proxy would never download or parse these extraneous .m3u8 files
      • the video segments they contain would never prefetch
      • the cache would never be overrun by video segments encoded at unwanted resolutions
  • another option is to manually choose one of the sub-manifests
    • for example, a 360p stream could be proxied with prefetch by loading the file (at the relative URL): 640x360.m3u8
  • yet another option is to use the --hooks "redirect" function
    • detect URLs of unwanted sub-manifests (.m3u8 files) and conditionally remove them by returning a falsy value
      • the manifests that correspond to unwanted resolutions would never download
      • consequently, their contents would never be parsed.. and the video segments they contain would never prefetch

stay tuned..

Matching using tvg-id instead of tvg-name

Hi guys - Is there any way HLS-Proxy could be setup to match M3U playlists to an EPG using the tvg-id tag instead of tvg-name.

The reason for this is that I like to create my own M3U's from my IPTV provider and prefer to rename the channels (as the ones from my provider are prefixed with the country name etc)

Many thanks

Multiple Streams

Hello. on 127.0.0.1:3000 i have a nodejs app that grabs tokens for some streams, accesible like 127.0.0.1:3000/channel1,127.0.0.1:3000/channel2 and so on
My question is, how could i proxy all of them?

embed in express app?

I tried modifying your code a bit to be able to embed it within an existing express app. I ran into some issues with the regexes not working and ended up rolling my own quick and dirty solution.

Can you help me understand some of the complexity in the proxy code? My implementation below works well for my fairly particular use case (bypassing CORS restriction) but I wanted to better understand how this might fail in more complicated scenarios that your code presumably is built to handle.

app.get("/proxy/", async function(req, res, next) {
  const protocol = req.protocol;
  const host = req.get("Host"); // host with port
  const source = req.query.url;
  console.log(`proxying ${source}`);
  const agent = stalker.agent;
  const headers = {
    "User-Agent": "Lavf/56.36.100",
    "Icy-Metadata": 1
  };
  const response = await fetch(source, { agent, headers });
  if (source.includes("m3u8?token=")) {
    const text = await response.text();
    const newTextBuilder = [];
    for (line of text.split("\n")) {
      if (line.includes("m3u8?token=") || line.includes("ts?token=")) {
        const parent = source
          .split("/")
          .slice(0, -1)
          .join("/");
        newTextBuilder.push(
          `${protocol}://${host}/proxy/?url=${parent}/${line}`
        );
      } else {
        newTextBuilder.push(line);
      }
    }
    const newText = newTextBuilder.join("\n");
    const responseHeaders = Object.fromEntries(
      Object.entries(response.headers.raw()).map(([k, v]) => [k, v[0]])
    );
    res.set({
      "Content-Type": responseHeaders['content-type']
    });
    try {
      res.send(newText);
    } catch (e) {
      console.error(e);
      console.log(newText);
    }
  } else {
    response.body.pipe(res);
  }
});

P.S. The m3u8 regex was failing on http://11.111.111.111:9999/AajTak/index.m3u8?token=8e55714a60ec4b14a536720df79355ab. Didn't debug much farther than that.

Cache of live streams

Hey, great project guys !

One question:
Does this proxy reduce the outgoing connections to the video source to 1 ?

We have a live streaming event (not a VOD) and we have a data source. Now we have 1000 visitors who view the live stream through our proxy.
Will the proxy do 1000 connections to the data source?
Or will it only do a single connection and stream the received data to the 1000 visitors?

Thanks a lot for clarifying !

Proxy doesn't work!!

When starting the proxy using hlsd command it says that it hosted on 80 port by default but it's impossible to navigate to it, and when I try to change it using hlsd --port 8080 it logs that it's been changed But looks like http://127.0.0.1:8080/ is not even hosted!. NVM, I'm dumb.

Doesn't Support extended URL with hmac Info

Using the proxy

How do you use this proxy to stream a m3u8 url. i've installed the proxy globally and started the proxy using the command + allowed ports in the firewall. but how do i use my m3u8 url to use this proxy ?

Some memory leak is happening

Screenshot 2024-02-17 at 12 37 44 PM Seems like some memory leak is happening. Using V3 branch, Started with `npm start` without any other configuration. Need help :)

How to do performance tuning

I tested 100 clients, the proxy server can't process new request smoothly, the CPU and network workload is not high.
If I have 5000 clients to watch a video with 2M bitrate, could HLS-Proxy do this job good?

test script:

#!/bin/sh
for i in `seq 11 100`; do \
   tag=$(printf "%04d" $i); \
   echo $tag; \
   (while true; do \
      ffmpeg -user-agent stat_$tag \
      -i http://ip/some.m3u8 -c copy \
      -flags +global_header -f null /dev/null 2>&1 \
      | stdbuf -i0 -o0 -e 0 tr -s '\r' '\n' \
      | stdbuf -i0 -o0 -e 0 \
      gawk '{ print strftime("[%Y-%m-%d %H:%M:%S.%s]"), $0 }' \
      >>log_$tag ; \
      sleep 2; \
      echo "RESTART----------" >> log_$tag ;
   done &); \
done

use node-fetch instead of Request()

Hello! I need to pass additional headers to access a playlist, and I recon its not possible with you request module.
Can you please make a version of proxy.js that uses fetch.
You project is very helpful, it would be great if the request headers are preserved while proxying the requests.

Thanks in advance.

Accelerating HLS via CDN?

Hi,

Is it possible to use a CDN to accelerate or cache live streams proxied by HLS proxy? I tried pointing a CDN to the server I've installed HLS-Proxy on and tried accessing the new link but I'm unable to access it somehow.

If it's possible, what would be the steps to get CDN working?

Thank You!

MAC address controll in the proxy?

Thank you for this program. I have a device purchased from a service provider that only allow connections based on the mac address. Would it be possible to use this proxy with that device?

Links not rewritten when #EXTINF out of order

Hello, thank you for your program!
I am currently fighting with an HLS server that serves m3u8 lists like this one:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:20934918
#EXTINF:6.0000,
#EXT-X-PROGRAM-DATE-TIME:2022-12-22T05:58:45.714499+00:00
https://some.site.com/abc/xyz/1671688725.ts

When hls-proxy encounters this file the link ends up not being rewritten, possibly because it does not directly follow the #EXTINF line. If I create a test m3u8 in which these two lines are swapped, all works:

#EXT-X-PROGRAM-DATE-TIME:2022-12-22T05:58:45.714499+00:00
#EXTINF:6.0000,
https://some.site.com/abc/xyz/1671688725.ts

This is unfortunately preventing me from using hls-proxy, since all of the links in the proxied list remain unchanged.
Thanks!

View Proxy Requests

When I am using the proxy to load a m3u8 playlist, my end client ends with a blank screen. Is there a way to view the requests & responses from the http server that hls-proxy runs on to see what the requests & response codes look like in real time? I have charles/burp but clearly do not get the requests being made from the http server itself.

This blank screen is only happening on a certain stream. Others come through without issue. Thanks!

with cloudflare workers

Thanks for your project, this is so useful.
Is it possible to make this work on cloudflare workers?

streams stop after 2 minutes under specific condition

hi!
first of all, thanks so much for creating and maintaining this plugin, I love it so much, it has helped me a ton!

i am currently experiencing a quite specific issues i am not even sure is hls-proxys fault.

i use hls-proxy to inject the http-referrer of a website into their hls-streams.
thing is, this works perfectly fine for VLC, as well as iOS (IPTV Streamer) and Android (M3U IPTV).

it just doesn't work (correctly) on M3U IPTV (same developer as the Android-app) for my Samsung Tizen TV. when i start the proxied streams on my tv, they work for exactly 2 minutes and then stop, with the tv-app saying something along the lines of the stream has gone offline.

do you have an idea if i can fix that via a hls-proxy setting. already tried to contact the app-developer, but he didn't react to my question.

i'm running hls-proxy with sudo hlsd --port 8082 -v 4 --referer http://www.WEBSITE.com/ &

thanks a lot!

Can't start "SyntaxError: Invalid regular expression flags"

Hey whe i wanna run it on latest version i get that error:

> @warren-bank/[email protected] sudo
> sudo node hls-proxy/bin/hlsd.js

/home/hlsproxy/HLS-Proxy/hls-proxy/manifest_parser.js:8
  m3u8_line_url:       /URI=["']([^"']+)["']/id
                       ^

SyntaxError: Invalid regular expression flags
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/home/hlsproxy/HLS-Proxy/hls-proxy/proxy.js:3:17)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
npm ERR! code 1
npm ERR! path /home/hlsproxy/HLS-Proxy
npm ERR! command failed
npm ERR! command sh -c sudo node hls-proxy/bin/hlsd.js

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2022-12-15T16_49_12_055Z-debug.log

ip restrictions

Hello,
Your project be awesome!
Will this repo handle IP restrictions? i have an m3u8 channel but it limits the use to 2 devices per ip address. Can you get around this? Can you somehow add support for SOCKS proxy or something like that?

example link: http://r.faola.li/6428/video.m3u8?token=K8C3Dt1DXA

Best Regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.