From b222dbe5a32eb33ee557a8452b0e8feaf1b6456f Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Tue, 29 Jul 2025 11:21:44 -0500 Subject: [PATCH] Display stream qualites in channel table. --- .../components/tables/ChannelTableStreams.jsx | 134 ++++++++++++++++-- .../src/components/tables/StreamsTable.jsx | 8 +- 2 files changed, 132 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/tables/ChannelTableStreams.jsx b/frontend/src/components/tables/ChannelTableStreams.jsx index 097a2ba8..3e034fb3 100644 --- a/frontend/src/components/tables/ChannelTableStreams.jsx +++ b/frontend/src/components/tables/ChannelTableStreams.jsx @@ -8,7 +8,11 @@ import { Text, useMantineTheme, Center, + Badge, + Group, + Tooltip, } from '@mantine/core'; +import { notifications } from '@mantine/notifications'; import { useReactTable, getCoreRowModel, @@ -141,6 +145,19 @@ const ChannelStreams = ({ channel, isExpanded }) => { await API.requeryChannels(); }; + // Create M3U account map for quick lookup + const m3uAccountsMap = useMemo(() => { + const map = {}; + if (playlists && Array.isArray(playlists)) { + playlists.forEach((account) => { + if (account.id) { + map[account.id] = account.name; + } + }); + } + return map; + }, [playlists]); + const table = useReactTable({ columns: useMemo( () => [ @@ -152,14 +169,114 @@ const ChannelStreams = ({ channel, isExpanded }) => { }, { id: 'name', - header: 'Name', + header: 'Stream Info', accessorKey: 'name', - }, - { - id: 'm3u', - header: 'M3U', - accessorFn: (row) => - playlists.find((playlist) => playlist.id === row.m3u_account)?.name, + cell: ({ row }) => { + const stream = row.original; + const playlistName = playlists[stream.m3u_account]?.name || 'Unknown'; + const accountName = m3uAccountsMap[stream.m3u_account] || playlistName; + + return ( + + {stream.name} + + + {accountName} + + {stream.quality && ( + + {stream.quality} + + )} + {stream.url && ( + + { + e.stopPropagation(); + navigator.clipboard.writeText(stream.url); + notifications.show({ + title: 'URL Copied', + message: 'Stream URL copied to clipboard', + color: 'green', + }); + }} + > + URL + + + )} + + {stream.stream_stats && ( + + {/* Video Information */} + {(stream.stream_stats.video_codec || stream.stream_stats.resolution || stream.stream_stats.video_bitrate || stream.stream_stats.source_fps) && ( + <> + Video: + {stream.stream_stats.resolution && ( + + {stream.stream_stats.resolution} + + )} + {stream.stream_stats.video_bitrate && ( + + {stream.stream_stats.video_bitrate} KbPS + + )} + {stream.stream_stats.source_fps && ( + + {stream.stream_stats.source_fps} FPS + + )} + {stream.stream_stats.video_codec && ( + + {stream.stream_stats.video_codec.toUpperCase()} + + )} + + )} + + {/* Audio Information */} + {(stream.stream_stats.audio_codec || stream.stream_stats.audio_channels || stream.stream_stats.audio_bitrate) && ( + <> + Audio: + {stream.stream_stats.audio_channels && ( + + {stream.stream_stats.audio_channels} + + )} + {stream.stream_stats.audio_codec && ( + + {stream.stream_stats.audio_codec.toUpperCase()} + + )} + {stream.stream_stats.audio_bitrate && ( + + {stream.stream_stats.audio_bitrate} KbPS + + )} + + )} + + {/* Output Bitrate */} + {(stream.stream_stats.ffmpeg_output_bitrate) && ( + <> + Output Bitrate: + {stream.stream_stats.ffmpeg_output_bitrate && ( + + {stream.stream_stats.ffmpeg_output_bitrate} KbPS + + )} + + )} + + )} + + ); + }, }, { id: 'actions', @@ -178,7 +295,7 @@ const ChannelStreams = ({ channel, isExpanded }) => { ), }, ], - [data, playlists] + [data, playlists, m3uAccountsMap] ), data, state: { @@ -292,4 +409,5 @@ const ChannelStreams = ({ channel, isExpanded }) => { ); }; + export default ChannelStreams; diff --git a/frontend/src/components/tables/StreamsTable.jsx b/frontend/src/components/tables/StreamsTable.jsx index c149e2a7..616a52a3 100644 --- a/frontend/src/components/tables/StreamsTable.jsx +++ b/frontend/src/components/tables/StreamsTable.jsx @@ -102,10 +102,14 @@ const StreamRowActions = ({ 'ID:', row.original.id, 'Hash:', - row.original.stream_hash + row.original.stream_hash, + 'Quality:', + row.original.quality, + 'Stats:', + row.original.stream_stats ); handleWatchStream(row.original.stream_hash); - }, [row.original.id]); // Add proper dependency to ensure correct stream + }, [row.original, handleWatchStream]); // Add proper dependencies to ensure correct stream const iconSize = tableSize == 'default' ? 'sm' : tableSize == 'compact' ? 'xs' : 'md';