mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-28 12:36:42 +00:00
Fixes stream switches not honouring user selected order.
This commit is contained in:
parent
e2d9e233da
commit
2f995b16fd
3 changed files with 42 additions and 24 deletions
|
|
@ -95,6 +95,7 @@ class ChannelService:
|
|||
dict: Result information including success status and diagnostics
|
||||
"""
|
||||
# If no direct URL is provided but a target stream is, get URL from target stream
|
||||
stream_id = None
|
||||
if not new_url and target_stream_id:
|
||||
stream_info = get_stream_info_for_switch(channel_id, target_stream_id)
|
||||
if 'error' in stream_info:
|
||||
|
|
@ -104,6 +105,10 @@ class ChannelService:
|
|||
}
|
||||
new_url = stream_info['url']
|
||||
user_agent = stream_info['user_agent']
|
||||
stream_id = target_stream_id
|
||||
elif target_stream_id:
|
||||
# If we have both URL and target_stream_id, use the target_stream_id
|
||||
stream_id = target_stream_id
|
||||
|
||||
# Check if channel exists
|
||||
in_local_managers = channel_id in proxy_server.stream_managers
|
||||
|
|
@ -155,7 +160,7 @@ class ChannelService:
|
|||
# Update metadata in Redis regardless of ownership
|
||||
if proxy_server.redis_client:
|
||||
try:
|
||||
ChannelService._update_channel_metadata(channel_id, new_url, user_agent)
|
||||
ChannelService._update_channel_metadata(channel_id, new_url, user_agent, stream_id)
|
||||
result['metadata_updated'] = True
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating Redis metadata: {e}", exc_info=True)
|
||||
|
|
@ -180,7 +185,7 @@ class ChannelService:
|
|||
# If we're not the owner, publish an event for the owner to pick up
|
||||
logger.info(f"Not the owner, requesting URL change via Redis PubSub")
|
||||
if proxy_server.redis_client:
|
||||
ChannelService._publish_stream_switch_event(channel_id, new_url, user_agent)
|
||||
ChannelService._publish_stream_switch_event(channel_id, new_url, user_agent, stream_id)
|
||||
result.update({
|
||||
'direct_update': False,
|
||||
'event_published': True,
|
||||
|
|
@ -400,7 +405,7 @@ class ChannelService:
|
|||
# Helper methods for Redis operations
|
||||
|
||||
@staticmethod
|
||||
def _update_channel_metadata(channel_id, url, user_agent=None):
|
||||
def _update_channel_metadata(channel_id, url, user_agent=None, stream_id=None):
|
||||
"""Update channel metadata in Redis"""
|
||||
if not proxy_server.redis_client:
|
||||
return False
|
||||
|
|
@ -411,23 +416,22 @@ class ChannelService:
|
|||
key_type = proxy_server.redis_client.type(metadata_key).decode('utf-8')
|
||||
logger.debug(f"Redis key {metadata_key} is of type: {key_type}")
|
||||
|
||||
# Build metadata update dict
|
||||
metadata = {ChannelMetadataField.URL: url}
|
||||
if user_agent:
|
||||
metadata[ChannelMetadataField.USER_AGENT] = user_agent
|
||||
if stream_id:
|
||||
metadata[ChannelMetadataField.STREAM_ID] = str(stream_id)
|
||||
logger.info(f"Updating stream ID to {stream_id} in Redis for channel {channel_id}")
|
||||
|
||||
# Use the appropriate method based on the key type
|
||||
if key_type == 'hash':
|
||||
proxy_server.redis_client.hset(metadata_key, ChannelMetadataField.URL, url)
|
||||
if user_agent:
|
||||
proxy_server.redis_client.hset(metadata_key, ChannelMetadataField.USER_AGENT, user_agent)
|
||||
proxy_server.redis_client.hset(metadata_key, mapping=metadata)
|
||||
elif key_type == 'none': # Key doesn't exist yet
|
||||
# Create new hash with all required fields
|
||||
metadata = {ChannelMetadataField.URL: url}
|
||||
if user_agent:
|
||||
metadata[ChannelMetadataField.USER_AGENT] = user_agent
|
||||
proxy_server.redis_client.hset(metadata_key, mapping=metadata)
|
||||
else:
|
||||
# If key exists with wrong type, delete it and recreate
|
||||
proxy_server.redis_client.delete(metadata_key)
|
||||
metadata = {ChannelMetadataField.URL: url}
|
||||
if user_agent:
|
||||
metadata[ChannelMetadataField.USER_AGENT] = user_agent
|
||||
proxy_server.redis_client.hset(metadata_key, mapping=metadata)
|
||||
|
||||
# Set switch request flag to ensure all workers see it
|
||||
|
|
@ -438,7 +442,7 @@ class ChannelService:
|
|||
return True
|
||||
|
||||
@staticmethod
|
||||
def _publish_stream_switch_event(channel_id, new_url, user_agent=None):
|
||||
def _publish_stream_switch_event(channel_id, new_url, user_agent=None, stream_id=None):
|
||||
"""Publish a stream switch event to Redis pubsub"""
|
||||
if not proxy_server.redis_client:
|
||||
return False
|
||||
|
|
@ -448,6 +452,7 @@ class ChannelService:
|
|||
"channel_id": channel_id,
|
||||
"url": new_url,
|
||||
"user_agent": user_agent,
|
||||
"stream_id": stream_id,
|
||||
"requester": proxy_server.worker_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,8 +194,8 @@ def get_alternate_streams(channel_id: str, current_stream_id: Optional[int] = No
|
|||
|
||||
logger.debug(f"Looking for alternate streams for channel {channel_id}, current stream ID: {current_stream_id}")
|
||||
|
||||
# Get all assigned streams for this channel
|
||||
streams = channel.streams.all()
|
||||
# Get all assigned streams for this channel using the correct ordering from the channelstream table
|
||||
streams = channel.streams.all().order_by('channelstream__order')
|
||||
logger.debug(f"Channel {channel_id} has {streams.count()} total assigned streams")
|
||||
|
||||
if not streams.exists():
|
||||
|
|
@ -204,7 +204,7 @@ def get_alternate_streams(channel_id: str, current_stream_id: Optional[int] = No
|
|||
|
||||
alternate_streams = []
|
||||
|
||||
# Process each stream
|
||||
# Process each stream in the user-defined order
|
||||
for stream in streams:
|
||||
# Log each stream we're checking
|
||||
logger.debug(f"Checking stream ID {stream.id} ({stream.name}) for channel {channel_id}")
|
||||
|
|
@ -215,8 +215,6 @@ def get_alternate_streams(channel_id: str, current_stream_id: Optional[int] = No
|
|||
continue
|
||||
|
||||
# Find compatible profiles for this stream
|
||||
# FIX: Looking at the error message, M3UAccountProfile doesn't have a 'stream' field
|
||||
# We need to find which field relates M3UAccountProfile to Stream
|
||||
try:
|
||||
# Check if we can find profiles via m3u_account
|
||||
profiles = M3UAccountProfile.objects.filter(m3u_account=stream.m3u_account)
|
||||
|
|
|
|||
|
|
@ -346,13 +346,27 @@ def next_stream(request, channel_id):
|
|||
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)
|
||||
# First check if channel is active in Redis
|
||||
current_stream_id = None
|
||||
profile_id = None
|
||||
|
||||
# Get current stream info to know which one we're currently using
|
||||
current_stream_id, profile_id = channel.get_stream()
|
||||
if proxy_server.redis_client:
|
||||
metadata_key = RedisKeys.channel_metadata(channel_id)
|
||||
if proxy_server.redis_client.exists(metadata_key):
|
||||
# Get current stream ID from Redis
|
||||
stream_id_bytes = proxy_server.redis_client.hget(metadata_key, ChannelMetadataField.STREAM_ID)
|
||||
if stream_id_bytes:
|
||||
current_stream_id = int(stream_id_bytes.decode('utf-8'))
|
||||
logger.info(f"Found current stream ID {current_stream_id} in Redis for channel {channel_id}")
|
||||
|
||||
# Get M3U profile from Redis if available
|
||||
profile_id_bytes = proxy_server.redis_client.hget(metadata_key, ChannelMetadataField.M3U_PROFILE)
|
||||
if profile_id_bytes:
|
||||
profile_id = int(profile_id_bytes.decode('utf-8'))
|
||||
logger.info(f"Found M3U profile ID {profile_id} in Redis for channel {channel_id}")
|
||||
|
||||
if not current_stream_id:
|
||||
# Channel is not running
|
||||
return JsonResponse({'error': 'No current stream found for channel'}, status=404)
|
||||
|
||||
# Get alternate streams excluding the current one
|
||||
|
|
@ -382,7 +396,8 @@ def next_stream(request, channel_id):
|
|||
result = ChannelService.change_stream_url(
|
||||
channel_id,
|
||||
stream_info['url'],
|
||||
stream_info['user_agent']
|
||||
stream_info['user_agent'],
|
||||
next_stream_id # Pass the stream_id to be stored in Redis
|
||||
)
|
||||
|
||||
if result.get('status') == 'error':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue