Fix: Include backend/audio Django app in repository

This commit is contained in:
Iulian 2025-12-24 01:58:56 +00:00
parent d04e726373
commit 644cfab298
37 changed files with 6632 additions and 4 deletions

View file

@ -0,0 +1,354 @@
"""Quick Sync service for adaptive streaming based on network and system resources"""
import psutil
import time
import logging
import requests
from typing import Dict, Any, Optional, Tuple
from django.core.cache import cache
from django.conf import settings
logger = logging.getLogger(__name__)
class QuickSyncService:
"""Service for adaptive streaming quality based on network and system resources"""
# Quality presets
QUALITY_PRESETS = {
'low': {
'bitrate': 64, # kbps
'buffer_size': 5, # seconds
'preload': 'metadata',
'description': 'Low quality - saves bandwidth',
},
'medium': {
'bitrate': 128, # kbps
'buffer_size': 10, # seconds
'preload': 'auto',
'description': 'Medium quality - balanced',
},
'high': {
'bitrate': 256, # kbps
'buffer_size': 15, # seconds
'preload': 'auto',
'description': 'High quality - best experience',
},
'ultra': {
'bitrate': 320, # kbps
'buffer_size': 20, # seconds
'preload': 'auto',
'description': 'Ultra quality - maximum fidelity',
},
'auto': {
'bitrate': 0, # Auto-detect
'buffer_size': 0, # Auto-adjust
'preload': 'auto',
'description': 'Automatic - adapts to connection',
},
}
# Network speed thresholds (Mbps)
SPEED_THRESHOLDS = {
'ultra': 5.0, # 5 Mbps+
'high': 2.0, # 2-5 Mbps
'medium': 1.0, # 1-2 Mbps
'low': 0.5, # 0.5-1 Mbps
}
def __init__(self):
self.cache_timeout = 300 # 5 minutes
def get_system_resources(self) -> Dict[str, Any]:
"""
Get current system resource usage
Returns:
Dictionary with CPU, memory, and disk usage
"""
try:
resources = {
'cpu_percent': psutil.cpu_percent(interval=1),
'memory_percent': psutil.virtual_memory().percent,
'memory_available_mb': psutil.virtual_memory().available / (1024 * 1024),
'disk_usage_percent': psutil.disk_usage('/').percent,
'timestamp': time.time(),
}
# Cache the results
cache.set('quick_sync_system_resources', resources, self.cache_timeout)
return resources
except Exception as e:
logger.error(f"Error getting system resources: {e}")
return {
'cpu_percent': 50,
'memory_percent': 50,
'memory_available_mb': 1000,
'disk_usage_percent': 50,
'timestamp': time.time(),
}
def measure_network_speed(self, test_url: str = None, timeout: int = 5) -> float:
"""
Measure network download speed
Args:
test_url: URL to download for speed test
timeout: Request timeout in seconds
Returns:
Download speed in Mbps
"""
# Check cache first
cached_speed = cache.get('quick_sync_network_speed')
if cached_speed is not None:
return cached_speed
try:
# Use a small test file (1MB)
if not test_url:
# Use a reliable CDN for speed testing
test_url = 'https://speed.cloudflare.com/__down?bytes=1000000'
start_time = time.time()
response = requests.get(test_url, timeout=timeout, stream=True)
# Download 1MB
chunk_size = 8192
downloaded = 0
for chunk in response.iter_content(chunk_size=chunk_size):
downloaded += len(chunk)
if downloaded >= 1000000: # 1MB
break
elapsed = time.time() - start_time
# Calculate speed in Mbps
speed_mbps = (downloaded * 8) / (elapsed * 1000000)
# Cache the result
cache.set('quick_sync_network_speed', speed_mbps, self.cache_timeout)
logger.info(f"Network speed measured: {speed_mbps:.2f} Mbps")
return speed_mbps
except Exception as e:
logger.warning(f"Error measuring network speed: {e}")
# Return conservative estimate
return 2.0
def get_recommended_quality(self, user_preferences: Dict[str, Any] = None) -> Tuple[str, Dict[str, Any]]:
"""
Get recommended quality based on network speed and system resources
Args:
user_preferences: User's quick sync preferences
Returns:
Tuple of (quality_level, quality_settings)
"""
# Get user preferences
if not user_preferences:
user_preferences = {
'mode': 'auto',
'prefer_quality': True,
'adapt_to_system': True,
}
mode = user_preferences.get('mode', 'auto')
# If manual mode, return the specified quality
if mode != 'auto':
return mode, self.QUALITY_PRESETS[mode]
# Auto mode - detect optimal quality
network_speed = self.measure_network_speed()
system_resources = self.get_system_resources()
# Determine quality based on network speed
if network_speed >= self.SPEED_THRESHOLDS['ultra']:
quality = 'ultra'
elif network_speed >= self.SPEED_THRESHOLDS['high']:
quality = 'high'
elif network_speed >= self.SPEED_THRESHOLDS['medium']:
quality = 'medium'
else:
quality = 'low'
# Adjust based on system resources if enabled
if user_preferences.get('adapt_to_system', True):
cpu_percent = system_resources.get('cpu_percent', 50)
memory_percent = system_resources.get('memory_percent', 50)
# Downgrade quality if system is under heavy load
if cpu_percent > 80 or memory_percent > 85:
if quality == 'ultra':
quality = 'high'
elif quality == 'high':
quality = 'medium'
# Upgrade if system has plenty of resources and user prefers quality
elif cpu_percent < 30 and memory_percent < 50 and user_preferences.get('prefer_quality', False):
if quality == 'medium' and network_speed >= self.SPEED_THRESHOLDS['high']:
quality = 'high'
elif quality == 'high' and network_speed >= self.SPEED_THRESHOLDS['ultra']:
quality = 'ultra'
settings = self.QUALITY_PRESETS[quality].copy()
settings['auto_selected'] = True
settings['network_speed_mbps'] = network_speed
settings['cpu_percent'] = system_resources.get('cpu_percent')
settings['memory_percent'] = system_resources.get('memory_percent')
logger.info(f"Recommended quality: {quality} (speed: {network_speed:.2f} Mbps)")
return quality, settings
def get_buffer_settings(self, quality: str, network_speed: float = None) -> Dict[str, Any]:
"""
Get optimal buffer settings for quality level
Args:
quality: Quality level
network_speed: Current network speed in Mbps
Returns:
Buffer configuration
"""
base_settings = self.QUALITY_PRESETS.get(quality, self.QUALITY_PRESETS['medium'])
buffer_config = {
'buffer_size': base_settings['buffer_size'],
'preload': base_settings['preload'],
'max_buffer_size': base_settings['buffer_size'] * 2,
'rebuffer_threshold': base_settings['buffer_size'] * 0.3,
}
# Adjust based on network speed if provided
if network_speed:
if network_speed < 1.0:
# Slow connection - increase buffer
buffer_config['buffer_size'] = max(buffer_config['buffer_size'], 15)
buffer_config['preload'] = 'auto'
elif network_speed > 5.0:
# Fast connection - can use smaller buffer
buffer_config['buffer_size'] = min(buffer_config['buffer_size'], 10)
return buffer_config
def get_quick_sync_status(self, user_preferences: Dict[str, Any] = None) -> Dict[str, Any]:
"""
Get complete quick sync status and recommendations
Args:
user_preferences: User's quick sync preferences
Returns:
Complete status including network, system, and quality info
"""
network_speed = self.measure_network_speed()
system_resources = self.get_system_resources()
quality, quality_settings = self.get_recommended_quality(user_preferences)
buffer_settings = self.get_buffer_settings(quality, network_speed)
status = {
'network': {
'speed_mbps': network_speed,
'status': self._get_network_status(network_speed),
},
'system': {
'cpu_percent': system_resources['cpu_percent'],
'memory_percent': system_resources['memory_percent'],
'memory_available_mb': system_resources['memory_available_mb'],
'status': self._get_system_status(system_resources),
},
'quality': {
'level': quality,
'bitrate': quality_settings['bitrate'],
'description': quality_settings['description'],
'auto_selected': quality_settings.get('auto_selected', False),
},
'buffer': buffer_settings,
'timestamp': time.time(),
}
return status
def _get_network_status(self, speed_mbps: float) -> str:
"""Get network status description"""
if speed_mbps >= 5.0:
return 'excellent'
elif speed_mbps >= 2.0:
return 'good'
elif speed_mbps >= 1.0:
return 'fair'
else:
return 'poor'
def _get_system_status(self, resources: Dict[str, Any]) -> str:
"""Get system status description"""
cpu = resources.get('cpu_percent', 50)
memory = resources.get('memory_percent', 50)
if cpu > 80 or memory > 85:
return 'high_load'
elif cpu > 50 or memory > 70:
return 'moderate_load'
else:
return 'low_load'
def update_user_preferences(self, user_id: int, preferences: Dict[str, Any]) -> bool:
"""
Update user's quick sync preferences
Args:
user_id: User ID
preferences: New preferences
Returns:
True if successful
"""
try:
# Validate preferences
mode = preferences.get('mode', 'auto')
if mode not in self.QUALITY_PRESETS:
mode = 'auto'
prefs = {
'mode': mode,
'prefer_quality': preferences.get('prefer_quality', True),
'adapt_to_system': preferences.get('adapt_to_system', True),
'auto_download_quality': preferences.get('auto_download_quality', False),
}
# Cache user preferences
cache.set(f'quick_sync_prefs_{user_id}', prefs, timeout=None)
logger.info(f"Updated quick sync preferences for user {user_id}: {prefs}")
return True
except Exception as e:
logger.error(f"Error updating quick sync preferences: {e}")
return False
def get_user_preferences(self, user_id: int) -> Dict[str, Any]:
"""
Get user's quick sync preferences
Args:
user_id: User ID
Returns:
User preferences or defaults
"""
prefs = cache.get(f'quick_sync_prefs_{user_id}')
if prefs:
return prefs
# Return defaults
return {
'mode': 'auto',
'prefer_quality': True,
'adapt_to_system': True,
'auto_download_quality': False,
}