warren-bank / HLS-Proxy

Node.js server to proxy HLS video streams
http://webcast-reloaded.surge.sh/proxy.html
GNU General Public License v2.0
238 stars 68 forks source link

View Proxy Requests #18

Open bhanna98 opened 1 year ago

bhanna98 commented 1 year ago

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!

warren-bank commented 1 year ago

Hi. Using -v 1 or higher, this will print the URL of every request being made by the proxy to the video server. If the response status code isn't in the 200-300 range, then this will print the response. If the response is successful, then you're correct.. there isn't currently any log statement to print the full content. If the request is for a video segment, then the response is piped to the socket.. and it wouldn't make any sense to read from the stream anyway. If, however, the request is for a m3u8 manifest.. then yes, I'd agree that it should be possible to see the full m3u8 content (both the original value as received from the server, as well as the modified value after the URLs have been rewritten to be directed through the proxy). I'll add 2x additional log statements to do this.. that will require a higher verbosity level (ie: -v 4) to be enabled. Would this satisfy your needs?

update: v0.20.2 adds these log statements, which are displayed when using -v 4 or higher.

bhanna98 commented 1 year ago

thank you!

bhanna98 commented 1 year ago

@warren-bank Updated but still having issues. I think I have it pinpointed but not sure if I am right or not with my theory. Are you on discord or any platform to discuss my current issue?

warren-bank commented 1 year ago

Sorry, no.. I'm not on any social/chat sites.. I'm fairly anti-social, but if you'd like to post the URL for a manifest that isn't proxying well.. I'll give it a quick look and identify the issue.

bhanna98 commented 1 year ago

As it turns I don't think it is an issue with the manifest.. I have been overlooking the fact that it is encrypted with Sample-AES encryption. If you still want to look, I can paste it in here

bhanna98 commented 1 year ago

@warren-bank This is the url FWIW dcs-live-uc1.mp.lura.live/server/play/m10rvaXGcos8a0gx/rendition.m3u8?track=video-3&anvsid=m177626904-nae80564d887cda81645dfbafb7b9bbdf&ts=1667246194

warren-bank commented 1 year ago

observations..

bhanna98 commented 1 year ago

I thought that was the key but was unsure as I couldn’t find and documentation on the manifest parameters for Apple FairPlay DRM. I know that certain DRM is troublesome according to most…  any browsers that you could point me towards that would be compatible? I’ll keep searching in the mean time.

warren-bank commented 1 year ago

I'd guess that Safari would be able to play this.. since:

but.. I don't know for certain; the only way to know for sure is to try playing the unproxied manifest URL and see what happens. If the unproxied manifest can play, then the proxied manifest (after I've fixed the above issue) should also play.

bhanna98 commented 1 year ago

@warren-bank I just put it in my iPhone and it played an Ad that was currently live in the player on my test device. See the pasted manifest & headers below. What I can assume from this is that it played the "targeting" .ts video fine because that did not have DRM (see key value is also now set to "none"). Once it kicked back into the content delivered from the 0300801-mp-lura-live.ctl domain was when I got a black screen.

HTTP/1.1 200 OK Server: nginx Date: Mon, 31 Oct 2022 22:50:39 GMT Content-Type: application/x-mpegURL Access-Control-Allow-Origin: Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: Cache-Control: max-age=0, no-cache, no-store Content-Range: X-Anv-Ver: ~~ x-akta-zone: projects/21396452285/zones/us-central1-c x-akta-locator: dcs-live-prod-us-central1-1-p7np.us-central1-c.c.m-600-2.internal X-Anv-Auth-Status: valid x-lura-scmod: 1 X-Anvato-Session: session token x-node-header-x-anvato-session: session token X-Anvato-StreamId: stream id X-Anvato-TTS: 72.57, 66.54, 58.53, 50.52, 42.51, 36.51, 31.37, 25.36, 19.39, 13.38, 7.38, 1.37, -4.63, -10.64, -16.61 x-anv-atb: a - 2096000 - 2264000 Content-Encoding: gzip Vary: Accept-Encoding Via: 1.1 google Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 Transfer-Encoding: chunked Connection: keep-alive

EXTM3U

EXT-X-VERSION:6

EXT-X-TARGETDURATION:10

EXT-X-MEDIA-SEQUENCE:1678

EXT-X-DISCONTINUITY-SEQUENCE:111

EXT-X-INDEPENDENT-SEGMENTS

