fix: resolve download failures and duplicate messages, add fast playlist detection
All checks were successful
CI / build (push) Successful in 39s
All checks were successful
CI / build (push) Successful in 39s
- Remove --audio-multi-streams flag (not supported by Alpine yt-dlp 2026.03.17) - Reuse the fetching message as the format selection message to avoid duplicate text - Add DetectPlaylist method for fast flat playlist detection before expensive GetMediaInfo - This avoids stalls on YouTube Music radio URLs with large playlists
This commit is contained in:
@@ -194,6 +194,24 @@ func (c *Client) GetPlaylistInfo(url string) (*domain.MediaInfo, error) {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
isPlaylist, mi, err := c.DetectPlaylist(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isPlaylist {
|
||||
mi.IsPlaylist = false
|
||||
mi.PlaylistCount = 0
|
||||
mi.PlaylistEntries = nil
|
||||
}
|
||||
|
||||
c.setCache(url, mi)
|
||||
return mi, nil
|
||||
}
|
||||
|
||||
// DetectPlaylist runs a fast flat yt-dlp check to determine if the URL is a playlist.
|
||||
// It returns basic info without format details. For non-playlist URLs it returns false.
|
||||
// Does NOT cache the result so a subsequent GetMediaInfo call fetches full format info.
|
||||
func (c *Client) DetectPlaylist(url string) (bool, *domain.MediaInfo, error) {
|
||||
args := []string{
|
||||
"-J", "--flat-playlist", "--no-download",
|
||||
"--no-warnings",
|
||||
@@ -206,29 +224,29 @@ func (c *Client) GetPlaylistInfo(url string) (*domain.MediaInfo, error) {
|
||||
args = append(args, "--proxy", c.proxyURL)
|
||||
}
|
||||
|
||||
slog.Info("fetching playlist info", "url", url)
|
||||
slog.Info("detecting playlist", "url", url)
|
||||
out, err := c.run(args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("yt-dlp playlist info failed: %w", err)
|
||||
return false, nil, fmt.Errorf("yt-dlp playlist detection failed: %w", err)
|
||||
}
|
||||
|
||||
var info ytdlpInfo
|
||||
if err := json.Unmarshal(out, &info); err != nil {
|
||||
return nil, fmt.Errorf("parse yt-dlp playlist output: %w", err)
|
||||
var rawInfo ytdlpInfo
|
||||
if err := json.Unmarshal(out, &rawInfo); err != nil {
|
||||
return false, nil, fmt.Errorf("parse yt-dlp output: %w", err)
|
||||
}
|
||||
|
||||
mi := &domain.MediaInfo{
|
||||
URL: url,
|
||||
Title: info.Title,
|
||||
Uploader: info.Uploader,
|
||||
Thumbnail: info.Thumbnail,
|
||||
IsPlaylist: true,
|
||||
PlaylistCount: info.PlaylistCount,
|
||||
PlaylistEntries: c.parsePlaylistEntries(info.Entries),
|
||||
Title: rawInfo.Title,
|
||||
Uploader: rawInfo.Uploader,
|
||||
Thumbnail: rawInfo.Thumbnail,
|
||||
Duration: rawInfo.Duration,
|
||||
IsPlaylist: rawInfo.Playlist != "",
|
||||
PlaylistCount: rawInfo.PlaylistCount,
|
||||
PlaylistEntries: c.parsePlaylistEntries(rawInfo.Entries),
|
||||
}
|
||||
|
||||
c.setCache(url, mi)
|
||||
return mi, nil
|
||||
return mi.IsPlaylist, mi, nil
|
||||
}
|
||||
|
||||
func (c *Client) parsePlaylistEntries(entries []json.RawMessage) []domain.PlaylistEntry {
|
||||
@@ -319,7 +337,6 @@ func (c *Client) StartDownload(job *domain.DownloadJob, downloadDir string) (<-c
|
||||
// Language selection if specified
|
||||
if job.Language != "" {
|
||||
args = append(args, "--sub-langs", job.Language)
|
||||
args = append(args, "--audio-multi-streams")
|
||||
}
|
||||
|
||||
// Cookies
|
||||
|
||||
Reference in New Issue
Block a user