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:
@@ -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']
|
||||||
|
|||||||
Reference in New Issue
Block a user