EXT-X-KEY:METHOD=NONE

EXTINF:8.000,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=0%3Amid&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FC6EF730EC751426AABC59061BE74D58B%2F2200000%2Fsegment-3.ts

EXTINF:6.033,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=0%3Atq%2C0%3Acom&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FC6EF730EC751426AABC59061BE74D58B%2F2200000%2Fsegment-4.ts

EXT-X-DISCONTINUITY

EXTINF:8.008,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=1%3Aimp%2C1%3Ast&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FD8023B0EF62F4C088A682FC2E896DF44%2F2200000%2Fsegment-1.ts

EXTINF:8.008,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=1%3Afq&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FD8023B0EF62F4C088A682FC2E896DF44%2F2200000%2Fsegment-2.ts

EXTINF:8.008,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=1%3Amid&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FD8023B0EF62F4C088A682FC2E896DF44%2F2200000%2Fsegment-3.ts

EXTINF:6.006,

https://dcs.mp.lura.live/targeting/analytics?stid=m10rvaXGcos8a0gx&act=3pt&tid=9CB3364427934FBFA837F5F9E1F30846&cues=1%3Atq%2C1%3Acom&url=https%3A%2F%2Fdcs-mcdn.mp.lura.live%2Fprod%2Fv18%2Fmedia%2FD8023B0EF62F4C088A682FC2E896DF44%2F2200000%2Fsegment-4.ts

EXT-X-DISCONTINUITY

EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://64899139cb88843cbf786be10915bdfd",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"

ANVATO-SEGMENT-INFO: type=master

EXTINF:5.139,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221492.ts?nva=1667260207&token=07a5d82a84f2828510a2e

ANVATO-SEGMENT-INFO: type=master

EXTINF:6.006,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221493.ts?nva=1667260213&token=0c4dfa7566abc2b4462b6

ANVATO-SEGMENT-INFO: type=master

EXTINF:5.973,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221494.ts?nva=1667260219&token=0100bcd1f5d86aa0fbb17

ANVATO-SEGMENT-INFO: type=master

EXTINF:6.006,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221495.ts?nva=1667260225&token=060bfdae60a0b569db46f

ANVATO-SEGMENT-INFO: type=master

EXTINF:6.006,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221496.ts?nva=1667260231&token=086911400d5b4660fa1a3

ANVATO-SEGMENT-INFO: type=master

EXTINF:6.006,

https://o300801-mp-lura-live.ctl._redacted_.com/live/ephemeral/54AVmb0klx0KCyCYkFbJwmEle6YKX2NE/nfln-la3/2096k/C1iAPLFPDLQ/169221/segment_169221497.ts?nva=1667260237&token=0d907bba1313fb99ec073

ANVATO-NODE:177619163

ANVATO-SESSION-ID: session token

ANVATO-CDN-PROVIDER: level3

warren-bank commented 1 year ago

v0.20.3 is pushed to npm and updates the regex to prevent any change to the KEYFORMAT.

so.. to summarize.. if the manifest uses FairPlay DRM (w/ skd: key URIs), then the info will just pass through the proxy without any changes. If the video player supports FairPlay DRM and knows what to do with this info.. then it should play exactly the same as it would have done without using any proxy.

warren-bank commented 1 year ago

PS: the structure of that long manifest can be summarized as..

#EXTM3U

#EXT-X-KEY:METHOD=NONE
#EXTINF:45.000,
45sec-of-unencrypted-video-segments.ts

#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://64899139cb88843cbf786be10915bdfd",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"
#EXTINF:5.000,
long-duration-of-encrypted-video-segments.ts

takeaways:

bhanna98 commented 1 year ago

is there a way to include a cookie in the http request? if I wanted to add hdntl=exp=1667527250~acl=%2f*~data=hdntl~hmac=96b3c088fe1fbfd288a27f876bab996670ea146bfd6eee8ca79ed066aca834e0 this cookie what would the format look like?

warren-bank commented 1 year ago

yes, but not on a per-manifest basis.. the cookie would be sent with all outbound requests:

hlsd --header "Cookie: name=value; name2=value2; name3=value3"

warren-bank commented 1 year ago

update: I thought it would be a good idea to support adding request headers (or more generally.. request options) that are conditional on the URL being requested.. so I just released v0.21.0 which adds 2x new hooks.

The readme includes a description, but here's a super fast example:

