Skip to content

Commit

Permalink
Merge pull request #442 from Harnas/feature/custom_file_format
Browse files Browse the repository at this point in the history
feat: added custom format support
  • Loading branch information
mxpv authored Nov 23, 2022
2 parents 67281bc + 7d44946 commit 6c5f602
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 14 deletions.
10 changes: 7 additions & 3 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,18 @@ vimeo = [ # Multiple keys will be rotated.
# How often query for updates, examples: "60m", "4h", "2h45m"
update_period = "12h"

quality = "high" # or "low"
format = "video" # or "audio"
quality = "high" # "high" or "low"
format = "video" # "audio", "video" or "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.
Expand Down
7 changes: 7 additions & 0 deletions pkg/feed/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"`
Expand Down
28 changes: 28 additions & 0 deletions pkg/feed/xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ func Build(_ctx context.Context, feed *model.Feed, cfg *Config, hostname string)
if feed.Format == model.FormatAudio {
enclosureType = itunes.MP3
}
if feed.Format == model.FormatCustom {
enclosureType = EnclosureFromExtension(cfg)
}

var (
episodeName = EpisodeName(cfg, episode)
Expand Down Expand Up @@ -165,6 +168,31 @@ func EpisodeName(feedConfig *Config, episode *model.Episode) string {
if feedConfig.Format == model.FormatAudio {
ext = "mp3"
}
if feedConfig.Format == model.FormatCustom {
ext = feedConfig.CustomFormat.Extension
}

return fmt.Sprintf("%s.%s", episode.ID, ext)
}

func EnclosureFromExtension(feedConfig *Config) itunes.EnclosureType {
ext := feedConfig.CustomFormat.Extension

switch {
case ext == "m4a":
return itunes.M4A
case ext == "m4v":
return itunes.M4V
case ext == "mp4":
return itunes.MP4
case ext == "mp3":
return itunes.MP3
case ext == "mov":
return itunes.MOV
case ext == "pdf":
return itunes.PDF
case ext == "epub":
return itunes.EPUB
}
return -1
}
5 changes: 3 additions & 2 deletions pkg/model/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion pkg/ytdl/ytdl.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ func (dl *YoutubeDl) Download(ctx context.Context, feedConfig *feed.Config, epis
if feedConfig.Format == model.FormatAudio {
ext = "mp3"
}
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)
Expand Down Expand Up @@ -236,14 +240,16 @@ 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 {
format = "worstaudio"
}

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
Expand Down
27 changes: 19 additions & 8 deletions pkg/ytdl/ytdl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -101,13 +102,23 @@ 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 {
t.Run(tst.name, func(t *testing.T) {
result := buildArgs(&feed.Config{
Format: tst.format,
Quality: tst.quality,
CustomFormat: tst.customFormat,
MaxHeight: tst.maxHeight,
YouTubeDLArgs: tst.ytdlArgs,
}, &model.Episode{
Expand Down

0 comments on commit 6c5f602

Please sign in to comment.