add support for youtube-dl channels

This commit is contained in:
Joseph
2024-02-24 00:29:36 +00:00
parent 0d8b592770
commit bab64bab72
2 changed files with 73 additions and 6 deletions

View File

@ -205,12 +205,15 @@ const (
TypeSingle TypeSingle
// TypePlaylist playlist with multiple tracks, files etc // TypePlaylist playlist with multiple tracks, files etc
TypePlaylist TypePlaylist
// TypeChannel channel containing one or more playlists, which will be flattened
TypeChannel
) )
var TypeFromString = map[string]Type{ var TypeFromString = map[string]Type{
"any": TypeAny, "any": TypeAny,
"single": TypeSingle, "single": TypeSingle,
"playlist": TypePlaylist, "playlist": TypePlaylist,
"channel": TypeChannel,
} }
// Options for New() // Options for New()
@ -248,7 +251,12 @@ func Version(ctx context.Context) (string, error) {
// Downloads given URL using the given options and filter (usually a format id or quality designator). // Downloads given URL using the given options and filter (usually a format id or quality designator).
// If filter is empty, then youtube-dl will use its default format selector. // If filter is empty, then youtube-dl will use its default format selector.
func Download(ctx context.Context, rawURL string, options Options, filter string) (*DownloadResult, error) { func Download(
ctx context.Context,
rawURL string,
options Options,
filter string,
) (*DownloadResult, error) {
options.noInfoDownload = true options.noInfoDownload = true
d, err := New(ctx, rawURL, options) d, err := New(ctx, rawURL, options)
if err != nil { if err != nil {
@ -286,7 +294,11 @@ func New(ctx context.Context, rawURL string, options Options) (result Result, er
}, nil }, nil
} }
func infoFromURL(ctx context.Context, rawURL string, options Options) (info Info, rawJSON []byte, err error) { func infoFromURL(
ctx context.Context,
rawURL string,
options Options,
) (info Info, rawJSON []byte, err error) {
cmd := exec.CommandContext( cmd := exec.CommandContext(
ctx, ctx,
ProbePath(), ProbePath(),
@ -309,7 +321,7 @@ func infoFromURL(ctx context.Context, rawURL string, options Options) (info Info
cmd.Args = append(cmd.Args, "--downloader", options.Downloader) cmd.Args = append(cmd.Args, "--downloader", options.Downloader)
} }
switch options.Type { switch options.Type {
case TypePlaylist: case TypePlaylist, TypeChannel:
cmd.Args = append(cmd.Args, "--yes-playlist") cmd.Args = append(cmd.Args, "--yes-playlist")
if options.PlaylistStart > 0 { if options.PlaylistStart > 0 {
@ -453,6 +465,23 @@ func infoFromURL(ctx context.Context, rawURL string, options Options) (info Info
info.Entries = filteredEntrise info.Entries = filteredEntrise
} }
// channels contain playlists, so recurse into them
if options.Type == TypeChannel {
var filteredEntrise []Info
for _, p := range info.Entries {
if p.Type != "playlist" {
continue
}
for _, e := range p.Entries {
if e.ID == "" {
continue
}
filteredEntrise = append(filteredEntrise, e)
}
}
info.Entries = filteredEntrise
}
return info, stdoutBuf.Bytes(), nil return info, stdoutBuf.Bytes(), nil
} }
@ -488,12 +517,18 @@ type DownloadOptions struct {
PlaylistIndex int PlaylistIndex int
} }
func (result Result) DownloadWithOptions(ctx context.Context, options DownloadOptions) (*DownloadResult, error) { func (result Result) DownloadWithOptions(
ctx context.Context,
options DownloadOptions,
) (*DownloadResult, error) {
debugLog := result.Options.DebugLog debugLog := result.Options.DebugLog
if !result.Options.noInfoDownload { if !result.Options.noInfoDownload {
if (result.Info.Type == "playlist" || result.Info.Type == "multi_video") && options.PlaylistIndex == 0 { if (result.Info.Type == "playlist" || result.Info.Type == "multi_video") &&
return nil, fmt.Errorf("can't download a playlist when the playlist index options is not set") options.PlaylistIndex == 0 {
return nil, fmt.Errorf(
"can't download a playlist when the playlist index options is not set",
)
} }
} }

View File

@ -217,6 +217,38 @@ func TestPlaylist(t *testing.T) {
} }
} }
func TestChannel(t *testing.T) {
defer leakChecks(t)()
ydlResult, ydlResultErr := goutubedl.New(
context.Background(),
channelRawURL,
goutubedl.Options{
Type: goutubedl.TypeChannel,
DownloadThumbnail: false,
},
)
if ydlResultErr != nil {
t.Errorf("failed to download: %s", ydlResultErr)
}
expectedTitle := "Simon Yapp"
if ydlResult.Info.Title != expectedTitle {
t.Errorf("expected title %q got %q", expectedTitle, ydlResult.Info.Title)
}
expectedEntries := 5
if len(ydlResult.Info.Entries) != expectedEntries {
t.Errorf("expected %d entries got %d", expectedEntries, len(ydlResult.Info.Entries))
}
expectedTitleOne := "#RNLI Shoreham #LifeBoat demo of launch."
if ydlResult.Info.Entries[0].Title != expectedTitleOne {
t.Errorf("expected title %q got %q", expectedTitleOne, ydlResult.Info.Entries[0].Title)
}
}
func TestUnsupportedURL(t *testing.T) { func TestUnsupportedURL(t *testing.T) {
defer leaktest.Check(t)() defer leaktest.Check(t)()