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
|
var origs []originals.Original
|
||||||
db.Where("user_id = ?", userID).Order("id DESC").Find(&origs)
|
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
|
var playlists []playlists.Playlist
|
||||||
db.Where("user_id = ?", userID).Order("id DESC").Find(&playlists)
|
db.Where("user_id = ?", userID).Order("id DESC").Find(&playlists)
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "videos.html",
|
return c.Render(http.StatusOK, "videos.html",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
"refresh": refresh,
|
||||||
"videos": origs,
|
"videos": origs,
|
||||||
"playlists": playlists,
|
"playlists": playlists,
|
||||||
"Footer": handlers.MakeFooter(),
|
"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_video/:id", transcodeToVideoHandler, handlers.AuthMiddleware)
|
||||||
e.POST("/transcode_to_audio/:id", transcodeToAudioHandler, handlers.AuthMiddleware)
|
e.POST("/transcode_to_audio/:id", transcodeToAudioHandler, handlers.AuthMiddleware)
|
||||||
e.GET("/status", handlers.StatusGet, 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.GET("/p/:id", playlistHandler, handlers.AuthMiddleware)
|
||||||
e.POST("/p/:id/delete", deletePlaylistHandler, 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{
|
log = logger.WithFields(logrus.Fields{
|
||||||
"component": "originals",
|
"component": "originals",
|
||||||
}).Logger
|
}).Logger
|
||||||
|
|
||||||
|
listeners = make(map[uint][]*Queue)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ type Original struct {
|
|||||||
var listeners map[uint][]*Queue // map of userId to queues
|
var listeners map[uint][]*Queue // map of userId to queues
|
||||||
var lMu sync.Mutex
|
var lMu sync.Mutex
|
||||||
|
|
||||||
func bcast(userId, origId uint, status Status) {
|
func bcast(userId, origId uint, pl VideoEventPayload) {
|
||||||
lMu.Lock()
|
lMu.Lock()
|
||||||
defer lMu.Unlock()
|
defer lMu.Unlock()
|
||||||
|
|
||||||
qs, ok := listeners[userId]
|
qs, ok := listeners[userId]
|
||||||
if ok {
|
if ok {
|
||||||
for _, q := range qs {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
bcast(orig.UserID, id, status)
|
bcast(orig.UserID, id, makeVideosPayload(status, orig.Title))
|
||||||
return nil
|
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 {
|
type Event struct {
|
||||||
VideoId uint
|
VideoId uint
|
||||||
Status Status
|
VideoEventPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
type Queue struct {
|
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 {
|
.video-options .delete-btn {
|
||||||
background-color: rgb(255, 70, 70);
|
background-color: rgb(255, 70, 70);
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-card .hidden {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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>
|
<title>Downloaded Videos</title>
|
||||||
<link rel="stylesheet" href="/static/style/common.css">
|
<link rel="stylesheet" href="/static/style/common.css">
|
||||||
<link rel="stylesheet" href="/static/style/videos.css">
|
<link rel="stylesheet" href="/static/style/videos.css">
|
||||||
@@ -19,38 +21,49 @@
|
|||||||
|
|
||||||
<div class="video-list">
|
<div class="video-list">
|
||||||
{{range .videos}}
|
{{range .videos}}
|
||||||
<div class="video-card">
|
<div class="video-card" id="video-card-{{.ID}}">
|
||||||
<div class="video-title">
|
{{$bareHidden := ""}}
|
||||||
{{if or (eq .Status "download completed") (eq .Status "transcoding") (eq .Status "completed")}}
|
{{$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>
|
<a href="/video/{{.ID}}">{{.Title}}</a>
|
||||||
{{else}}
|
</div>
|
||||||
|
<div class="video-title video-title-bare {{$bareHidden}}">
|
||||||
{{.Title}}
|
{{.Title}}
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="video-info">{{.Artist}}</div>
|
<div class="video-info">{{.Artist}}</div>
|
||||||
<div class="video-info"><a href="{{.URL}}">{{.URL}}</a></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">
|
<div class="video-info">
|
||||||
{{if .Audio}}
|
{{if .Audio}} Audio {{end}}
|
||||||
Audio
|
{{if .Video}} Video {{end}}
|
||||||
{{end}}
|
|
||||||
{{if .Video}}
|
|
||||||
Video
|
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="video-options">
|
<div class="video-options">
|
||||||
|
{{$processHidden := ""}}
|
||||||
|
{{$deleteHidden := ""}}
|
||||||
|
{{$restartHidden := ""}}
|
||||||
{{if eq .Status "completed"}}
|
{{if eq .Status "completed"}}
|
||||||
<form action="/video/{{.ID}}/process" method="post" style="display:inline;">
|
{{$restartHidden = "hidden"}}
|
||||||
<button type="submit">Reprocess</button>
|
|
||||||
</form>
|
|
||||||
{{else if eq .Status "failed"}}
|
{{else if eq .Status "failed"}}
|
||||||
<form action="/video/{{.ID}}/restart" method="post" style="display:inline;">
|
{{$processHidden = "hidden"}}
|
||||||
<button type="submit">Restart</button>
|
{{$deleteHidden = "hidden"}}
|
||||||
</form>
|
{{else}}
|
||||||
{{else if eq .Status "downloading"}}
|
{{$processHidden = "hidden"}}
|
||||||
|
{{$deleteHidden = "hidden"}}
|
||||||
|
{{$restartHidden = "hidden"}}
|
||||||
{{end}}
|
{{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;">
|
<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>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,7 +90,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{{template "footer" .}}
|
{{template "footer" .}}
|
||||||
|
<!-- <script src="/static/script/videos-events.js" defer></script> -->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user