Preserve HLS media session cookies

This commit is contained in:
Dymas
2026-09-07 21:52:08 +02:00
parent baf5298631
commit d39d783738
5 changed files with 141 additions and 6 deletions
+89 -1
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env python3
import base64
from email.message import Message
import http.cookiejar
import importlib.util
import io
import json
@@ -4535,7 +4537,9 @@ seg-3.ts
def test_curl_fetch_bytes_returns_body_before_status_marker(self):
proc = mock.Mock(returncode=0, stdout=b"video-bytes\nKAIZOKU_HTTP_STATUS:200", stderr=b"")
with mock.patch.object(provider_downloader, "curl_candidates", return_value=["/usr/bin/curl"]), mock.patch.object(
with tempfile.TemporaryDirectory() as temp_root, mock.patch.object(
provider_downloader, "curl_cookie_file", return_value=Path(temp_root) / "cookies.txt"
), mock.patch.object(provider_downloader, "curl_candidates", return_value=["/usr/bin/curl"]), mock.patch.object(
provider_downloader.subprocess, "run", return_value=proc
) as run:
data = provider_downloader.curl_fetch_bytes("https://cdn.example/segment.ts", headers={"Referer": "https://player.example/"})
@@ -4543,6 +4547,90 @@ seg-3.ts
self.assertEqual(data, b"video-bytes")
self.assertIn("--header", run.call_args.args[0])
self.assertIn("Referer: https://player.example/", run.call_args.args[0])
self.assertIn("--cookie-jar", run.call_args.args[0])
def test_media_request_preserves_playlist_cookie_for_segments(self):
jar = http.cookiejar.CookieJar()
cookie = http.cookiejar.Cookie(
version=0,
name="cdn_session",
value="allowed",
port=None,
port_specified=False,
domain="cdn.example",
domain_specified=True,
domain_initial_dot=False,
path="/",
path_specified=True,
secure=True,
expires=None,
discard=True,
comment=None,
comment_url=None,
rest={},
rfc2109=False,
)
jar.set_cookie(cookie)
with mock.patch.object(provider_downloader, "MEDIA_COOKIE_JAR", jar):
request = provider_downloader.media_request("https://cdn.example/video/segment.ts")
self.assertEqual(request.get_header("Cookie"), "cdn_session=allowed")
def test_fetch_bytes_keeps_set_cookie_for_next_media_request(self):
class Response:
def __init__(self, url, body, cookie=""):
self.url = url
self.body = body
self.headers = Message()
if cookie:
self.headers.add_header("Set-Cookie", cookie)
def __enter__(self):
return self
def __exit__(self, *_args):
return False
def info(self):
return self.headers
def geturl(self):
return self.url
def read(self):
return self.body
requests = []
responses = iter(
[
Response("https://cdn.example/index.m3u8", b"playlist", "cdn_session=allowed; Path=/; Secure"),
Response("https://cdn.example/video/segment.ts", b"video"),
]
)
def fake_urlopen(request, timeout):
requests.append(request)
return next(responses)
with mock.patch.object(provider_downloader, "MEDIA_COOKIE_JAR", http.cookiejar.CookieJar()), mock.patch.object(
provider_downloader.urllib.request, "urlopen", side_effect=fake_urlopen
):
provider_downloader.fetch_bytes("https://cdn.example/index.m3u8")
provider_downloader.fetch_bytes("https://cdn.example/video/segment.ts")
self.assertEqual(requests[1].get_header("Cookie"), "cdn_session=allowed")
def test_curl_fetch_uses_python_media_session_cookie(self):
proc = mock.Mock(returncode=0, stdout=b"video\nKAIZOKU_HTTP_STATUS:200", stderr=b"")
with tempfile.TemporaryDirectory() as temp_root, mock.patch.object(
provider_downloader, "curl_cookie_file", return_value=Path(temp_root) / "cookies.txt"
), mock.patch.object(provider_downloader, "curl_candidates", return_value=["/usr/bin/curl"]), mock.patch.object(
provider_downloader, "media_cookie_header", return_value="cdn_session=allowed"
), mock.patch.object(provider_downloader.subprocess, "run", return_value=proc) as run:
provider_downloader.curl_fetch_bytes("https://cdn.example/segment.ts")
self.assertIn("Cookie: cdn_session=allowed", run.call_args.args[0])
def test_curl_request_headers_preserve_browser_wrapper_defaults(self):
headers = provider_downloader.curl_request_headers(