// hooks.js
module.exports = {
  add_request_options: (url, is_m3u8) => ({headers: {
    "x-abc": "foo"
  }}),

  add_request_headers: (url, is_m3u8) => ({
    "x-xyz": "bar"
  })
}

Of course, these functions aren't applying any conditional logic.. but you can see how easy it would be to do so.

Falsy return values are ignored.

For the purpose of adding headers, only _add_requestheaders is needed; _add_requestoptions allows the ability to tweak more of the request behavior, including headers.. I only included it in the example to illustrate usage.

bhanna98 commented 1 year ago

Is it possible instead of a header flag to append every URL request with my cookie? I have not been able to get it functioning yet when using the header to set the cookie. The host requires that hmac cookie when requesting the master.m3u8 file AND when requesting the .ts segments. I realized after some testing that I could append the value at the end of the url like so...

http://some.host.com/hls/#/#/#/master.m3u8?hdntl=exp=1667601490~acl=%2f*~data=hdntl~hmac=cd6a3355902f727bed499565caa7e0564c97ea6b8456adc498e7653258397532

or

http://some.host.com/hls/#/#/#/master_2692_xxxxxxxxx.ts?hdntl=exp=1667601490~acl=%2f*~data=hdntl~hmac=cd6a3355902f727bed499565caa7e0564c97ea6b8456adc498e7653258397532

... and it would give me access to the requested endpoint

warren-bank commented 1 year ago

well.. if we're no-longer talking about adding conditional headers.. but rather, we now want to add conditional querystring parameters to URLs.. you could use the "redirect" hook:

// hooks.js
module.exports = {
  redirect: (url) => {
    if (url.toLowerCase().indexOf('://some.host.com/') >= 0) {
      const querystring = 'hdntl=exp=1667601490~acl=%2f*~data=hdntl~hmac=cd6a3355902f727bed499565caa7e0564c97ea6b8456adc498e7653258397532'

      url += (url.indexOf('?') >= 0) ? '&' : '?'
      url += querystring
    }
    return url
  }
}

I should note that the value of querystring in the above example doesn't appear to be formatted properly.. but if that's what your backend likes.. then so be it..

bhanna98 commented 1 year ago

Yeah I noticed it appeared in other links to work that way. Not sure why a cookie parameter could also be passed in that method for authentication (seems like a vulnerability to me) but it works 🤷🏼‍♂️ 

bhanna98 commented 1 year ago

In reference to a separate site from above...

`#EXTINF:6.006000,no-desc Fragments(video=2477251416062000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251476122000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251536182000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251596242000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251656302000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251716362000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251776422000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251836482000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251896542000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477251956602000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477252016662000,format=m3u8-aapl-v3,audiotrack=audio)

EXTINF:6.006000,no-desc

Fragments(video=2477252076722000,format=m3u8-aapl-v3,audiotrack=audio)`

That is a snip from a manifest.m3u8 file. The fragments are constantly concatinated to the file rather than reloading a new set each time. Is there a method for hls proxy to recognize that and keep a base url but add that to it?

warren-bank commented 1 year ago

that format doesn't look familiar to me.. are there any URLs to video segments (..which you can directly curl) in that snippet of manifest?

bhanna98 commented 1 year ago

so the video fragment is located at

https://domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3c9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/Fragments(video=2477252076722000,format=m3u8-aapl-v3,audiotrack=audio)

With a validated hmac in the request, it will respond with the video segment (fragment) as the response. The endpoint which returns that is slightly different at

https://domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3b9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/Manifest(video,format=m3u8-aapl-v3,audiotrack=audio,filter=hls)

warren-bank commented 1 year ago

well.. if the video host responds to the request:

wget -O '2477251416062000.ts' 'https://domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3c9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/Fragments(video=2477251416062000,format=m3u8-aapl-v3,audiotrack=audio)'

with:

HTTP/2 200
Content-Type: video/mp2t
Content-Length: ...

and the .m3u8 uses a relative URL to reference this path:

#EXTINF:6.006000,no-desc
Fragments(video=2477251416062000,format=m3u8-aapl-v3,audiotrack=audio)

then the way that the .m3u8 is (currently) parsed to extract URLs won't match these relative URLs.. since it uses a regex that matches patterns.. and this relative path doesn't look very much like a URL.

the hooks that are (currently) available also can't help in this situation, because there isn't (yet) any hook that gets to modify the raw manifest content before it gets parsed.

having said that.. it might be a good idea to add one. maybe something like:

