mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Added ability to send a next stream command.
This commit is contained in:
parent
ce6e019e6a
commit
e2d9e233da
4 changed files with 84 additions and 10 deletions
|
|
@ -888,7 +888,8 @@ class StreamManager:
|
|||
self.buffer.redis_client.hset(metadata_key, mapping={
|
||||
ChannelMetadataField.URL: new_url,
|
||||
ChannelMetadataField.USER_AGENT: new_user_agent,
|
||||
ChannelMetadataField.STREAM_PROFILE: stream_info['profile'],
|
||||
ChannelMetadataField.STREAM_PROFILE: stream_info['stream_profile'],
|
||||
ChannelMetadataField.M3U_PROFILE: stream_info['m3u_profile_id'],
|
||||
ChannelMetadataField.STREAM_ID: str(stream_id),
|
||||
ChannelMetadataField.STREAM_SWITCH_TIME: str(time.time()),
|
||||
ChannelMetadataField.STREAM_SWITCH_REASON: "max_retries_exceeded"
|
||||
|
|
|
|||
|
|
@ -132,21 +132,21 @@ def get_stream_info_for_switch(channel_id: str, target_stream_id: Optional[int]
|
|||
).first()
|
||||
|
||||
if default_profile:
|
||||
profile_id = default_profile.id
|
||||
m3u_profile_id = default_profile.id
|
||||
else:
|
||||
logger.error(f"No profile found for stream {stream_id}")
|
||||
return {'error': 'No profile found for stream'}
|
||||
else:
|
||||
# Use first available profile
|
||||
profile_id = profiles.first().id
|
||||
m3u_profile_id = profiles.first().id
|
||||
else:
|
||||
stream_id, profile_id = channel.get_stream()
|
||||
if stream_id is None or profile_id is None:
|
||||
stream_id, m3u_profile_id = channel.get_stream()
|
||||
if stream_id is None or m3u_profile_id is None:
|
||||
return {'error': 'No stream assigned to channel'}
|
||||
|
||||
# Get the stream and profile objects directly
|
||||
stream = get_object_or_404(Stream, pk=stream_id)
|
||||
profile = get_object_or_404(M3UAccountProfile, pk=profile_id)
|
||||
profile = get_object_or_404(M3UAccountProfile, pk=m3u_profile_id)
|
||||
|
||||
# Get the user agent from the M3U account
|
||||
m3u_account = M3UAccount.objects.get(id=profile.m3u_account.id)
|
||||
|
|
@ -166,9 +166,9 @@ def get_stream_info_for_switch(channel_id: str, target_stream_id: Optional[int]
|
|||
'url': stream_url,
|
||||
'user_agent': user_agent,
|
||||
'transcode': transcode,
|
||||
'profile': profile_value,
|
||||
'stream_profile': profile_value,
|
||||
'stream_id': stream_id,
|
||||
'profile_id': profile_id
|
||||
'm3u_profile_id': m3u_profile_id
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting stream info for switch: {e}", exc_info=True)
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ urlpatterns = [
|
|||
path('status/<str:channel_id>', views.channel_status, name='channel_status_detail'),
|
||||
path('stop/<str:channel_id>', views.stop_channel, name='stop_channel'),
|
||||
path('stop_client/<str:channel_id>', views.stop_client, name='stop_client'),
|
||||
path('next_stream/<str:channel_id>', views.next_stream, name='next_stream'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from rest_framework.permissions import IsAuthenticated
|
|||
from .constants import ChannelState, EventType, StreamType, ChannelMetadataField
|
||||
from .config_helper import ConfigHelper
|
||||
from .services.channel_service import ChannelService
|
||||
from .url_utils import generate_stream_url, transform_url, get_stream_info_for_switch, get_stream_object
|
||||
from .url_utils import generate_stream_url, transform_url, get_stream_info_for_switch, get_stream_object, get_alternate_streams
|
||||
from .utils import get_logger
|
||||
from uuid import UUID
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ def stream_ts(request, channel_id):
|
|||
|
||||
@csrf_exempt
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
#@permission_classes([IsAuthenticated])
|
||||
def change_stream(request, channel_id):
|
||||
"""Change stream URL for existing channel with enhanced diagnostics"""
|
||||
try:
|
||||
|
|
@ -337,3 +337,75 @@ def stop_client(request, channel_id):
|
|||
except Exception as e:
|
||||
logger.error(f"Failed to stop client: {e}", exc_info=True)
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
|
||||
@csrf_exempt
|
||||
@api_view(['POST'])
|
||||
#@permission_classes([IsAuthenticated])
|
||||
def next_stream(request, channel_id):
|
||||
"""Switch to the next available stream for a channel"""
|
||||
try:
|
||||
logger.info(f"Request to switch to next stream for channel {channel_id} received")
|
||||
|
||||
# Check if the channel exists
|
||||
channel = get_stream_object(channel_id)
|
||||
|
||||
# Get current stream info to know which one we're currently using
|
||||
current_stream_id, profile_id = channel.get_stream()
|
||||
|
||||
if not current_stream_id:
|
||||
return JsonResponse({'error': 'No current stream found for channel'}, status=404)
|
||||
|
||||
# Get alternate streams excluding the current one
|
||||
alternate_streams = get_alternate_streams(channel_id, current_stream_id)
|
||||
|
||||
if not alternate_streams:
|
||||
return JsonResponse({
|
||||
'error': 'No alternate streams available for this channel',
|
||||
'current_stream_id': current_stream_id
|
||||
}, status=404)
|
||||
|
||||
# Pick the next stream from alternatives
|
||||
next_stream = alternate_streams[0] # Get the first alternative
|
||||
next_stream_id = next_stream['stream_id']
|
||||
|
||||
# Get full stream info including URL for the next stream
|
||||
stream_info = get_stream_info_for_switch(channel_id, next_stream_id)
|
||||
|
||||
if 'error' in stream_info:
|
||||
return JsonResponse({
|
||||
'error': stream_info['error'],
|
||||
'current_stream_id': current_stream_id,
|
||||
'next_stream_id': next_stream_id
|
||||
}, status=404)
|
||||
|
||||
# Now use the ChannelService to change the stream URL
|
||||
result = ChannelService.change_stream_url(
|
||||
channel_id,
|
||||
stream_info['url'],
|
||||
stream_info['user_agent']
|
||||
)
|
||||
|
||||
if result.get('status') == 'error':
|
||||
return JsonResponse({
|
||||
'error': result.get('message', 'Unknown error'),
|
||||
'diagnostics': result.get('diagnostics', {}),
|
||||
'current_stream_id': current_stream_id,
|
||||
'next_stream_id': next_stream_id
|
||||
}, status=404)
|
||||
|
||||
# Format success response
|
||||
response_data = {
|
||||
'message': 'Stream switched to next available',
|
||||
'channel': channel_id,
|
||||
'previous_stream_id': current_stream_id,
|
||||
'new_stream_id': next_stream_id,
|
||||
'new_url': stream_info['url'],
|
||||
'owner': result.get('direct_update', False),
|
||||
'worker_id': proxy_server.worker_id
|
||||
}
|
||||
|
||||
return JsonResponse(response_data)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to switch to next stream: {e}", exc_info=True)
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue