diff --git a/apps/proxy/hls_proxy/views.py b/apps/proxy/hls_proxy/views.py index 18622771..eaf0f1cd 100644 --- a/apps/proxy/hls_proxy/views.py +++ b/apps/proxy/hls_proxy/views.py @@ -1,39 +1,80 @@ +import json +import threading +import logging from django.http import StreamingHttpResponse, JsonResponse, HttpResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods -import json from .server import ProxyServer, Config +logger = logging.getLogger(__name__) proxy_server = ProxyServer() +@csrf_exempt @require_http_methods(["GET"]) def stream_endpoint(request, channel_id): - """Serve HLS manifest""" + """Handle HLS manifest requests""" + if channel_id not in proxy_server.stream_managers: + return JsonResponse({'error': 'Channel not found'}, status=404) + response = proxy_server.stream_endpoint(channel_id) return StreamingHttpResponse( - response.response[0], + response[0], content_type='application/vnd.apple.mpegurl', - status=response.status_code + status=response[1] ) -@require_http_methods(["GET"]) -def get_segment(request, channel_id, segment_name): +@csrf_exempt +@require_http_methods(["GET"]) +def get_segment(request, segment_name): """Serve MPEG-TS segments""" - response = proxy_server.get_segment(channel_id, segment_name) - if response[1] == 404: - return HttpResponse(status=404) - return StreamingHttpResponse(response[0], content_type='video/MP2T') + try: + segment_num = int(segment_name.split('.')[0]) + buffer = proxy_server.stream_buffers.get(segment_num) + + if not buffer: + return JsonResponse({'error': 'Segment not found'}, status=404) + + return StreamingHttpResponse( + buffer, + content_type='video/MP2T' + ) + except ValueError: + return JsonResponse({'error': 'Invalid segment name'}, status=400) + except Exception as e: + logger.error(f"Error serving segment: {e}") + return JsonResponse({'error': str(e)}, status=500) @csrf_exempt @require_http_methods(["POST"]) def change_stream(request, channel_id): - """Handle stream URL changes""" + """Change stream URL for existing channel""" try: + if channel_id not in proxy_server.stream_managers: + return JsonResponse({'error': 'Channel not found'}, status=404) + data = json.loads(request.body) - response = proxy_server.change_stream(channel_id) - return JsonResponse(response[0], status=response[1]) + new_url = data.get('url') + if not new_url: + return JsonResponse({'error': 'No URL provided'}, status=400) + + manager = proxy_server.stream_managers[channel_id] + if manager.update_url(new_url): + return JsonResponse({ + 'message': 'Stream URL updated', + 'channel': channel_id, + 'url': new_url + }) + + return JsonResponse({ + 'message': 'URL unchanged', + 'channel': channel_id, + 'url': new_url + }) except json.JSONDecodeError: return JsonResponse({'error': 'Invalid JSON'}, status=400) + except Exception as e: + logger.error(f"Failed to change stream: {e}") + return JsonResponse({'error': str(e)}, status=500) @csrf_exempt @require_http_methods(["POST"]) @@ -52,4 +93,7 @@ def initialize_stream(request, channel_id): 'url': url }) except json.JSONDecodeError: - return JsonResponse({'error': 'Invalid JSON'}, status=400) \ No newline at end of file + return JsonResponse({'error': 'Invalid JSON'}, status=400) + except Exception as e: + logger.error(f"Failed to initialize stream: {e}") + return JsonResponse({'error': str(e)}, status=500) \ No newline at end of file diff --git a/apps/proxy/ts_proxy/views.py b/apps/proxy/ts_proxy/views.py index a8ad70b4..f15a4b49 100644 --- a/apps/proxy/ts_proxy/views.py +++ b/apps/proxy/ts_proxy/views.py @@ -1,26 +1,30 @@ +import json +import threading +import logging from django.http import StreamingHttpResponse, JsonResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods -import json from .server import ProxyServer +logger = logging.getLogger(__name__) proxy_server = ProxyServer() +@csrf_exempt @require_http_methods(["GET"]) def stream_ts(request, channel_id): """Handle TS stream requests""" if channel_id not in proxy_server.stream_managers: - return StreamingHttpResponse('Channel not found', status=404) + return JsonResponse({'error': 'Channel not found'}, status=404) def generate(): client_id = threading.get_ident() - buffer = proxy_server.stream_buffers[channel_id] - client_manager = proxy_server.client_managers[channel_id] - - client_manager.add_client(client_id) - last_index = buffer.index - try: + buffer = proxy_server.stream_buffers[channel_id] + client_manager = proxy_server.client_managers[channel_id] + + client_manager.add_client(client_id) + last_index = buffer.index + while True: with buffer.lock: if buffer.index > last_index: @@ -31,11 +35,14 @@ def stream_ts(request, channel_id): yield buffer.buffer[i] last_index = buffer.index - time.sleep(Config.CLIENT_POLL_INTERVAL) - except Exception: - remaining = client_manager.remove_client(client_id) - if remaining == 0: - proxy_server.stop_channel(channel_id) + threading.Event().wait(0.1) # Short sleep between checks + + except Exception as e: + logger.error(f"Streaming error for channel {channel_id}: {e}") + if channel_id in proxy_server.client_managers: + remaining = proxy_server.client_managers[channel_id].remove_client(client_id) + if remaining == 0: + proxy_server.stop_channel(channel_id) raise return StreamingHttpResponse( @@ -43,34 +50,6 @@ def stream_ts(request, channel_id): content_type='video/MP2T' ) -@csrf_exempt -@require_http_methods(["POST"]) -def change_stream(request, channel_id): - """Handle stream URL changes""" - try: - data = json.loads(request.body) - new_url = data.get('url') - if not new_url: - return JsonResponse({'error': 'No URL provided'}, status=400) - - if channel_id not in proxy_server.stream_managers: - return JsonResponse({'error': 'Channel not found'}, status=404) - - manager = proxy_server.stream_managers[channel_id] - if manager.update_url(new_url): - return JsonResponse({ - 'message': 'Stream URL updated', - 'channel': channel_id, - 'url': new_url - }) - return JsonResponse({ - 'message': 'URL unchanged', - 'channel': channel_id, - 'url': new_url - }) - except json.JSONDecodeError: - return JsonResponse({'error': 'Invalid JSON'}, status=400) - @csrf_exempt @require_http_methods(["POST"]) def initialize_stream(request, channel_id): @@ -88,4 +67,39 @@ def initialize_stream(request, channel_id): 'url': url }) except json.JSONDecodeError: - return JsonResponse({'error': 'Invalid JSON'}, status=400) \ No newline at end of file + return JsonResponse({'error': 'Invalid JSON'}, status=400) + except Exception as e: + logger.error(f"Failed to initialize stream: {e}") + return JsonResponse({'error': str(e)}, status=500) + +@csrf_exempt +@require_http_methods(["POST"]) +def change_stream(request, channel_id): + """Change stream URL for existing channel""" + try: + if channel_id not in proxy_server.stream_managers: + return JsonResponse({'error': 'Channel not found'}, status=404) + + data = json.loads(request.body) + new_url = data.get('url') + if not new_url: + return JsonResponse({'error': 'No URL provided'}, status=400) + + manager = proxy_server.stream_managers[channel_id] + if manager.update_url(new_url): + return JsonResponse({ + 'message': 'Stream URL updated', + 'channel': channel_id, + 'url': new_url + }) + + return JsonResponse({ + 'message': 'URL unchanged', + 'channel': channel_id, + 'url': new_url + }) + except json.JSONDecodeError: + return JsonResponse({'error': 'Invalid JSON'}, status=400) + except Exception as e: + logger.error(f"Failed to change stream: {e}") + return JsonResponse({'error': str(e)}, status=500) \ No newline at end of file