118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
import requests
|
|
from django.conf import settings
|
|
from django.core.cache import cache
|
|
from functools import wraps
|
|
from django.shortcuts import redirect
|
|
from django.contrib import messages
|
|
|
|
class JellyfinClient:
|
|
def __init__(self):
|
|
# Base settings from Django settings
|
|
self.client = settings.JELLYFIN_CLIENT
|
|
self.version = settings.JELLYFIN_VERSION
|
|
self.device = settings.JELLYFIN_DEVICE
|
|
self.device_id = settings.JELLYFIN_DEVICE_ID
|
|
self.server_url = None # Wird später gesetzt
|
|
self.api_key = None # Optional, wird aus den AppSettings geholt wenn nötig
|
|
|
|
def authenticate(self, username, password):
|
|
"""Authenticate with Jellyfin and return user info if successful"""
|
|
if not self.server_url:
|
|
raise ValueError("No server URL provided")
|
|
|
|
# Ensure the URL has a protocol
|
|
if not self.server_url.startswith(('http://', 'https://')):
|
|
self.server_url = f'http://{self.server_url}'
|
|
|
|
# Remove trailing slashes
|
|
self.server_url = self.server_url.rstrip('/')
|
|
|
|
headers = {
|
|
'X-Emby-Authorization': (
|
|
f'MediaBrowser Client="{self.client}", '
|
|
f'Device="{self.device}", '
|
|
f'DeviceId="{self.device_id}", '
|
|
f'Version="{self.version}"'
|
|
)
|
|
}
|
|
|
|
auth_data = {
|
|
'Username': username,
|
|
'Pw': password
|
|
}
|
|
|
|
try:
|
|
response = requests.post(
|
|
f'{self.server_url}/Users/AuthenticateByName',
|
|
json=auth_data,
|
|
headers=headers,
|
|
timeout=10
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
return {
|
|
'user_id': data['User']['Id'],
|
|
'access_token': data['AccessToken'],
|
|
'is_admin': data['User'].get('Policy', {}).get('IsAdministrator', False)
|
|
}
|
|
except requests.exceptions.ConnectionError:
|
|
raise ValueError("Unable to connect to the server. Please check the server URL.")
|
|
except requests.exceptions.Timeout:
|
|
raise ValueError("Connection to the server timed out.")
|
|
except requests.exceptions.HTTPError as e:
|
|
if e.response.status_code == 401:
|
|
return None # Authentifizierung fehlgeschlagen
|
|
raise ValueError(f"HTTP error: {e.response.status_code}")
|
|
except Exception as e:
|
|
return None
|
|
|
|
def is_admin(self, user_id, token):
|
|
"""Check if user is admin in Jellyfin"""
|
|
cache_key = f'jellyfin_admin_{user_id}'
|
|
|
|
# Check cache first
|
|
cached = cache.get(cache_key)
|
|
if cached is not None:
|
|
return cached
|
|
|
|
headers = {
|
|
'X-Emby-Authorization': (
|
|
f'MediaBrowser Client="{self.client}", '
|
|
f'Device="{self.device}", '
|
|
f'DeviceId="{self.device_id}", '
|
|
f'Version="{self.version}", '
|
|
f'Token="{token}"'
|
|
)
|
|
}
|
|
|
|
try:
|
|
response = requests.get(
|
|
f'{self.server_url}/Users/{user_id}',
|
|
headers=headers
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
is_admin = data.get('Policy', {}).get('IsAdministrator', False)
|
|
|
|
# Cache result for 5 minutes
|
|
cache.set(cache_key, is_admin, 300)
|
|
|
|
return is_admin
|
|
except:
|
|
return False
|
|
|
|
def jellyfin_admin_required(view_func):
|
|
@wraps(view_func)
|
|
def _wrapped_view(request, *args, **kwargs):
|
|
if not request.user.is_authenticated:
|
|
messages.error(request, 'You must be logged in to view this page.')
|
|
return redirect('accounts:login')
|
|
|
|
if not request.user.is_jellyfin_admin:
|
|
messages.error(request, 'You need admin rights to view this page.')
|
|
return redirect('index')
|
|
|
|
return view_func(request, *args, **kwargs)
|
|
return _wrapped_view
|