refactoring-1
introduced pipelines and abstracted download process.go in Downloader interface
This commit is contained in:
@@ -18,7 +18,7 @@ import (
|
||||
--max-downloads NUMBER | | stops after N completed downloads
|
||||
*/
|
||||
|
||||
func ApplyModifiers(entries *[]common.DownloadInfo, args []string) error {
|
||||
func ApplyModifiers(entries *[]common.DownloadMetadata, args []string) error {
|
||||
for i, modifier := range args {
|
||||
switch modifier {
|
||||
case "--playlist-start":
|
||||
@@ -38,7 +38,7 @@ func ApplyModifiers(entries *[]common.DownloadInfo, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func playlistStart(i int, modifier string, args []string, entries *[]common.DownloadInfo) error {
|
||||
func playlistStart(i int, modifier string, args []string, entries *[]common.DownloadMetadata) error {
|
||||
if !guard(i, len(modifier)) {
|
||||
return nil
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func playlistStart(i int, modifier string, args []string, entries *[]common.Down
|
||||
return nil
|
||||
}
|
||||
|
||||
func playlistEnd(i int, modifier string, args []string, entries *[]common.DownloadInfo) error {
|
||||
func playlistEnd(i int, modifier string, args []string, entries *[]common.DownloadMetadata) error {
|
||||
if !guard(i, len(modifier)) {
|
||||
return nil
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func playlistEnd(i int, modifier string, args []string, entries *[]common.Downlo
|
||||
return nil
|
||||
}
|
||||
|
||||
func maxDownloads(i int, modifier string, args []string, entries *[]common.DownloadInfo) error {
|
||||
func maxDownloads(i int, modifier string, args []string, entries *[]common.DownloadMetadata) error {
|
||||
if !guard(i, len(modifier)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
102
server/playlist/playlist.go
Normal file
102
server/playlist/playlist.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package playlist
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/common"
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/config"
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal"
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/downloaders"
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/kv"
|
||||
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/queue"
|
||||
)
|
||||
|
||||
func PlaylistDetect(req internal.DownloadRequest, mq *queue.MessageQueue, db *kv.Store) error {
|
||||
params := append(req.Params, "--flat-playlist", "-J")
|
||||
urlWithParams := append([]string{req.URL}, params...)
|
||||
|
||||
var (
|
||||
downloader = config.Instance().DownloaderPath
|
||||
cmd = exec.Command(downloader, urlWithParams...)
|
||||
)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var m Metadata
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("decoding playlist metadata", slog.String("url", req.URL))
|
||||
|
||||
if err := json.NewDecoder(stdout).Decode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("decoded playlist metadata", slog.String("url", req.URL))
|
||||
|
||||
if m.Type == "" {
|
||||
return errors.New("probably not a valid URL")
|
||||
}
|
||||
|
||||
if m.IsPlaylist() {
|
||||
entries := slices.CompactFunc(slices.Compact(m.Entries), func(a common.DownloadMetadata, b common.DownloadMetadata) bool {
|
||||
return a.URL == b.URL
|
||||
})
|
||||
|
||||
entries = slices.DeleteFunc(entries, func(e common.DownloadMetadata) bool {
|
||||
return strings.Contains(e.URL, "list=")
|
||||
})
|
||||
|
||||
slog.Info("playlist detected", slog.String("url", req.URL), slog.Int("count", len(entries)))
|
||||
|
||||
if err := ApplyModifiers(&entries, req.Params); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, meta := range entries {
|
||||
// detect playlist title from metadata since each playlist entry will be
|
||||
// treated as an individual download
|
||||
req.Rename = strings.Replace(
|
||||
req.Rename,
|
||||
"%(playlist_title)s",
|
||||
m.PlaylistTitle,
|
||||
1,
|
||||
)
|
||||
|
||||
//XXX: it's idiotic but it works: virtually delay the creation time
|
||||
meta.CreatedAt = time.Now().Add(time.Millisecond * time.Duration(i*10))
|
||||
|
||||
downloader := downloaders.NewGenericDownload(meta.URL, req.Params)
|
||||
downloader.SetOutput(internal.DownloadOutput{Filename: req.Rename})
|
||||
// downloader.SetMetadata(meta)
|
||||
|
||||
db.Set(downloader)
|
||||
mq.Publish(downloader)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
d := downloaders.NewGenericDownload(req.URL, req.Params)
|
||||
|
||||
db.Set(d)
|
||||
mq.Publish(d)
|
||||
slog.Info("sending new process to message queue", slog.String("url", d.GetUrl()))
|
||||
|
||||
return cmd.Wait()
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package playlist
|
||||
import "github.com/marcopiovanello/yt-dlp-web-ui/v3/server/common"
|
||||
|
||||
type Metadata struct {
|
||||
Entries []common.DownloadInfo `json:"entries"`
|
||||
Count int `json:"playlist_count"`
|
||||
PlaylistTitle string `json:"title"`
|
||||
Type string `json:"_type"`
|
||||
Entries []common.DownloadMetadata `json:"entries"`
|
||||
Count int `json:"playlist_count"`
|
||||
PlaylistTitle string `json:"title"`
|
||||
Type string `json:"_type"`
|
||||
}
|
||||
|
||||
func (m *Metadata) IsPlaylist() bool { return m.Type == "playlist" }
|
||||
|
||||
Reference in New Issue
Block a user