// hooks.js
module.exports = {
  modify_m3u8_content: (m3u8_content, m3u8_url) => {
    const base_url = m3u8_url.replace(/[^\/]*$/, '')
    return m3u8_content.replace(
      /^(Fragments\([^\)]+\))$/mg,
      (m0, m1) => base_url + m1
    )
  }
}
warren-bank commented 1 year ago

actually.. that still wouldn't solve the problem.. since the regex doesn't allow the filename to include any ',' characters; otherwise, it would match every comma separated list.. which would be bad

warren-bank commented 1 year ago

though.. this might work; assuming the video host doesn't object to the commas being URL encoded:

// hooks.js
module.exports = {
  modify_m3u8_content: (m3u8_content, m3u8_url) => {
    const base_url = m3u8_url.replace(/[^\/]*$/, '')
    return m3u8_content.replace(
      /^(Fragments\([^\)]+\))$/mg,
      (m0, m1) => base_url + m1.replace(/[,]/g, '%2C')
    )
  }
}
warren-bank commented 1 year ago

test to confirm:

{
  const regexs = {}
  regexs.urls  = new RegExp('(^|(?<!(?:KEYFORMAT=))[\\s\'"])((?:https?:/)?/)?((?:[^\\?#/\\s\'"]*/)+?)?([^\\?#,/\\s\'"]+?)(\\.[^\\?#,/\\.\\s\'"]+(?:[\\?#][^\\s\'"]*)?)?([\\s\'"]|$)', 'img')

  let m3u8_content = `
#EXTINF:6.006000,no-desc
Fragments(video=2477251416062000,format=m3u8-aapl-v3,audiotrack=audio)
`

  const m3u8_url = 'https://domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3c9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/index.m3u8'

  {
    const base_url = m3u8_url.replace(/[^\/]*$/, '')

    m3u8_content = m3u8_content.replace(
      /^(Fragments\([^\)]+\))$/mg,
      (m0, m1) => base_url + m1.replace(/[,]/g, '%2C')
    )
  }

  m3u8_content.replace(regexs.urls, function(match, head, abs_path, rel_path, file_name, file_ext, tail) {
    console.log(JSON.stringify({match, head, abs_path, rel_path, file_name, file_ext, tail}, null, 2))
  })

  void(0)
}

output:

{
  "match": "\nhttps://domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3c9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/Fragments(video=2477251416062000%2Cformat=m3u8-aapl-v3%2Caudiotrack=audio)\n",
  "head": "\n",
  "abs_path": "https://",
  "rel_path": "domain.akamaized.net/ch12/c12b13f7-32c3-4280-a71f-23ed88237a2a/c12b13f7-32c3-4280-a71f-23ed88237a2a.ism/exp=1667833586~acl=%2f*~data=hdntl,3cad4b4c-eb4f-4603-bfb1-5e5beba4ea0f~hmac=8e774d06f7edbc645f1ab3c9053f9d563227d04b6c87d63bf3704fa971bb8ca4/QualityLevels(4749952)/",
  "file_name": "Fragments(video=2477251416062000%2Cformat=m3u8-aapl-v3%2Caudiotrack=audio)",
  "tail": "\n"
}
warren-bank commented 1 year ago

v0.22.0 was just pushed to npm.. and it adds this new hook method.

I tested the examples given earlier.. and they work as expected.

Here is a more complete example, which uses the redirect hook to undo the URL-escaping of commas that occur in the earlier modify_m3u8_content hook.. because they are required during the parsing phase to pattern-match the URLs:

//hooks.js
module.exports = {
  modify_m3u8_content: (m3u8_content, m3u8_url) => {
    const base_url = m3u8_url.replace(/[^\/]*$/, '')
    return m3u8_content.replace(
      /^(Fragments\([^\)]+\))$/mg,
      (m0, m1) => base_url + m1.replace(/[,]/g, '%2C')
    )
  },
  redirect: (url) => {
    return url.replace(
      /^(.+\/)(Fragments\([^\)]+\))$/,
      (m0, m1, m2) => m1 + m2.replace(/%2C/g, ',')
    )
  }
}
bhanna98 commented 1 year ago

So for hook usage in my case - I would create the hooks.js file & then call that with --hooks modify_m3u8_content in the command to start hlsd?

warren-bank commented 1 year ago

hlsd --hooks '/path/to/hooks.js'

bhanna98 commented 1 year ago

