Generate the appropriate stream URL for a channel or stream based on its profile settings. Returns: Tuple: (stream_url, user_agent, transcode_flag, profile_id, slot_reserved, error_reason)
(
channel_id: str,
)
| 59 | return get_object_or_404(Stream, stream_hash=id) |
| 60 | |
| 61 | def generate_stream_url( |
| 62 | channel_id: str, |
| 63 | ) -> Tuple[str, str, bool, Optional[int], bool, Optional[str]]: |
| 64 | """ |
| 65 | Generate the appropriate stream URL for a channel or stream based on its profile settings. |
| 66 | |
| 67 | Returns: |
| 68 | Tuple: (stream_url, user_agent, transcode_flag, profile_id, slot_reserved, error_reason) |
| 69 | """ |
| 70 | try: |
| 71 | channel_or_stream = get_stream_object(channel_id) |
| 72 | |
| 73 | # Handle direct stream preview (custom streams) |
| 74 | if isinstance(channel_or_stream, Stream): |
| 75 | stream = channel_or_stream |
| 76 | logger.info(f"Previewing stream directly: {stream.id} ({stream.name})") |
| 77 | |
| 78 | if not stream.m3u_account: |
| 79 | logger.error(f"Stream {stream.id} has no M3U account") |
| 80 | return None, None, False, None, False, "Stream has no M3U account" |
| 81 | |
| 82 | stream_id, profile_id, error_reason, slot_reserved = stream.get_stream() |
| 83 | if not stream_id or not profile_id: |
| 84 | logger.error(f"No profile available for stream {stream.id}: {error_reason}") |
| 85 | return None, None, False, None, False, error_reason |
| 86 | |
| 87 | try: |
| 88 | profile = M3UAccountProfile.objects.get(id=profile_id) |
| 89 | m3u_account = stream.m3u_account |
| 90 | |
| 91 | stream_user_agent = m3u_account.get_user_agent().user_agent |
| 92 | if stream_user_agent is None: |
| 93 | stream_user_agent = UserAgent.objects.get(id=CoreSettings.get_default_user_agent_id()) |
| 94 | logger.debug(f"No user agent found for account, using default: {stream_user_agent}") |
| 95 | |
| 96 | stream_url = _resolve_live_stream_url(stream, m3u_account, profile) |
| 97 | |
| 98 | stream_profile = stream.get_stream_profile() |
| 99 | logger.debug(f"Using stream profile: {stream_profile.name}") |
| 100 | |
| 101 | transcode = not stream_profile.is_proxy() |
| 102 | stream_profile_id = stream_profile.id |
| 103 | |
| 104 | return stream_url, stream_user_agent, transcode, stream_profile_id, slot_reserved, None |
| 105 | except Exception as e: |
| 106 | logger.error(f"Error generating stream URL for stream {stream.id}: {e}") |
| 107 | if slot_reserved: |
| 108 | stream.release_stream() |
| 109 | return None, None, False, None, False, str(e) |
| 110 | |
| 111 | |
| 112 | # Handle channel preview (existing logic) |
| 113 | channel = channel_or_stream |
| 114 | |
| 115 | # Get stream and profile for this channel |
| 116 | stream_id, profile_id, error_reason, slot_reserved = channel.get_stream() |
| 117 | |
| 118 | if not stream_id or not profile_id: |