diff --git a/config.toml.example b/config.toml.example index 094f744..9e3ac6e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -51,13 +51,17 @@ vimeo = [ # Multiple keys will be rotated. update_period = "12h" quality = "high" # or "low" - format = "video" # or "audio" + format = "video" # or: "audio", "custom" + # When format = "custom" + # YouTubeDL format parameter and result file extension + custom_format = { youtube_dl_format = "bestaudio[ext=m4a]", extension = "m4a" } + playlist_sort = "asc" # or "desc", which will fetch playlist items from the end # Optional maximal height of video, example: 720, 1080, 1440, 2160, ... max_height = 720 - # Optinally include this feed in OPML file (default value: false) + # Optionally include this feed in OPML file (default value: false) opml = true # Optional cron expression format for more precise update schedule. diff --git a/pkg/feed/config.go b/pkg/feed/config.go index 2a7a741..facfa6f 100644 --- a/pkg/feed/config.go +++ b/pkg/feed/config.go @@ -28,6 +28,8 @@ type Config struct { MaxHeight int `toml:"max_height"` // Format to use for this feed Format model.Format `toml:"format"` + // Custom format properties + CustomFormat CustomFormat `toml:"custom_format"` // Only download episodes that match this regexp (defaults to matching anything) Filters Filters `toml:"filters"` // Clean is a cleanup policy to use for this feed @@ -44,6 +46,11 @@ type Config struct { PlaylistSort model.Sorting `toml:"playlist_sort"` } +type CustomFormat struct { + YouTubeDLFormat string `toml:"youtube_dl_format"` + Extension string `toml:"extension"` +} + type Filters struct { Title string `toml:"title"` NotTitle string `toml:"not_title"` diff --git a/pkg/feed/xml.go b/pkg/feed/xml.go index c20cc92..42ff272 100644 --- a/pkg/feed/xml.go +++ b/pkg/feed/xml.go @@ -164,6 +164,8 @@ func EpisodeName(feedConfig *Config, episode *model.Episode) string { ext := "mp4" if feedConfig.Format == model.FormatAudio { ext = "mp3" + }else if feedConfig.Format == model.FormatCustom { + ext = feedConfig.CustomFormat.Extension } return fmt.Sprintf("%s.%s", episode.ID, ext) diff --git a/pkg/model/feed.go b/pkg/model/feed.go index 7c79e1b..fb6cc40 100644 --- a/pkg/model/feed.go +++ b/pkg/model/feed.go @@ -16,8 +16,9 @@ const ( type Format string const ( - FormatAudio = Format("audio") - FormatVideo = Format("video") + FormatAudio = Format("audio") + FormatVideo = Format("video") + FormatCustom = Format("custom") ) // Playlist sorting style diff --git a/pkg/ytdl/ytdl.go b/pkg/ytdl/ytdl.go index f035461..7dfc178 100644 --- a/pkg/ytdl/ytdl.go +++ b/pkg/ytdl/ytdl.go @@ -197,7 +197,10 @@ func (dl *YoutubeDl) Download(ctx context.Context, feedConfig *feed.Config, epis ext := "mp4" if feedConfig.Format == model.FormatAudio { ext = "mp3" + } else if feedConfig.Format == model.FormatCustom { + ext = feedConfig.CustomFormat.Extension } + // filePath now with the final extension filePath = filepath.Join(tmpDir, fmt.Sprintf("%s.%s", episode.ID, ext)) f, err := os.Open(filePath) @@ -236,7 +239,7 @@ func buildArgs(feedConfig *feed.Config, episode *model.Episode, outputFilePath s } args = append(args, "--format", format) - } else { + } else if feedConfig.Format == model.FormatAudio { // Audio, mp3, high by default format := "bestaudio" if feedConfig.Quality == model.QualityLow { @@ -244,6 +247,8 @@ func buildArgs(feedConfig *feed.Config, episode *model.Episode, outputFilePath s } args = append(args, "--extract-audio", "--audio-format", "mp3", "--format", format) + } else { + args = append(args, "--audio-format", feedConfig.CustomFormat.Extension, "--format", feedConfig.CustomFormat.YouTubeDLFormat) } // Insert additional per-feed youtube-dl arguments diff --git a/pkg/ytdl/ytdl_test.go b/pkg/ytdl/ytdl_test.go index c55571e..f1cbe91 100644 --- a/pkg/ytdl/ytdl_test.go +++ b/pkg/ytdl/ytdl_test.go @@ -11,14 +11,15 @@ import ( func TestBuildArgs(t *testing.T) { tests := []struct { - name string - format model.Format - quality model.Quality - maxHeight int - output string - videoURL string - ytdlArgs []string - expect []string + name string + format model.Format + customFormat feed.CustomFormat + quality model.Quality + maxHeight int + output string + videoURL string + ytdlArgs []string + expect []string }{ { name: "Audio unknown quality", @@ -101,6 +102,15 @@ func TestBuildArgs(t *testing.T) { ytdlArgs: []string{"--write-sub", "--embed-subs", "--sub-lang", "en,en-US,en-GB"}, expect: []string{"--format", "bestvideo[ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/best[ext=mp4][vcodec^=avc1]/best[ext=mp4]/best", "--write-sub", "--embed-subs", "--sub-lang", "en,en-US,en-GB", "--output", "/tmp/2", "http://url1"}, }, + { + name: "Custom format", + format: model.FormatCustom, + customFormat: feed.CustomFormat{YouTubeDLFormat: "bestaudio[ext=m4a]", Extension: "m4a"}, + quality: model.QualityHigh, + output: "/tmp/2", + videoURL: "http://url1", + expect: []string{"--audio-format", "m4a", "--format", "bestaudio[ext=m4a]", "--output", "/tmp/2", "http://url1"}, + }, } for _, tst := range tests { @@ -108,6 +118,7 @@ func TestBuildArgs(t *testing.T) { result := buildArgs(&feed.Config{ Format: tst.format, Quality: tst.quality, + CustomFormat: tst.customFormat, MaxHeight: tst.maxHeight, YouTubeDLArgs: tst.ytdlArgs, }, &model.Episode{