@warren-bank Had to take a break last week but I am getting back to my project here. After doing some digging it looks like the platform originating the stream is utilizing Azure Media Service with Apple HLS v3

https://learn.microsoft.com/en-us/azure/media-services/previous/media-services-deliver-content-overview <-- is a great reference. If you have time could you check that and let me know if hls-proxy would still be suitable for my project with this delivery?

Edit: Also I found out that the Manifest(video,format=m3u8-aapl-v3,audiotrack=audio,filter=hls) url will respond if .m3u8 is appended. Not sure if that helps in any way

bhanna98 commented 1 year ago

@warren-bank you can also find a test endpoint that microsoft hosts here. https://testweb.playready.microsoft.com/Content/Content2X

You can see the first manifest returns the manifest with quality/bandwidth values... https://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=m3u8-aapl-v3)

That can be bypassed as it can be hardcoded. The next m3u8 file to grab is located at... https://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(5820064)/Manifest(video,format=m3u8-aapl-v3,audiotrack=aac_UND_2_128) You can see the base url is appended with the value from the 1st manifest request.

The last request is for a fragment from the /QualityLevels()/Manifest(video,format=m3u8-aapl-v3,audiotrack=aac_UND_2_128) endpoint. We can see here the first fragment is located at ... https://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(5820064)/Fragments(video=0,format=m3u8-aapl-v3,audiotrack=aac_UND_2_128) This fragment is a video/mp2t which is exactly what we need, right?

The difference between this test environment and mine is that the test urls have a defined end of list while the streamed content in the environment I am working with has no predetermined end of list.

bhanna98 commented 1 year ago

@warren-bank Is this still being followed?

warren-bank commented 1 year ago

Admittedly, I haven't given this issue any thought.

I just did some reading.. on these URLs.. which are produced by videos hosted by Microsoft Azure Media Services..

https://learn.microsoft.com/en-us/azure/media-services/previous/
https://learn.microsoft.com/en-us/azure/media-services/previous/media-services-deliver-content-overview
  Azure Media Services v2

https://learn.microsoft.com/en-us/azure/media-services/latest/
https://learn.microsoft.com/en-us/azure/media-services/latest/encode-dynamic-packaging-concept
https://learn.microsoft.com/en-us/azure/media-services/latest/filters-dynamic-manifest-concept
  Azure Media Services v3

https://azure.microsoft.com/en-us/blog/dynamic-manifest/
https://azure.microsoft.com/en-us/blog/azure-media-services-release-dynamic-manifest-composition-remove-hls-audio-only-track-and-hls-i-frame-track-support/

and inspecting the manifest that you referenced:

https://testweb.playready.microsoft.com/Content/Content2X

http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=m3u8-aapl)
  => manifest-master.m3u8
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Manifest(video,format=m3u8-aapl)
  => manifest-child.m3u8
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Fragments(video=0,format=m3u8-aapl)
  => segment-001.ts
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Fragments(video=100000000,format=m3u8-aapl)
  => segment-002.ts

As I see it, I have 2 options:

  1. add a hacky workaround to the existing regex patterns to detect these URL conventions
  2. go back to the drawing board.. and rewrite the m3u8 parser
    • the existing methodology is a naive parser..
      not making any assumptions about the format of the blob of text from which it's extracting URLs
    • a better methodology would be a parser that understands the format of m3u8 manifests..
      and uses context to extract URLs
      • which would allow URLs to be be structured in any way that the video host likes (ex: Azure)
      • which would prevent matching false positives

Option 2 sounds like a good idea. Of course, it could also completely break the app.. if not careful. I'll probably play around with this idea over the next few days.

warren-bank commented 1 year ago

notes..

https://datatracker.ietf.org/doc/html/rfc8216
  stable spec

manifest URLs:
==============
#EXT-X-MEDIA: ... URI="${URL}"
#EXT-X-I-FRAME-STREAM-INF: ... URI="${URL}"
#EXT-X-STREAM-INF: ... \n${URL}

segment URLs:
=============
#EXTINF: ...\n${URL}

other URLs:
===========
#EXT-X-KEY: ... URI="${URL}"
#EXT-X-SESSION-DATA: ... URI="${URL}"
https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis
  draft spec

manifest URLs:
==============
#EXT-X-MEDIA: ... URI="${URL}"
#EXT-X-I-FRAME-STREAM-INF: ... URI="${URL}"
#EXT-X-RENDITION-REPORT: ... URI="${URL}"
#EXT-X-DATERANGE: ... X-ASSET-URI="${URL}"
#EXT-X-CONTENT-STEERING: ... SERVER-URI="${URL}"
#EXT-X-STREAM-INF: ... \n${URL}

