Preserve HLS media session cookies
This commit is contained in:
+44
-2
@@ -3,12 +3,15 @@
|
||||
"""Download episodes from Kaizoku's StrawVerse-compatible provider bridge."""
|
||||
|
||||
import argparse
|
||||
import atexit
|
||||
import http.cookiejar
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.error
|
||||
from urllib.parse import urljoin, urlparse
|
||||
@@ -21,6 +24,8 @@ BRIDGE = PROJECT_ROOT / "providers" / "bridge.js"
|
||||
PROVIDERS = ("anikoto", "anineko", "pahe")
|
||||
RETRYABLE_HTTP_STATUS = {408, 425, 429, 500, 502, 503, 504}
|
||||
CURL_STATUS_MARKER = b"\nKAIZOKU_HTTP_STATUS:"
|
||||
MEDIA_COOKIE_JAR = http.cookiejar.CookieJar()
|
||||
MEDIA_CURL_COOKIE_DIR = None
|
||||
|
||||
|
||||
def clean_component(value, default="Anime"):
|
||||
@@ -214,6 +219,28 @@ def request_headers(headers=None, referer=None):
|
||||
return merged
|
||||
|
||||
|
||||
def media_request(url, headers=None):
|
||||
request = urllib.request.Request(url, headers=request_headers(headers))
|
||||
MEDIA_COOKIE_JAR.add_cookie_header(request)
|
||||
return request
|
||||
|
||||
|
||||
def media_cookie_header(url):
|
||||
request = urllib.request.Request(url)
|
||||
MEDIA_COOKIE_JAR.add_cookie_header(request)
|
||||
return request.get_header("Cookie") or ""
|
||||
|
||||
|
||||
def curl_cookie_file():
|
||||
global MEDIA_CURL_COOKIE_DIR
|
||||
if MEDIA_CURL_COOKIE_DIR is None:
|
||||
MEDIA_CURL_COOKIE_DIR = tempfile.TemporaryDirectory(prefix="kaizoku-media-cookies-")
|
||||
atexit.register(MEDIA_CURL_COOKIE_DIR.cleanup)
|
||||
cookie_file = Path(MEDIA_CURL_COOKIE_DIR.name) / "cookies.txt"
|
||||
cookie_file.touch(mode=0o600)
|
||||
return Path(MEDIA_CURL_COOKIE_DIR.name) / "cookies.txt"
|
||||
|
||||
|
||||
def curl_candidates():
|
||||
def candidate_score(name):
|
||||
text = Path(str(name or "")).name
|
||||
@@ -279,8 +306,13 @@ def curl_fetch_bytes(url, headers=None, timeout=30):
|
||||
if not candidates:
|
||||
raise RuntimeError("curl is not available for media fetch fallback.")
|
||||
last_error = None
|
||||
failures = []
|
||||
cookie_file = curl_cookie_file()
|
||||
for curl_bin in candidates:
|
||||
clean_headers = curl_request_headers(curl_bin, headers)
|
||||
cookie_header = media_cookie_header(url)
|
||||
if cookie_header and not any(str(key).lower() == "cookie" for key in clean_headers):
|
||||
clean_headers["Cookie"] = cookie_header
|
||||
cmd = [
|
||||
curl_bin,
|
||||
"--location",
|
||||
@@ -288,6 +320,10 @@ def curl_fetch_bytes(url, headers=None, timeout=30):
|
||||
"--show-error",
|
||||
"--max-time",
|
||||
str(max(1, int(timeout or 30))),
|
||||
"--cookie",
|
||||
str(cookie_file),
|
||||
"--cookie-jar",
|
||||
str(cookie_file),
|
||||
]
|
||||
for key, value in clean_headers.items():
|
||||
if value:
|
||||
@@ -305,7 +341,12 @@ def curl_fetch_bytes(url, headers=None, timeout=30):
|
||||
status = 0
|
||||
if 200 <= status < 300 and proc.returncode == 0:
|
||||
return payload
|
||||
message = (proc.stderr or b"curl media fetch failed").decode("utf-8", errors="replace").strip()
|
||||
client_name = Path(curl_bin).name
|
||||
detail = (proc.stderr or b"").decode("utf-8", errors="replace").strip()
|
||||
failures.append(f"{client_name}: HTTP {status or 0}" if status else f"{client_name}: exit {proc.returncode}")
|
||||
message = "; ".join(failures)
|
||||
if detail:
|
||||
message = f"{message} ({detail})"
|
||||
last_error = urllib.error.HTTPError(str(url), status or 0, message, hdrs={}, fp=None)
|
||||
raise last_error or RuntimeError("curl media fetch failed.")
|
||||
|
||||
@@ -314,9 +355,10 @@ def fetch_bytes(url, headers=None, timeout=30):
|
||||
client = str(os.environ.get("KAIZOKU_MEDIA_HTTP_CLIENT") or "auto").strip().lower()
|
||||
if client == "curl":
|
||||
return curl_fetch_bytes(url, headers=headers, timeout=timeout)
|
||||
request = urllib.request.Request(url, headers=request_headers(headers))
|
||||
request = media_request(url, headers=headers)
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||
MEDIA_COOKIE_JAR.extract_cookies(response, request)
|
||||
return response.read()
|
||||
except urllib.error.HTTPError as exc:
|
||||
if client != "urllib" and exc.code == 403 and curl_candidates():
|
||||
|
||||
Reference in New Issue
Block a user