diff --git a/CHANGELOG.md b/CHANGELOG.md index cb61bbf4..2946d261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Stats page enhancements: Added "Now Playing" program information for active streams with smart polling that only fetches EPG data when programs are about to change (not on every stats refresh). Features include: - Currently playing program title displayed with live broadcast indicator (green Radio icon) - Expandable program descriptions via chevron button + - Progress bar showing elapsed and remaining time for currently playing programs - Efficient POST-based API endpoint (`/api/epg/current-programs/`) supporting batch channel queries or fetching all channels - Smart scheduling that fetches new program data 5 seconds after current program ends - Only polls when active channel list changes, not on stats refresh diff --git a/frontend/src/components/cards/StreamConnectionCard.jsx b/frontend/src/components/cards/StreamConnectionCard.jsx index 5488aef5..e8b8a33b 100644 --- a/frontend/src/components/cards/StreamConnectionCard.jsx +++ b/frontend/src/components/cards/StreamConnectionCard.jsx @@ -11,6 +11,7 @@ import { Center, Flex, Group, + Progress, Select, Stack, Text, @@ -549,6 +550,56 @@ const StreamConnectionCard = ({ )} + {/* Program progress bar */} + {currentProgram && + isProgramDescExpanded && + currentProgram.start_time && + currentProgram.end_time && + (() => { + const now = new Date(); + const startTime = new Date(currentProgram.start_time); + const endTime = new Date(currentProgram.end_time); + const totalDuration = (endTime - startTime) / 1000; // in seconds + const elapsed = (now - startTime) / 1000; // in seconds + const remaining = (endTime - now) / 1000; // in seconds + const percentage = Math.min( + 100, + Math.max(0, (elapsed / totalDuration) * 100) + ); + + const formatProgramTime = (seconds) => { + const absSeconds = Math.abs(seconds); + const hours = Math.floor(absSeconds / 3600); + const minutes = Math.floor((absSeconds % 3600) / 60); + const secs = Math.floor(absSeconds % 60); + if (hours > 0) { + return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; + } + return `${minutes}:${secs.toString().padStart(2, '0')}`; + }; + + return ( + + + + {formatProgramTime(elapsed)} elapsed + + + {formatProgramTime(remaining)} remaining + + + + + ); + })()} + {/* Add stream selection dropdown and preview button */} {availableStreams.length > 0 && (