segment URLs:
=============
#EXT-X-PART: ... URI="${URL}"
#EXT-X-PRELOAD-HINT: ... URI="${URL}"
#EXTINF: ...\n${URL}

other URLs:
===========
#EXT-X-KEY: ... URI="${URL}"
#EXT-X-SESSION-DATA: ... URI="${URL}"
bhanna98 commented 1 year ago

I have created a companion script that will actively run in the background along side hls. It's functionality is to get an active session token (hmac) for the endpoints that require them. I haven't implemented database storage at the time for those values but that is the plan. As of right now they are just written to json objects and stored locally.

bhanna98 commented 1 year ago

Feasibly that companion script could be used alongside a hook I guess? To set parts of the url as a variable that requests those values from the local storage? As far as detection goes, the only way I see it possible would be for you to detect ".ism" within the link and use a function dedicated to the azure media services delivery platform

warren-bank commented 1 year ago

quick update.. I finally gave this repo some attention and did a ton of internal housekeeping, refactoring, and rewriting. I like where it is now.. so unless I'm told that I broke something.. I'll probably leave it alone (at v3.0.0) for now.

regarding the Azure/PlayReady manifests.. the proxy (with its completely new manifest parser) can now successfully detect and encode its URLs. That said, I couldn't easily find a video player that supports PlayReady.. but the stream plays the same for me (ie: artifacts on the screen because the stream is scrambled) when using the proxy as it does when playing the stream directly (in VLC on Win64, and in ExoPlayer on Android). So.. if you have a video player that supports PlayReady.. I'm fairly certain it'll work through the proxy.

bhanna98 commented 1 year ago

https://ampdemo.azureedge.net/ looks to be a good demo site. I will play around with the new update today! Is it the same usage command to start up?

bhanna98 commented 1 year ago

Disregard previous question about usage.

May need a little debugging if this is not an issue solely on my end. If my top level manifest link is

https://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/manifest(format=m3u8-aapl-v3)

Then the next phase is a bandwidth determination. Since those bandwidth levels are static, could we hardcode that value to say something like --bandwidth 4925887 which would direct us to this from the bandwidth Manifest...

#EXT-X-STREAM-INF:BANDWIDTH=4925887,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" QualityLevels(4678229)/Manifest(video,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)

Which would now make our Fragment manifest...

https://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Manifest(video,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)

The proxy in 3.0.0 does fine when it is directly calling a Fragment URL

I.e. https://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Fragments(video=600000000,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)

But if I call the full fragment manifest it just returns that manifest rather than parsing those fragments into a fetched stream

warren-bank commented 1 year ago

the only change to user space is that file extensions appended to the encoded URL are now very important, whereas previously they were optional. ex: http://localhost:8080/xxxxx.m3u8

previously, the xxxxx was base64 decoded to reveal the origin url.. and assumptions were made.. such as that the url includes a file extension to indicate what type of file is being proxied. now, the .m3u8 is used to know that the url points to a manifest. since the proxy always appends an explicit extension to the urls within a manifest that it rewrites.. no assumptions are needed. however, for a 3rd party to get the ball rolling.. an .m3u8 file extension is now required.

as far as your comment about video "fragments".. I get the sense that you think the proxy is in some way transcoding the video stream.. and should be merging segments.. which is entirely not the case. there is no transcoding.. and there never will be.

the manifest is modified so the url to each individual video segment (ie: "fragment") is rewritten to be directed through the proxy (with the original url being base64 encoded and a .ts file extension appended).

and when each video segment is requested through the proxy by a client.. it is retrieved (either by requesting it from the origin server or by obtaining it from the internal cache) and returned in the response.

bhanna98 commented 1 year ago

Maybe I had its functionality misconstrued but what I thought the proxy did would be to tunnel all traffic through a central location thus it would turn

'https://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Fragments(video=600000000,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)'

Into

'https://localhost.com/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Fragments(video=600000000,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)'

Right?

warren-bank commented 1 year ago

OK, yes.. that is correct.

Here is a quick example to walk through its behavior using the example (master) manifest:

https://testweb.playready.microsoft.com/Content/Content2X

