mhdzumair commited on
Commit
480076c
1 Parent(s): b053b86

Fix key URL in m3u8 & update libs & bump version

Browse files
mediaflow_proxy/handlers.py CHANGED
@@ -1,9 +1,9 @@
1
  import base64
2
  import logging
 
3
 
4
  import httpx
5
  from fastapi import Request, Response, HTTPException
6
- from pydantic import HttpUrl
7
  from starlette.background import BackgroundTask
8
 
9
  from .configs import settings
@@ -86,7 +86,7 @@ async def handle_hls_stream_proxy(
86
  client, streamer = await setup_client_and_streamer(hls_params.use_request_proxy, hls_params.verify_ssl)
87
 
88
  try:
89
- if hls_params.destination.endswith((".m3u", ".m3u8")):
90
  return await fetch_and_process_m3u8(
91
  streamer, hls_params.destination, proxy_headers, request, hls_params.key_url
92
  )
@@ -199,7 +199,7 @@ async def proxy_stream(method: str, stream_params: ProxyStreamParams, proxy_head
199
 
200
 
201
  async def fetch_and_process_m3u8(
202
- streamer: Streamer, url: str, proxy_headers: ProxyRequestHeaders, request: Request, key_url: HttpUrl = None
203
  ):
204
  """
205
  Fetches and processes the m3u8 playlist, converting it to an HLS playlist.
@@ -209,7 +209,7 @@ async def fetch_and_process_m3u8(
209
  url (str): The URL of the m3u8 playlist.
210
  proxy_headers (ProxyRequestHeaders): The headers to include in the request.
211
  request (Request): The incoming HTTP request.
212
- key_url (HttpUrl, optional): The HLS Key URL to replace the original key URL. Defaults to None.
213
 
214
  Returns:
215
  Response: The HTTP response with the processed m3u8 playlist.
 
1
  import base64
2
  import logging
3
+ from urllib.parse import urlparse
4
 
5
  import httpx
6
  from fastapi import Request, Response, HTTPException
 
7
  from starlette.background import BackgroundTask
8
 
9
  from .configs import settings
 
86
  client, streamer = await setup_client_and_streamer(hls_params.use_request_proxy, hls_params.verify_ssl)
87
 
88
  try:
89
+ if urlparse(hls_params.destination).path.endswith((".m3u", ".m3u8")):
90
  return await fetch_and_process_m3u8(
91
  streamer, hls_params.destination, proxy_headers, request, hls_params.key_url
92
  )
 
199
 
200
 
201
  async def fetch_and_process_m3u8(
202
+ streamer: Streamer, url: str, proxy_headers: ProxyRequestHeaders, request: Request, key_url: str = None
203
  ):
204
  """
205
  Fetches and processes the m3u8 playlist, converting it to an HLS playlist.
 
209
  url (str): The URL of the m3u8 playlist.
210
  proxy_headers (ProxyRequestHeaders): The headers to include in the request.
211
  request (Request): The incoming HTTP request.
212
+ key_url (str, optional): The HLS Key URL to replace the original key URL. Defaults to None.
213
 
214
  Returns:
215
  Response: The HTTP response with the processed m3u8 playlist.
mediaflow_proxy/utils/http_utils.py CHANGED
@@ -370,7 +370,7 @@ class EnhancedStreamingResponse(Response):
370
 
371
  await send({"type": "http.response.body", "body": b"", "more_body": False})
372
  except Exception as e:
373
- logger.error(f"Error in stream_response: {str(e)}")
374
 
375
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
376
  async with anyio.create_task_group() as task_group:
 
370
 
371
  await send({"type": "http.response.body", "body": b"", "more_body": False})
372
  except Exception as e:
373
+ logger.exception(f"Error in stream_response: {str(e)}")
374
 
375
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
376
  async with anyio.create_task_group() as task_group:
mediaflow_proxy/utils/m3u8_processor.py CHANGED
@@ -1,14 +1,12 @@
1
  import re
2
  from urllib import parse
3
 
4
- from pydantic import HttpUrl
5
-
6
  from mediaflow_proxy.utils.crypto_utils import encryption_handler
7
  from mediaflow_proxy.utils.http_utils import encode_mediaflow_proxy_url, get_original_scheme
8
 
9
 
10
  class M3U8Processor:
11
- def __init__(self, request, key_url: HttpUrl = None):
12
  """
13
  Initializes the M3U8Processor with the request and URL prefix.
14
 
@@ -17,7 +15,7 @@ class M3U8Processor:
17
  key_url (HttpUrl, optional): The URL of the key server. Defaults to None.
18
  """
19
  self.request = request
20
- self.key_url = key_url
21
  self.mediaflow_proxy_url = str(request.url_for("hls_stream_proxy").replace(scheme=get_original_scheme(request)))
22
 
23
  async def process_m3u8(self, content: str, base_url: str) -> str:
@@ -58,7 +56,7 @@ class M3U8Processor:
58
  original_uri = uri_match.group(1)
59
  uri = parse.urlparse(original_uri)
60
  if self.key_url:
61
- uri = uri._replace(scheme=self.key_url.scheme, netloc=self.key_url.host)
62
  new_uri = await self.proxy_url(uri.geturl(), base_url)
63
  line = line.replace(f'URI="{original_uri}"', f'URI="{new_uri}"')
64
  return line
 
1
  import re
2
  from urllib import parse
3
 
 
 
4
  from mediaflow_proxy.utils.crypto_utils import encryption_handler
5
  from mediaflow_proxy.utils.http_utils import encode_mediaflow_proxy_url, get_original_scheme
6
 
7
 
8
  class M3U8Processor:
9
+ def __init__(self, request, key_url: str = None):
10
  """
11
  Initializes the M3U8Processor with the request and URL prefix.
12
 
 
15
  key_url (HttpUrl, optional): The URL of the key server. Defaults to None.
16
  """
17
  self.request = request
18
+ self.key_url = parse.urlparse(key_url) if key_url else None
19
  self.mediaflow_proxy_url = str(request.url_for("hls_stream_proxy").replace(scheme=get_original_scheme(request)))
20
 
21
  async def process_m3u8(self, content: str, base_url: str) -> str:
 
56
  original_uri = uri_match.group(1)
57
  uri = parse.urlparse(original_uri)
58
  if self.key_url:
59
+ uri = uri._replace(scheme=self.key_url.scheme, netloc=self.key_url.netloc)
60
  new_uri = await self.proxy_url(uri.geturl(), base_url)
61
  line = line.replace(f'URI="{original_uri}"', f'URI="{new_uri}"')
62
  return line
poetry.lock CHANGED
@@ -35,33 +35,33 @@ trio = ["trio (>=0.26.1)"]
35
 
36
  [[package]]
37
  name = "black"
38
- version = "24.8.0"
39
  description = "The uncompromising code formatter."
40
  optional = false
41
- python-versions = ">=3.8"
42
  files = [
43
- {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"},
44
- {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"},
45
- {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"},
46
- {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"},
47
- {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"},
48
- {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"},
49
- {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"},
50
- {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"},
51
- {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"},
52
- {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"},
53
- {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"},
54
- {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"},
55
- {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"},
56
- {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"},
57
- {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"},
58
- {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"},
59
- {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"},
60
- {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"},
61
- {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"},
62
- {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"},
63
- {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"},
64
- {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"},
65
  ]
66
 
67
  [package.dependencies]
@@ -75,7 +75,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
75
 
76
  [package.extras]
77
  colorama = ["colorama (>=0.4.3)"]
78
- d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
79
  jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
80
  uvloop = ["uvloop (>=0.15.2)"]
81
 
@@ -579,13 +579,13 @@ files = [
579
 
580
  [[package]]
581
  name = "uvicorn"
582
- version = "0.31.0"
583
  description = "The lightning-fast ASGI server."
584
  optional = false
585
  python-versions = ">=3.8"
586
  files = [
587
- {file = "uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced"},
588
- {file = "uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906"},
589
  ]
590
 
591
  [package.dependencies]
@@ -598,16 +598,16 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
598
 
599
  [[package]]
600
  name = "xmltodict"
601
- version = "0.13.0"
602
  description = "Makes working with XML feel like you are working with JSON"
603
  optional = false
604
- python-versions = ">=3.4"
605
  files = [
606
- {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"},
607
- {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"},
608
  ]
609
 
610
  [metadata]
611
  lock-version = "2.0"
612
  python-versions = ">=3.10"
613
- content-hash = "cfa51491c2cccf2ff0bd593a2ede5734b580e2c20f6380e6a50ea3d900c9e809"
 
35
 
36
  [[package]]
37
  name = "black"
38
+ version = "24.10.0"
39
  description = "The uncompromising code formatter."
40
  optional = false
41
+ python-versions = ">=3.9"
42
  files = [
43
+ {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"},
44
+ {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"},
45
+ {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"},
46
+ {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"},
47
+ {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"},
48
+ {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"},
49
+ {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"},
50
+ {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"},
51
+ {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"},
52
+ {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"},
53
+ {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"},
54
+ {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"},
55
+ {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"},
56
+ {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"},
57
+ {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"},
58
+ {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"},
59
+ {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"},
60
+ {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"},
61
+ {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"},
62
+ {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"},
63
+ {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"},
64
+ {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"},
65
  ]
66
 
67
  [package.dependencies]
 
75
 
76
  [package.extras]
77
  colorama = ["colorama (>=0.4.3)"]
78
+ d = ["aiohttp (>=3.10)"]
79
  jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
80
  uvloop = ["uvloop (>=0.15.2)"]
81
 
 
579
 
580
  [[package]]
581
  name = "uvicorn"
582
+ version = "0.31.1"
583
  description = "The lightning-fast ASGI server."
584
  optional = false
585
  python-versions = ">=3.8"
586
  files = [
587
+ {file = "uvicorn-0.31.1-py3-none-any.whl", hash = "sha256:adc42d9cac80cf3e51af97c1851648066841e7cfb6993a4ca8de29ac1548ed41"},
588
+ {file = "uvicorn-0.31.1.tar.gz", hash = "sha256:f5167919867b161b7bcaf32646c6a94cdbd4c3aa2eb5c17d36bb9aa5cfd8c493"},
589
  ]
590
 
591
  [package.dependencies]
 
598
 
599
  [[package]]
600
  name = "xmltodict"
601
+ version = "0.14.1"
602
  description = "Makes working with XML feel like you are working with JSON"
603
  optional = false
604
+ python-versions = ">=3.6"
605
  files = [
606
+ {file = "xmltodict-0.14.1-py2.py3-none-any.whl", hash = "sha256:3ef4a7b71c08f19047fcbea572e1d7f4207ab269da1565b5d40e9823d3894e63"},
607
+ {file = "xmltodict-0.14.1.tar.gz", hash = "sha256:338c8431e4fc554517651972d62f06958718f6262b04316917008e8fd677a6b0"},
608
  ]
609
 
610
  [metadata]
611
  lock-version = "2.0"
612
  python-versions = ">=3.10"
613
+ content-hash = "82b614db25311cde2b5ae15465b537fcb82c4c9cef5817fe45f030d1ea588646"
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
  [tool.poetry]
2
  name = "mediaflow-proxy"
3
- version = "1.7.2"
4
  description = "A high-performance proxy server for streaming media, supporting HTTP(S), HLS, and MPEG-DASH with real-time DRM decryption."
5
  authors = ["mhdzumair <[email protected]>"]
6
  readme = "README.md"
@@ -26,7 +26,7 @@ python = ">=3.10"
26
  fastapi = "0.115.0"
27
  httpx = {extras = ["socks"], version = "^0.27.2"}
28
  tenacity = "^9.0.0"
29
- xmltodict = "^0.13.0"
30
  cachetools = "^5.4.0"
31
  pydantic-settings = "^2.5.2"
32
  gunicorn = "^23.0.0"
 
1
  [tool.poetry]
2
  name = "mediaflow-proxy"
3
+ version = "1.7.3"
4
  description = "A high-performance proxy server for streaming media, supporting HTTP(S), HLS, and MPEG-DASH with real-time DRM decryption."
5
  authors = ["mhdzumair <[email protected]>"]
6
  readme = "README.md"
 
26
  fastapi = "0.115.0"
27
  httpx = {extras = ["socks"], version = "^0.27.2"}
28
  tenacity = "^9.0.0"
29
+ xmltodict = "^0.14.0"
30
  cachetools = "^5.4.0"
31
  pydantic-settings = "^2.5.2"
32
  gunicorn = "^23.0.0"