Fix Xbox proxy: Add proper header forwarding and streaming support

- Add query parameter forwarding (?api_key=... etc.)
- Add X-Forwarded-* headers for client IP tracking
- Exclude problematic headers (content-length, transfer-encoding, etc.)
- Add streaming support for large files (8KB chunks)
- Add root route handler
- Properly forward all HTTP methods
This commit is contained in:
mani
2026-01-09 00:12:50 +01:00
parent 6efda6b0bd
commit 485b809a63

View File

@@ -47,6 +47,7 @@ def filter_codecs(profile):
return profile return profile
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']) @app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
def proxy(path): def proxy(path):
"""Proxy all requests to Jellyfin, filter Xbox responses""" """Proxy all requests to Jellyfin, filter Xbox responses"""
@@ -54,9 +55,23 @@ def proxy(path):
is_xbox = 'xbox' in user_agent.lower() is_xbox = 'xbox' in user_agent.lower()
is_playback_info = 'PlaybackInfo' in path and request.method == 'POST' is_playback_info = 'PlaybackInfo' in path and request.method == 'POST'
# Forward request to Jellyfin # Build full URL with query parameters
url = f"{JELLYFIN_URL}/{path}" url = f"{JELLYFIN_URL}/{path}"
headers = {key: value for key, value in request.headers if key.lower() != 'host'} if request.query_string:
url += f"?{request.query_string.decode('utf-8')}"
# Copy headers, exclude problematic ones
headers = {}
excluded = ['host', 'connection', 'content-length', 'content-encoding', 'transfer-encoding']
for key, value in request.headers:
if key.lower() not in excluded:
headers[key] = value
# Add X-Forwarded-* headers for proper client tracking
headers['X-Forwarded-For'] = request.remote_addr
headers['X-Forwarded-Proto'] = request.scheme
headers['X-Forwarded-Host'] = request.host
headers['X-Real-IP'] = request.remote_addr
resp = requests.request( resp = requests.request(
method=request.method, method=request.method,
@@ -64,12 +79,14 @@ def proxy(path):
headers=headers, headers=headers,
data=request.get_data(), data=request.get_data(),
cookies=request.cookies, cookies=request.cookies,
allow_redirects=False allow_redirects=False,
stream=True # Support large file streaming
) )
# Filter response for Xbox PlaybackInfo requests # Filter response for Xbox PlaybackInfo requests
if is_xbox and is_playback_info and resp.status_code == 200: if is_xbox and is_playback_info and resp.status_code == 200:
try: try:
# Read full response for JSON manipulation
data = resp.json() data = resp.json()
# Filter DeviceProfile in request body (if sent back) # Filter DeviceProfile in request body (if sent back)
@@ -89,9 +106,11 @@ def proxy(path):
response.headers['Content-Type'] = 'application/json' response.headers['Content-Type'] = 'application/json'
except Exception as e: except Exception as e:
logger.error(f"Error filtering response: {e}") logger.error(f"Error filtering response: {e}")
response = Response(resp.content, status=resp.status_code) # Fallback to streaming response
response = Response(resp.iter_content(chunk_size=8192), status=resp.status_code)
else: else:
response = Response(resp.content, status=resp.status_code) # Stream response for large files (videos, etc.)
response = Response(resp.iter_content(chunk_size=8192), status=resp.status_code)
# Copy headers from Jellyfin response # Copy headers from Jellyfin response
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']