http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=m3u8-aapl)
  => manifest-master.m3u8
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Manifest(video,format=m3u8-aapl)
  => manifest-child.m3u8
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Fragments(video=0,format=m3u8-aapl)
  => segment-001.ts
http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/QualityLevels(3294017)/Fragments(video=100000000,format=m3u8-aapl)
  => segment-002.ts

The corresponding encoded URLs to proxy these endpoints are:

http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL21hbmlmZXN0KGZvcm1hdD1tM3U4LWFhcGwp.m3u8
  => manifest-master.m3u8
http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8
  => manifest-child.m3u8
http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTAsZm9ybWF0PW0zdTgtYWFwbCk=.ts
  => segment-001.ts
http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTEwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts
  => segment-002.ts

Where the modified manifests are:

manifest-master.m3u8 ```text #EXTM3U #EXT-X-VERSION:4 #EXT-X-PLAYREADYHEADER:YAMAAAEAAQBWAzwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ANABSAHAAbABiACsAVABiAE4ARQBTADgAdABHAGsATgBGAFcAVABFAEgAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBLAEwAagAzAFEAegBRAFAALwBOAEEAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbwBmAGYAaQBjAGkAYQBsAHMAaQB0AGUALgBrAGUAeQBkAGUAbABpAHYAZQByAHkALgBtAGUAZABpAGEAcwBlAHIAdgBpAGMAZQBzAC4AdwBpAG4AZABvAHcAcwAuAG4AZQB0AC8AUABsAGEAeQBSAGUAYQBkAHkALwA8AC8ATABBAF8AVQBSAEwAPgA8AEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AEkASQBTAF8ARABSAE0AXwBWAEUAUgBTAEkATwBOAD4AOAAuADEALgAyADIAMQAwAC4AMgAyADAAMgA8AC8ASQBJAFMAXwBEAFIATQBfAFYARQBSAFMASQBPAE4APgA8AC8AQwBVAFMAVABPAE0AQQBUAFQAUgBJAEIAVQBUAEUAUwA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="aac_UND_2_128",DEFAULT=YES,URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTI4MDAzKS9NYW5pZmVzdChhYWNfVU5EXzJfMTI4LGZvcm1hdD1tM3U4LWFhcGwp.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=1138489,RESOLUTION=640x288,CODECS="avc1.640015,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoOTcwMDEwKS9NYW5pZmVzdCh2aWRlbyxmb3JtYXQ9bTN1OC1hYXBsKQ==.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1138489,RESOLUTION=640x288,CODECS="avc1.640015",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoOTcwMDEwKS9NYW5pZmVzdCh2aWRlbyxmb3JtYXQ9bTN1OC1hYXBsLHR5cGU9a2V5ZnJhbWVzKQ==.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=2376263,RESOLUTION=960x428,CODECS="avc1.64001e,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMjE4MTEzOSkvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=2376263,RESOLUTION=960x428,CODECS="avc1.64001e",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMjE4MTEzOSkvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=3513624,RESOLUTION=1280x572,CODECS="avc1.64001f,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=3513624,RESOLUTION=1280x572,CODECS="avc1.64001f",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=4782065,RESOLUTION=1920x860,CODECS="avc1.640028,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNDUzNTE1MykvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=4782065,RESOLUTION=1920x860,CODECS="avc1.640028",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNDUzNTE1MykvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=6095244,RESOLUTION=1920x860,CODECS="avc1.640028,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNTgyMDA2NCkvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=6095244,RESOLUTION=1920x860,CODECS="avc1.640028",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNTgyMDA2NCkvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=8096400,RESOLUTION=2560x1144,CODECS="avc1.640032,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNzc3ODE0MikvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=8096400,RESOLUTION=2560x1144,CODECS="avc1.640032",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoNzc3ODE0MikvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=10117885,RESOLUTION=2560x1144,CODECS="avc1.640032,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoOTc1NjExMikvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCk=.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=10117885,RESOLUTION=2560x1144,CODECS="avc1.640032",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoOTc1NjExMikvTWFuaWZlc3QodmlkZW8sZm9ybWF0PW0zdTgtYWFwbCx0eXBlPWtleWZyYW1lcyk=.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=12129814,RESOLUTION=2560x1144,CODECS="avc1.640032,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTE3MjQ3MzEpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwp.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=12129814,RESOLUTION=2560x1144,CODECS="avc1.640032",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTE3MjQ3MzEpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwsdHlwZT1rZXlmcmFtZXMp.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=14127575,RESOLUTION=3840x1716,CODECS="avc1.640033,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTM2Nzk0ODgpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwp.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=14127575,RESOLUTION=3840x1716,CODECS="avc1.640033",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTM2Nzk0ODgpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwsdHlwZT1rZXlmcmFtZXMp.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=16130666,RESOLUTION=3840x1716,CODECS="avc1.640033,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTU2Mzk0NTkpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwp.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=16130666,RESOLUTION=3840x1716,CODECS="avc1.640033",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTU2Mzk0NTkpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwsdHlwZT1rZXlmcmFtZXMp.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=18134680,RESOLUTION=3840x1716,CODECS="avc1.640033,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTc2MDAzMzQpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwp.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=18134680,RESOLUTION=3840x1716,CODECS="avc1.640033",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTc2MDAzMzQpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwsdHlwZT1rZXlmcmFtZXMp.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=20115909,RESOLUTION=4096x1828,CODECS="avc1.640033,mp4a.40.2",AUDIO="audio" http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTk1Mzg5MTQpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwp.m3u8 #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=20115909,RESOLUTION=4096x1828,CODECS="avc1.640033",URI="http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMTk1Mzg5MTQpL01hbmlmZXN0KHZpZGVvLGZvcm1hdD1tM3U4LWFhcGwsdHlwZT1rZXlmcmFtZXMp.m3u8" ```
manifest-child.m3u8 ```text #EXTM3U #EXT-X-VERSION:4 #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-ALLOW-CACHE:NO #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-TARGETDURATION:10 #EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:00Z #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTEwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTIwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTMwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTUwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTYwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTcwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTgwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTkwMDAwMDAwMCxmb3JtYXQ9bTN1OC1hYXBsKQ==.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTEwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTExMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTEyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTEzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTE5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTIwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTIxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTIyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTIzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTI5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTMwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTMxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTMyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTMzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTM5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTQ5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTUwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTUxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTUyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTUzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTU5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTYwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTYxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTYyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTYzMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY0MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY1MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY2MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY3MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY4MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTY5MDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTcwMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTcxMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:10.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTcyMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXTINF:4.000000,no-desc http://127.0.0.1:8080/aHR0cDovL3Byb2ZmaWNpYWxzaXRlLm9yaWdpbi5tZWRpYXNlcnZpY2VzLndpbmRvd3MubmV0L2M1MTM1OGVhLTlhNWUtNDMyMi04OTUxLTg5N2Q2NDBmZGZkNy90ZWFyc29mc3RlZWxfNGsuaXNtL1F1YWxpdHlMZXZlbHMoMzI5NDAxNykvRnJhZ21lbnRzKHZpZGVvPTczMDAwMDAwMDAsZm9ybWF0PW0zdTgtYWFwbCk=.ts #EXT-X-ENDLIST ```
warren-bank commented 1 year ago

