Improve initial playlist data
This commit is contained in:
85
handlers.go
85
handlers.go
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -181,24 +180,30 @@ func getYtdlpTitle(url string, args []string) (string, error) {
|
|||||||
return strings.TrimSpace(string(stdout)), nil
|
return strings.TrimSpace(string(stdout)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getYtdlpPlaylistTitle(url string) (string, error) {
|
type PlaylistEntry struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlaylistData struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Entries []PlaylistEntry `json:"entries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getYtdlpPlaylist(url string) (PlaylistData, error) {
|
||||||
|
var data PlaylistData
|
||||||
stdout, _, err := runYtdlp("--flat-playlist", "--dump-single-json", url)
|
stdout, _, err := runYtdlp("--flat-playlist", "--dump-single-json", url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
return "", err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var data map[string]interface{}
|
|
||||||
err = json.Unmarshal(stdout, &data)
|
err = json.Unmarshal(stdout, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return data, err
|
||||||
}
|
|
||||||
title, ok := data["title"].(string)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("title field not found or not a string")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return title, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getYtdlpArtist(url string, args []string) (string, error) {
|
func getYtdlpArtist(url string, args []string) (string, error) {
|
||||||
@@ -684,41 +689,33 @@ func startDownload(originalID uint, videoURL string, audioOnly bool) {
|
|||||||
|
|
||||||
func startPlaylist(id uint, url string, audioOnly bool) {
|
func startPlaylist(id uint, url string, audioOnly bool) {
|
||||||
// retrieve playlist metadata
|
// retrieve playlist metadata
|
||||||
title, err := getYtdlpPlaylistTitle(url)
|
pl, err := getYtdlpPlaylist(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SetPlaylistStatus(id, Failed)
|
SetPlaylistStatus(id, Failed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = db.Model(&Playlist{}).Where("id = ?", id).Updates(map[string]interface{}{
|
err = db.Model(&Playlist{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"title": title,
|
"title": pl.Title,
|
||||||
}).Error
|
}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SetPlaylistStatus(id, Failed)
|
SetPlaylistStatus(id, Failed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate playlist entries
|
for _, entry := range pl.Entries {
|
||||||
stdout, _, err := runYtdlp("--get-id", "--flat-playlist", url)
|
original := Original{
|
||||||
if err != nil {
|
Title: entry.Title,
|
||||||
SetPlaylistStatus(id, Failed)
|
URL: entry.URL,
|
||||||
return
|
Status: Pending,
|
||||||
}
|
Video: !audioOnly,
|
||||||
for _, line := range strings.Split(string(stdout), "\n") {
|
Audio: audioOnly,
|
||||||
line = strings.TrimSpace(line)
|
Playlist: true,
|
||||||
if line != "" {
|
PlaylistID: id,
|
||||||
original := Original{
|
}
|
||||||
URL: fmt.Sprintf("https://www.youtube.com/watch?v=%s", line),
|
err = db.Create(&original).Error
|
||||||
Status: Pending,
|
if err != nil {
|
||||||
Video: !audioOnly,
|
SetPlaylistStatus(id, Failed)
|
||||||
Audio: audioOnly,
|
return
|
||||||
Playlist: true,
|
|
||||||
PlaylistID: id,
|
|
||||||
}
|
|
||||||
err = db.Create(&original).Error
|
|
||||||
if err != nil {
|
|
||||||
SetPlaylistStatus(id, Failed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetPlaylistStatus(id, Completed)
|
SetPlaylistStatus(id, Completed)
|
||||||
@@ -1088,11 +1085,23 @@ func processHandler(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func playlistHandler(c echo.Context) error {
|
func playlistHandler(c echo.Context) error {
|
||||||
referrer := c.Request().Referer()
|
|
||||||
if referrer == "" {
|
id := c.Param("id")
|
||||||
referrer = "/videos"
|
|
||||||
|
var originals []Original
|
||||||
|
|
||||||
|
err := db.Where("playlist = ?", true).
|
||||||
|
Where("playlist_id = ?", id).
|
||||||
|
Find(&originals).Error
|
||||||
|
if err != nil {
|
||||||
|
return c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err))
|
||||||
}
|
}
|
||||||
return c.Redirect(http.StatusSeeOther, referrer)
|
|
||||||
|
return c.Render(http.StatusOK, "playlist.html",
|
||||||
|
map[string]interface{}{
|
||||||
|
"originals": originals,
|
||||||
|
"Footer": makeFooter(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deletePlaylistHandler(c echo.Context) error {
|
func deletePlaylistHandler(c echo.Context) error {
|
||||||
|
62
templates/playlist.html
Normal file
62
templates/playlist.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="refresh" content="10">
|
||||||
|
<title>Playlist</title>
|
||||||
|
<link rel="stylesheet" href="/static/style/common.css">
|
||||||
|
<link rel="stylesheet" href="/static/style/videos.css">
|
||||||
|
{{template "footer-css" .}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Playlist</h1>
|
||||||
|
|
||||||
|
<div class="video-list">
|
||||||
|
{{range .originals}}
|
||||||
|
<div class="video-card">
|
||||||
|
<div class="video-title">
|
||||||
|
{{if or (eq .Status "download completed") (eq .Status "transcoding") (eq .Status "completed")}}
|
||||||
|
<a href="/video/{{.ID}}">{{.Title}}</a>
|
||||||
|
{{else}}
|
||||||
|
{{.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">
|
||||||
|
{{if .Audio}}
|
||||||
|
Audio
|
||||||
|
{{end}}
|
||||||
|
{{if .Video}}
|
||||||
|
Video
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="video-options">
|
||||||
|
{{if eq .Status "completed"}}
|
||||||
|
<form action="/video/{{.ID}}/process" method="post" style="display:inline;">
|
||||||
|
<button type="submit">Reprocess</button>
|
||||||
|
</form>
|
||||||
|
{{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"}}
|
||||||
|
{{end}}
|
||||||
|
<form action="/video/{{.ID}}/delete" method="post" style="display:inline;">
|
||||||
|
<button type="submit">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><a href="/logout">Logout</a></p>
|
||||||
|
|
||||||
|
{{template "footer" .}}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Reference in New Issue
Block a user