Skip to content

Commit

Permalink
Show currently playing stream on dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
csfrancis committed Nov 18, 2024
1 parent 5f71c2d commit bca689b
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 21 deletions.
4 changes: 4 additions & 0 deletions debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ import "github.com/gin-gonic/gin"
func SetGinMode() {
gin.SetMode(gin.DebugMode)
}

func IsDebugMode() bool {
return true
}
4 changes: 4 additions & 0 deletions release.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ import "github.com/gin-gonic/gin"
func SetGinMode() {
gin.SetMode(gin.ReleaseMode)
}

func IsDebugMode() bool {
return false
}
68 changes: 54 additions & 14 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,6 @@ func (s *Server) streamTracker(c *gin.Context) {
}
}

func (s *Server) getActiveStreamCount() int {
s.lock.Lock()
defer s.lock.Unlock()
return len(s.streams)
}

func (s *Server) getActiveStreams() []*streamInfo {
s.lock.Lock()
defer s.lock.Unlock()
Expand Down Expand Up @@ -368,22 +362,68 @@ func (s *Server) debug() gin.HandlerFunc {
}
}

func (s *Server) getStreamCountData() gin.H {
return gin.H{
"ActiveStreams": s.getActiveStreamCount(),
"TotalStreams": atomic.LoadInt64(&s.totalStreams),
func (s *Server) headContent() template.HTML {
if IsDebugMode() {
return template.HTML(`<script src="/static/js/htmx.min.js?v=debug"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
dark: {
bg: '#1a202c',
text: '#e2e8f0',
},
},
},
},
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.toggle-checkbox:checked {
@apply: right-0 border-green-400;
right: 0;
border-color: #68D391;
}
.toggle-checkbox:checked + .toggle-label {
@apply: bg-green-400;
background-color: #68D391;
}
}
</style>`)
} else {
return template.HTML(fmt.Sprintf(`<script src="/static/js/htmx.min.js?v=%[1]s"></script>
<link href="/static/css/output.css?v=%[1]s" rel="stylesheet">`, s.version))
}
}

func (s *Server) homePage() gin.HandlerFunc {
streamInfoData := s.getStreamInfoData()
streamInfoData["HeadContent"] = s.headContent()
if IsDebugMode() {
streamInfoData["Version"] = "debug"
} else {
streamInfoData["Version"] = s.version
}
return func(c *gin.Context) {
c.HTML(http.StatusOK, "base.html", s.getStreamCountData())
c.HTML(http.StatusOK, "base.html", streamInfoData)
}
}

func (s *Server) getStreamInfoData() gin.H {
return gin.H{
"ActiveStreams": s.getActiveStreams(),
"TotalStreams": atomic.LoadInt64(&s.totalStreams),
"Now": time.Now(),
}
}

func (s *Server) getStreamCounts() gin.HandlerFunc {
func (s *Server) getStreamInfo() gin.HandlerFunc {
return func(c *gin.Context) {
c.HTML(http.StatusOK, "stream_counts.html", s.getStreamCountData())
c.HTML(http.StatusOK, "stream_info.html", s.getStreamInfoData())
}
}

Expand All @@ -400,7 +440,7 @@ func (s *Server) Start(provider *Provider) chan error {
s.router.GET(fmt.Sprintf("%s:channelId", channelURIPrefix), s.streamChannel())
s.router.PUT("/refresh", s.refresh())
s.router.GET("/debug", s.debug())
s.router.GET("/stream-counts", s.getStreamCounts())
s.router.GET("/stream-info", s.getStreamInfo())
s.router.StaticFS("/static", static.AssetFile())

s.server = &http.Server{
Expand Down
25 changes: 25 additions & 0 deletions web/static/js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
function updateDurations() {
const entries = document.querySelectorAll('[data-start-time]');
const now = Math.floor(Date.now() / 1000);

entries.forEach(entry => {
const startTime = parseInt(entry.dataset.startTime);
const durationSeconds = now - startTime;

const hours = Math.floor(durationSeconds / 3600);
const minutes = Math.floor((durationSeconds % 3600) / 60);
const seconds = durationSeconds % 60;

let durationStr = '';
if (hours > 0) durationStr += `${hours}h `;
if (minutes > 0) durationStr += `${minutes}m `;
durationStr += `${seconds}s`;

const startTimeStr = new Date(startTime * 1000).toLocaleTimeString();
entry.title = `Started: ${startTimeStr} (Duration: ${durationStr})`;
});
}

// Update durations immediately and every second
updateDurations();
setInterval(updateDurations, 1000);
4 changes: 2 additions & 2 deletions web/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ProxyTV</title>
<script src="/static/js/htmx.min.js"></script>
<link href="/static/css/output.css" rel="stylesheet">
{{ .HeadContent }}
</head>
<body class="bg-gray-100 dark:bg-dark-bg text-gray-900 dark:text-dark-text">
<div class="container mx-auto p-4">
Expand Down Expand Up @@ -40,5 +39,6 @@
}
});
</script>
<script src="/static/js/script.js?v={{ .Version }}"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions web/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<h1 class="text-3xl font-bold mb-4 dark:text-dark-text">ProxyTV Dashboard</h1>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-white dark:bg-gray-800 p-4 rounded shadow">
<h2 class="text-xl font-semibold mb-2 dark:text-dark-text">Server Status</h2>
<div hx-get="/stream-counts" hx-trigger="every 5s">
{{ template "stream_counts.html" . }}
<h2 class="text-xl font-semibold dark:text-dark-text">Server Status</h2>
<div hx-get="/stream-info" hx-trigger="every 5s">
{{ template "stream_info.html" . }}
</div>
</div>
<div class="bg-white dark:bg-gray-800 p-4 rounded shadow">
Expand Down
2 changes: 0 additions & 2 deletions web/templates/stream_counts.html

This file was deleted.

19 changes: 19 additions & 0 deletions web/templates/stream_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="p-4">
<h3 class="text-lg font-semibold mb-5">Active Streams: {{len .ActiveStreams}} / Total Streams: {{.TotalStreams}}</h3>

<div class="flex flex-col gap-3 mt-5">
{{range .ActiveStreams}}
<div class="flex items-center p-3 bg-gray-50 dark:bg-dark-bg rounded-lg transition-colors hover:bg-gray-100" data-start-time="{{.StartTime.Unix}}" title="Started: {{.StartTime.Format "15:04:05"}}">
{{if .LogoURL}}
<img src="{{.LogoURL}}" alt="{{.Name}}" class="w-10 h-10 object-contain mr-4">
{{end}}
<div class="flex gap-x-6">
<div class="font-bold">{{.Name}}</div>
<div class="text-sm text-gray-500 content-center">{{.ClientIP}}</div>
</div>
</div>
{{else}}
<div class="text-center font-bold text-gray-500 py-5">No active streams</div>
{{end}}
</div>
</div>

0 comments on commit bca689b

Please sign in to comment.