diff --git a/apps/hdhr/api_views.py b/apps/hdhr/api_views.py index f4f174f3..8f1609d4 100644 --- a/apps/hdhr/api_views.py +++ b/apps/hdhr/api_views.py @@ -17,7 +17,6 @@ from django.views import View from django.utils.decorators import method_decorator from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt -from apps.m3u.models import M3UAccountProfile # Configure logger logger = logging.getLogger(__name__) @@ -60,43 +59,9 @@ class DiscoverAPIView(APIView): base_url = request.build_absolute_uri(f'/{"/".join(uri_parts)}/').rstrip("/") device = HDHRDevice.objects.first() - # Calculate tuner count from active profiles from active M3U accounts (excluding default "custom Default" profile) - profiles = M3UAccountProfile.objects.filter( - is_active=True, - m3u_account__is_active=True, # Only include profiles from enabled M3U accounts - ).exclude(id=1) - - # 1. Check if any profile has unlimited streams (max_streams=0) - has_unlimited = profiles.filter(max_streams=0).exists() - - # 2. Calculate tuner count from limited profiles - limited_tuners = 0 - if not has_unlimited: - limited_tuners = ( - profiles.filter(max_streams__gt=0) - .aggregate(total=models.Sum("max_streams")) - .get("total", 0) - or 0 - ) - - # 3. Add custom stream count to tuner count - custom_stream_count = Stream.objects.filter(is_custom=True).count() - logger.debug(f"Found {custom_stream_count} custom streams") - - # 4. Calculate final tuner count - if has_unlimited: - # If there are unlimited profiles, start with 10 plus custom streams - tuner_count = 10 + custom_stream_count - else: - # Otherwise use the limited profile sum plus custom streams - tuner_count = limited_tuners + custom_stream_count - - # 5. Ensure minimum of 1 tuners - tuner_count = max(1, tuner_count) - - logger.debug( - f"Calculated tuner count: {tuner_count} (limited profiles: {limited_tuners}, custom streams: {custom_stream_count}, unlimited: {has_unlimited})" - ) + # Calculate tuner count using centralized function + from apps.m3u.utils import calculate_tuner_count + tuner_count = calculate_tuner_count(minimum=1, unlimited_default=10) # Create a unique DeviceID for the HDHomeRun device based on profile ID or a default value device_ID = "12345678" # Default DeviceID diff --git a/apps/m3u/utils.py b/apps/m3u/utils.py index 784188ba..4e1027b2 100644 --- a/apps/m3u/utils.py +++ b/apps/m3u/utils.py @@ -1,9 +1,12 @@ # apps/m3u/utils.py import threading +import logging +from django.db import models lock = threading.Lock() # Dictionary to track usage: {m3u_account_id: current_usage} active_streams_map = {} +logger = logging.getLogger(__name__) def increment_stream_count(account): with lock: @@ -24,3 +27,64 @@ def decrement_stream_count(account): active_streams_map[account.id] = current_usage account.active_streams = current_usage account.save(update_fields=['active_streams']) + + +def calculate_tuner_count(minimum=1, unlimited_default=10): + """ + Calculate tuner/connection count from active M3U profiles and custom streams. + This is the centralized function used by both HDHR and XtreamCodes APIs. + + Args: + minimum (int): Minimum number to return (default: 1) + unlimited_default (int): Default value when unlimited profiles exist (default: 10) + + Returns: + int: Calculated tuner/connection count + """ + try: + from apps.m3u.models import M3UAccountProfile + from apps.channels.models import Stream + + # Calculate tuner count from active profiles from active M3U accounts (excluding default "custom Default" profile) + profiles = M3UAccountProfile.objects.filter( + is_active=True, + m3u_account__is_active=True, # Only include profiles from enabled M3U accounts + ).exclude(id=1) + + # 1. Check if any profile has unlimited streams (max_streams=0) + has_unlimited = profiles.filter(max_streams=0).exists() + + # 2. Calculate tuner count from limited profiles + limited_tuners = 0 + if not has_unlimited: + limited_tuners = ( + profiles.filter(max_streams__gt=0) + .aggregate(total=models.Sum("max_streams")) + .get("total", 0) + or 0 + ) + + # 3. Add custom stream count to tuner count + custom_stream_count = Stream.objects.filter(is_custom=True).count() + logger.debug(f"Found {custom_stream_count} custom streams") + + # 4. Calculate final tuner count + if has_unlimited: + # If there are unlimited profiles, start with unlimited_default plus custom streams + tuner_count = unlimited_default + custom_stream_count + else: + # Otherwise use the limited profile sum plus custom streams + tuner_count = limited_tuners + custom_stream_count + + # 5. Ensure minimum number + tuner_count = max(minimum, tuner_count) + + logger.debug( + f"Calculated tuner count: {tuner_count} (limited profiles: {limited_tuners}, custom streams: {custom_stream_count}, unlimited: {has_unlimited})" + ) + + return tuner_count + + except Exception as e: + logger.error(f"Error calculating tuner count: {e}") + return minimum # Fallback to minimum value diff --git a/apps/output/views.py b/apps/output/views.py index 79e3594a..33e932a9 100644 --- a/apps/output/views.py +++ b/apps/output/views.py @@ -20,6 +20,7 @@ from urllib.parse import urlparse import base64 import logging import os +from apps.m3u.utils import calculate_tuner_count logger = logging.getLogger(__name__) @@ -733,7 +734,7 @@ def xc_get_info(request, full=False): "auth": 1, "status": "Active", "exp_date": str(int(time.time()) + (90 * 24 * 60 * 60)), - "max_connections": "99", + "max_connections": str(calculate_tuner_count(minimum=1, unlimited_default=50)), "allowed_output_formats": [ "ts", ],