backend improvements

This commit is contained in:
Simon
2026-02-12 17:40:45 +00:00
parent 7ba8896405
commit d73e413352

View File

@@ -277,7 +277,7 @@ def stream_video():
return forwarded_headers return forwarded_headers
def proxy_response(target_url, content_type_override=None, referer_override=None): def proxy_response(target_url, content_type_override=None, referer_override=None, upstream_headers=None):
# Extract the base domain to spoof the referer # Extract the base domain to spoof the referer
request_referer = request.args.get('referer') request_referer = request.args.get('referer')
if referer_override: if referer_override:
@@ -290,6 +290,10 @@ def stream_video():
dbg(f"proxy_response target={target_url} referer={referer}") dbg(f"proxy_response target={target_url} referer={referer}")
safe_request_headers = build_upstream_headers(referer) safe_request_headers = build_upstream_headers(referer)
if isinstance(upstream_headers, dict):
for key, value in upstream_headers.items():
if value:
safe_request_headers[key] = value
# Pass through Range headers so the browser can 'sniff' the video # Pass through Range headers so the browser can 'sniff' the video
if 'Range' in request.headers: if 'Range' in request.headers:
@@ -315,9 +319,12 @@ def stream_video():
encoding = resp.encoding encoding = resp.encoding
resp.close() resp.close()
dbg("detected m3u8 by content sniff") dbg("detected m3u8 by content sniff")
upstream_for_playlist = dict(safe_request_headers)
upstream_for_playlist.pop('Range', None)
return proxy_hls_playlist( return proxy_hls_playlist(
target_url, target_url,
referer_hint=referer, referer_hint=referer,
upstream_headers=upstream_for_playlist,
prefetched_body=body_bytes, prefetched_body=body_bytes,
prefetched_base_url=base_url, prefetched_base_url=base_url,
prefetched_encoding=encoding, prefetched_encoding=encoding,
@@ -378,20 +385,39 @@ def stream_video():
body = "\n".join(rewritten) body = "\n".join(rewritten)
return Response(body, status=200, content_type='application/vnd.apple.mpegurl') return Response(body, status=200, content_type='application/vnd.apple.mpegurl')
def proxy_hls_playlist(playlist_url, referer_hint=None, prefetched_body=None, prefetched_base_url=None, prefetched_encoding=None): def proxy_hls_playlist(playlist_url, referer_hint=None, prefetched_body=None, prefetched_base_url=None, prefetched_encoding=None, upstream_headers=None):
dbg(f"proxy_hls_playlist url={playlist_url} referer_hint={referer_hint}") dbg(f"proxy_hls_playlist url={playlist_url} referer_hint={referer_hint}")
base_url = prefetched_base_url or playlist_url base_url = prefetched_base_url or playlist_url
body_text = None body_text = None
if prefetched_body is None: if prefetched_body is None:
headers = build_upstream_headers(referer_hint or "") headers = build_upstream_headers(referer_hint or "")
if isinstance(upstream_headers, dict):
for key, value in upstream_headers.items():
if value:
headers[key] = value
if 'User-Agent' not in headers: if 'User-Agent' not in headers:
headers['User-Agent'] = 'Mozilla/5.0' headers['User-Agent'] = 'Mozilla/5.0'
if 'Accept' not in headers: if 'Accept' not in headers:
headers['Accept'] = '*/*' headers['Accept'] = '*/*'
resp = session.get(playlist_url, headers=headers, stream=True, timeout=30) resp = session.get(playlist_url, headers=headers, stream=True, timeout=30)
resp.raise_for_status()
base_url = resp.url base_url = resp.url
if resp.status_code >= 400:
forwarded_headers = build_forwarded_headers(resp, target_url=base_url)
if request.method == 'HEAD':
resp.close()
return Response("", status=resp.status_code, headers=forwarded_headers)
def generate():
try:
for chunk in resp.iter_content(chunk_size=1024 * 16):
if chunk:
yield chunk
finally:
resp.close()
return Response(generate(), status=resp.status_code, headers=forwarded_headers)
if request.method == 'HEAD': if request.method == 'HEAD':
forwarded_headers = build_forwarded_headers(resp, target_url=base_url) forwarded_headers = build_forwarded_headers(resp, target_url=base_url)
resp.close() resp.close()
@@ -459,6 +485,11 @@ def stream_video():
except Exception as e: except Exception as e:
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
def extract_referer(headers):
if not isinstance(headers, dict):
return None
return headers.get('Referer') or headers.get('referer')
try: try:
# Configure yt-dlp options # Configure yt-dlp options
ydl_opts = { ydl_opts = {
@@ -488,21 +519,41 @@ def stream_video():
# Try to get the URL from the info dict (works for progressive downloads) # Try to get the URL from the info dict (works for progressive downloads)
stream_url = info.get('url') stream_url = info.get('url')
protocol = info.get('protocol') protocol = info.get('protocol')
selected_format = None
# If no direct URL, try to get it from formats # If no direct URL, try to get it from formats
if not stream_url and 'formats' in info: if 'formats' in info:
# Find the best format that has a URL if info.get('format_id'):
for fmt in info['formats']: for fmt in info['formats']:
if fmt.get('url'): if fmt.get('format_id') == info.get('format_id'):
stream_url = fmt.get('url') selected_format = fmt
break break
if not selected_format and stream_url:
for fmt in info['formats']:
if fmt.get('url') == stream_url:
selected_format = fmt
break
if not selected_format:
for fmt in info['formats']:
if fmt.get('url'):
selected_format = fmt
break
if not stream_url and selected_format:
stream_url = selected_format.get('url')
if not stream_url: if not stream_url:
return jsonify({"error": "Could not extract stream URL"}), 500 return jsonify({"error": "Could not extract stream URL"}), 500
upstream_headers = None
if selected_format and isinstance(selected_format.get('http_headers'), dict):
upstream_headers = selected_format['http_headers']
elif isinstance(info.get('http_headers'), dict):
upstream_headers = info['http_headers']
referer_hint = None referer_hint = None
if isinstance(info.get('http_headers'), dict): if upstream_headers:
referer_hint = info['http_headers'].get('Referer') or info['http_headers'].get('referer') referer_hint = extract_referer(upstream_headers)
if not referer_hint: if not referer_hint:
parsed = urllib.parse.urlparse(video_url) parsed = urllib.parse.urlparse(video_url)
referer_hint = f"{parsed.scheme}://{parsed.netloc}/" referer_hint = f"{parsed.scheme}://{parsed.netloc}/"
@@ -510,18 +561,18 @@ def stream_video():
if protocol and 'm3u8' in protocol: if protocol and 'm3u8' in protocol:
dbg("protocol indicates hls") dbg("protocol indicates hls")
return proxy_hls_playlist(stream_url, referer_hint) return proxy_hls_playlist(stream_url, referer_hint, upstream_headers=upstream_headers)
if is_hls(stream_url): if is_hls(stream_url):
dbg("stream_url is hls") dbg("stream_url is hls")
return proxy_hls_playlist(stream_url, referer_hint) return proxy_hls_playlist(stream_url, referer_hint, upstream_headers=upstream_headers)
if is_dash(stream_url): if is_dash(stream_url):
dbg("stream_url is dash") dbg("stream_url is dash")
return proxy_response(stream_url, content_type_override='application/dash+xml', referer_override=referer_hint) return proxy_response(stream_url, content_type_override='application/dash+xml', referer_override=referer_hint, upstream_headers=upstream_headers)
dbg("stream_url is direct media") dbg("stream_url is direct media")
return proxy_response(stream_url, referer_override=referer_hint) return proxy_response(stream_url, referer_override=referer_hint, upstream_headers=upstream_headers)
except Exception as e: except Exception as e:
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500