more sse, disable sse, disable auto-refresh if compelted
This commit is contained in:
@@ -716,11 +716,20 @@ func videosHandler(c echo.Context) error {
|
||||
var origs []originals.Original
|
||||
db.Where("user_id = ?", userID).Order("id DESC").Find(&origs)
|
||||
|
||||
refresh := false
|
||||
for _, orig := range origs {
|
||||
if orig.Status != "completed" {
|
||||
refresh = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var playlists []playlists.Playlist
|
||||
db.Where("user_id = ?", userID).Order("id DESC").Find(&playlists)
|
||||
|
||||
return c.Render(http.StatusOK, "videos.html",
|
||||
map[string]interface{}{
|
||||
"refresh": refresh,
|
||||
"videos": origs,
|
||||
"playlists": playlists,
|
||||
"Footer": handlers.MakeFooter(),
|
||||
|
1
main.go
1
main.go
@@ -148,6 +148,7 @@ func main() {
|
||||
e.POST("/transcode_to_video/:id", transcodeToVideoHandler, handlers.AuthMiddleware)
|
||||
e.POST("/transcode_to_audio/:id", transcodeToAudioHandler, handlers.AuthMiddleware)
|
||||
e.GET("/status", handlers.StatusGet, handlers.AuthMiddleware)
|
||||
e.GET("/videos/events", handlers.VideosEvents, handlers.AuthMiddleware)
|
||||
|
||||
e.GET("/p/:id", playlistHandler, handlers.AuthMiddleware)
|
||||
e.POST("/p/:id/delete", deletePlaylistHandler, handlers.AuthMiddleware)
|
||||
|
@@ -8,6 +8,9 @@ func Init(logger *logrus.Logger) error {
|
||||
log = logger.WithFields(logrus.Fields{
|
||||
"component": "originals",
|
||||
}).Logger
|
||||
|
||||
listeners = make(map[uint][]*Queue)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -39,14 +39,14 @@ type Original struct {
|
||||
var listeners map[uint][]*Queue // map of userId to queues
|
||||
var lMu sync.Mutex
|
||||
|
||||
func bcast(userId, origId uint, status Status) {
|
||||
func bcast(userId, origId uint, pl VideoEventPayload) {
|
||||
lMu.Lock()
|
||||
defer lMu.Unlock()
|
||||
|
||||
qs, ok := listeners[userId]
|
||||
if ok {
|
||||
for _, q := range qs {
|
||||
q.Ch <- Event{origId, status}
|
||||
q.Ch <- Event{origId, pl}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func SetStatus(id uint, status Status) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bcast(orig.UserID, id, status)
|
||||
bcast(orig.UserID, id, makeVideosPayload(status, orig.Title))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -87,9 +87,18 @@ func SetStatusTranscodingOrCompleted(id uint) error {
|
||||
}
|
||||
}
|
||||
|
||||
type VideoEventPayload struct {
|
||||
Status Status
|
||||
Title string
|
||||
}
|
||||
|
||||
func makeVideosPayload(status Status, title string) VideoEventPayload {
|
||||
return VideoEventPayload{status, title}
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
VideoId uint
|
||||
Status Status
|
||||
VideoEventPayload
|
||||
}
|
||||
|
||||
type Queue struct {
|
||||
|
101
static/script/videos-events.js
Normal file
101
static/script/videos-events.js
Normal file
@@ -0,0 +1,101 @@
|
||||
// Function to disable the auto-refresh
|
||||
function disableAutoRefresh() {
|
||||
// Find the meta tag that controls the refresh
|
||||
var metaRefresh = document.querySelector('meta[http-equiv="refresh"]');
|
||||
|
||||
// If the meta tag exists, remove it
|
||||
if (metaRefresh) {
|
||||
metaRefresh.remove();
|
||||
console.log("Auto-refresh disabled");
|
||||
} else {
|
||||
console.log("No auto-refresh meta tag found");
|
||||
}
|
||||
}
|
||||
|
||||
const eventSource = new EventSource('/videos/events');
|
||||
|
||||
function closeEventSource() {
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
}
|
||||
}
|
||||
|
||||
function hideDivs(parent, hide, classes) {
|
||||
classes.forEach(cls => {
|
||||
divs = parent.querySelectorAll('div' + cls)
|
||||
console.log(divs)
|
||||
if (hide) {
|
||||
divs.forEach(div => div.classList.add("hidden"))
|
||||
} else {
|
||||
divs.forEach(div => div.classList.remove("hidden"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showDivs(parent, show, classes) {
|
||||
classes.forEach(cls => {
|
||||
divs = parent.querySelectorAll(cls)
|
||||
console.log(divs)
|
||||
if (show) {
|
||||
divs.forEach(div => div.classList.remove("hidden"))
|
||||
} else {
|
||||
divs.forEach(div => div.classList.add("hidden"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateCardsStyling(card) {
|
||||
console.log(`updateCardsStyling: card:`, card);
|
||||
|
||||
const statusDiv = card.querySelector('.video-status');
|
||||
if (statusDiv) {
|
||||
const statusText = statusDiv.textContent.trim().toLowerCase();
|
||||
|
||||
if (["completed", "download completed", "transcoding"].includes(statusText)) {
|
||||
hideDivs(card, false, [".video-title-link"])
|
||||
hideDivs(card, true, [".video-title-bare"])
|
||||
} else { // failed
|
||||
hideDivs(card, true, [".video-title-link"])
|
||||
hideDivs(card, false, [".video-title-bare"])
|
||||
}
|
||||
|
||||
showDivs(card, (statusText == "completed"), [".reprocess-btn", ".delete-btn"])
|
||||
showDivs(card, (statusText == "failed"), [".restart-btn"])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
eventSource.onmessage = function (event) {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log(data)
|
||||
|
||||
const videoCard = document.getElementById(`video-card-${data.VideoId}`);
|
||||
if (videoCard) {
|
||||
const statusDiv = videoCard.querySelector('.video-info.video-status');
|
||||
if (statusDiv) {
|
||||
statusDiv.textContent = data.Status;
|
||||
} else {
|
||||
console.error(`Status div not found for video ID ${data.VideoId}`);
|
||||
}
|
||||
} else {
|
||||
console.error(`Video card not found for ID ${data.VideoId}`);
|
||||
}
|
||||
|
||||
updateCardsStyling(videoCard)
|
||||
};
|
||||
|
||||
eventSource.onopen = function (event) {
|
||||
console.log("Connection to server opened.");
|
||||
disableAutoRefresh();
|
||||
};
|
||||
|
||||
eventSource.onerror = function (error) {
|
||||
console.error('EventSource failed:', error);
|
||||
eventSource.close();
|
||||
};
|
||||
|
||||
// Add event listener for when the page is about to unload
|
||||
window.addEventListener('beforeunload', closeEventSource);
|
||||
|
||||
// Call the function when the page loads
|
||||
// window.onload = disableAutoRefresh;
|
@@ -37,4 +37,9 @@
|
||||
.video-options .delete-btn {
|
||||
background-color: rgb(255, 70, 70);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.video-card .hidden {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
@@ -4,7 +4,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="refresh" content="10">
|
||||
{{if .refresh}}
|
||||
<meta http-equiv="refresh" content="15">
|
||||
{{end}}
|
||||
<title>Downloaded Videos</title>
|
||||
<link rel="stylesheet" href="/static/style/common.css">
|
||||
<link rel="stylesheet" href="/static/style/videos.css">
|
||||
@@ -19,38 +21,49 @@
|
||||
|
||||
<div class="video-list">
|
||||
{{range .videos}}
|
||||
<div class="video-card">
|
||||
<div class="video-title">
|
||||
{{if or (eq .Status "download completed") (eq .Status "transcoding") (eq .Status "completed")}}
|
||||
<div class="video-card" id="video-card-{{.ID}}">
|
||||
{{$bareHidden := ""}}
|
||||
{{$linkHidden := ""}}
|
||||
{{if or (eq .Status "completed") (eq .Status "transcoding") (eq .Status "download completed")}}
|
||||
{{$bareHidden = "hidden"}}
|
||||
{{else}}
|
||||
{{$linkHidden = "hidden"}}
|
||||
{{end}}
|
||||
<div class="video-title video-title-link {{$linkHidden}}">
|
||||
<a href="/video/{{.ID}}">{{.Title}}</a>
|
||||
{{else}}
|
||||
</div>
|
||||
<div class="video-title video-title-bare {{$bareHidden}}">
|
||||
{{.Title}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="video-info">{{.Artist}}</div>
|
||||
<div class="video-info"><a href="{{.URL}}">{{.URL}}</a></div>
|
||||
<div class="video-info">{{.Status}}</div>
|
||||
<div class="video-info video-status">{{.Status}}</div>
|
||||
<div class="video-info">
|
||||
{{if .Audio}}
|
||||
Audio
|
||||
{{end}}
|
||||
{{if .Video}}
|
||||
Video
|
||||
{{end}}
|
||||
{{if .Audio}} Audio {{end}}
|
||||
{{if .Video}} Video {{end}}
|
||||
</div>
|
||||
<div class="video-options">
|
||||
{{$processHidden := ""}}
|
||||
{{$deleteHidden := ""}}
|
||||
{{$restartHidden := ""}}
|
||||
{{if eq .Status "completed"}}
|
||||
<form action="/video/{{.ID}}/process" method="post" style="display:inline;">
|
||||
<button type="submit">Reprocess</button>
|
||||
</form>
|
||||
{{$restartHidden = "hidden"}}
|
||||
{{else if eq .Status "failed"}}
|
||||
<form action="/video/{{.ID}}/restart" method="post" style="display:inline;">
|
||||
<button type="submit">Restart</button>
|
||||
</form>
|
||||
{{else if eq .Status "downloading"}}
|
||||
{{$processHidden = "hidden"}}
|
||||
{{$deleteHidden = "hidden"}}
|
||||
{{else}}
|
||||
{{$processHidden = "hidden"}}
|
||||
{{$deleteHidden = "hidden"}}
|
||||
{{$restartHidden = "hidden"}}
|
||||
{{end}}
|
||||
<form action="/video/{{.ID}}/process" method="post" style="display:inline;">
|
||||
<button type="submit" class="reprocess-btn {{$processHidden}}">Reprocess</button>
|
||||
</form>
|
||||
<form action="/video/{{.ID}}/delete" method="post" style="display:inline;">
|
||||
<button type="submit" class="delete-btn">Delete</button>
|
||||
<button type="submit" class="delete-btn {{$deleteHidden}}">Delete</button>
|
||||
</form>
|
||||
<form action="/video/{{.ID}}/restart" method="post" style="display:inline;">
|
||||
<button type="submit" class="restart-btn {{$restartHidden}}">Restart</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,7 +90,10 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
|
||||
{{template "footer" .}}
|
||||
<!-- <script src="/static/script/videos-events.js" defer></script> -->
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user