well.. actually "yes" and "no".. your example has problems.

this:

https://localhost.com/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Fragments(video=600000000,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)

..is not a valid URL to make a request to the proxy

as the readme describes, the format of a proxied URL is:

  proxy_url='http://127.0.0.1:8080'
  video_url='https://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/QualityLevels(4678229)/Fragments(video=600000000,format=m3u8-aapl-v3,audiotrack=AAC_und_ch2_56kbps)'
  file_extension='.ts'

  hls_proxy_url="${proxy_url}/"$(echo -n "$video_url" | base64 --wrap=0)"$file_extension"

though, I personally always use this webpage to do all of the hard work for me. If you pipe the resulting URL to the option for "AirPlay sender", then the proxied URL will be pre-populated in the text input field: "Video URL".

notes:

bhanna98 commented 1 year ago

I see. I will give it another test run on my end tomorrow. Looks like it was an error on my end as I did not know the file extensions were required as of latest update

bhanna98 commented 1 year ago

Working great! Looks like the website uses user-agent strings as a form of security validation. If I wanted to write a hook to fetch the user agent from a json file, what would that look like in my command usage? and would the hook look like this...

// hooks.js module.exports = { user-agent: require(./useragent.json).UA }

warren-bank commented 1 year ago

unless you need to configure different user-agent request headers for different video hosts (which is unlikely), you could just configure a global value that is included in all requests:

hlsd --useragent 'Chrome/100' ...

but.. if you really do need to apply logic on a per-request basis, then either of these 2x hooks could be used:

..the signatures of each hook is described in the readme