Skip to content

Commit 6c5f602

Browse files
authored
Merge pull request #442 from Harnas/feature/custom_file_format
feat: added custom format support
2 parents 67281bc + 7d44946 commit 6c5f602

File tree

6 files changed

+71
-14
lines changed

6 files changed

+71
-14
lines changed

config.toml.example

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,18 @@ vimeo = [ # Multiple keys will be rotated.
5050
# How often query for updates, examples: "60m", "4h", "2h45m"
5151
update_period = "12h"
5252

53-
quality = "high" # or "low"
54-
format = "video" # or "audio"
53+
quality = "high" # "high" or "low"
54+
format = "video" # "audio", "video" or "custom"
55+
# When format = "custom"
56+
# YouTubeDL format parameter and result file extension
57+
custom_format = { youtube_dl_format = "bestaudio[ext=m4a]", extension = "m4a" }
58+
5559
playlist_sort = "asc" # or "desc", which will fetch playlist items from the end
5660

5761
# Optional maximal height of video, example: 720, 1080, 1440, 2160, ...
5862
max_height = 720
5963

60-
# Optinally include this feed in OPML file (default value: false)
64+
# Optionally include this feed in OPML file (default value: false)
6165
opml = true
6266

6367
# Optional cron expression format for more precise update schedule.

pkg/feed/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type Config struct {
2828
MaxHeight int `toml:"max_height"`
2929
// Format to use for this feed
3030
Format model.Format `toml:"format"`
31+
// Custom format properties
32+
CustomFormat CustomFormat `toml:"custom_format"`
3133
// Only download episodes that match this regexp (defaults to matching anything)
3234
Filters Filters `toml:"filters"`
3335
// Clean is a cleanup policy to use for this feed
@@ -44,6 +46,11 @@ type Config struct {
4446
PlaylistSort model.Sorting `toml:"playlist_sort"`
4547
}
4648

49+
type CustomFormat struct {
50+
YouTubeDLFormat string `toml:"youtube_dl_format"`
51+
Extension string `toml:"extension"`
52+
}
53+
4754
type Filters struct {
4855
Title string `toml:"title"`
4956
NotTitle string `toml:"not_title"`

pkg/feed/xml.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ func Build(_ctx context.Context, feed *model.Feed, cfg *Config, hostname string)
133133
if feed.Format == model.FormatAudio {
134134
enclosureType = itunes.MP3
135135
}
136+
if feed.Format == model.FormatCustom {
137+
enclosureType = EnclosureFromExtension(cfg)
138+
}
136139

137140
var (
138141
episodeName = EpisodeName(cfg, episode)
@@ -165,6 +168,31 @@ func EpisodeName(feedConfig *Config, episode *model.Episode) string {
165168
if feedConfig.Format == model.FormatAudio {
166169
ext = "mp3"
167170
}
171+
if feedConfig.Format == model.FormatCustom {
172+
ext = feedConfig.CustomFormat.Extension
173+
}
168174

169175
return fmt.Sprintf("%s.%s", episode.ID, ext)
170176
}
177+
178+
func EnclosureFromExtension(feedConfig *Config) itunes.EnclosureType {
179+
ext := feedConfig.CustomFormat.Extension
180+
181+
switch {
182+
case ext == "m4a":
183+
return itunes.M4A
184+
case ext == "m4v":
185+
return itunes.M4V
186+
case ext == "mp4":
187+
return itunes.MP4
188+
case ext == "mp3":
189+
return itunes.MP3
190+
case ext == "mov":
191+
return itunes.MOV
192+
case ext == "pdf":
193+
return itunes.PDF
194+
case ext == "epub":
195+
return itunes.EPUB
196+
}
197+
return -1
198+
}

pkg/model/feed.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ const (
1616
type Format string
1717

1818
const (
19-
FormatAudio = Format("audio")
20-
FormatVideo = Format("video")
19+
FormatAudio = Format("audio")
20+
FormatVideo = Format("video")
21+
FormatCustom = Format("custom")
2122
)
2223

2324
// Playlist sorting style

pkg/ytdl/ytdl.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ func (dl *YoutubeDl) Download(ctx context.Context, feedConfig *feed.Config, epis
198198
if feedConfig.Format == model.FormatAudio {
199199
ext = "mp3"
200200
}
201+
if feedConfig.Format == model.FormatCustom {
202+
ext = feedConfig.CustomFormat.Extension
203+
}
204+
201205
// filePath now with the final extension
202206
filePath = filepath.Join(tmpDir, fmt.Sprintf("%s.%s", episode.ID, ext))
203207
f, err := os.Open(filePath)
@@ -236,14 +240,16 @@ func buildArgs(feedConfig *feed.Config, episode *model.Episode, outputFilePath s
236240
}
237241

238242
args = append(args, "--format", format)
239-
} else {
243+
} else if feedConfig.Format == model.FormatAudio {
240244
// Audio, mp3, high by default
241245
format := "bestaudio"
242246
if feedConfig.Quality == model.QualityLow {
243247
format = "worstaudio"
244248
}
245249

246250
args = append(args, "--extract-audio", "--audio-format", "mp3", "--format", format)
251+
} else {
252+
args = append(args, "--audio-format", feedConfig.CustomFormat.Extension, "--format", feedConfig.CustomFormat.YouTubeDLFormat)
247253
}
248254

249255
// Insert additional per-feed youtube-dl arguments

pkg/ytdl/ytdl_test.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import (
1111

1212
func TestBuildArgs(t *testing.T) {
1313
tests := []struct {
14-
name string
15-
format model.Format
16-
quality model.Quality
17-
maxHeight int
18-
output string
19-
videoURL string
20-
ytdlArgs []string
21-
expect []string
14+
name string
15+
format model.Format
16+
customFormat feed.CustomFormat
17+
quality model.Quality
18+
maxHeight int
19+
output string
20+
videoURL string
21+
ytdlArgs []string
22+
expect []string
2223
}{
2324
{
2425
name: "Audio unknown quality",
@@ -101,13 +102,23 @@ func TestBuildArgs(t *testing.T) {
101102
ytdlArgs: []string{"--write-sub", "--embed-subs", "--sub-lang", "en,en-US,en-GB"},
102103
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"},
103104
},
105+
{
106+
name: "Custom format",
107+
format: model.FormatCustom,
108+
customFormat: feed.CustomFormat{YouTubeDLFormat: "bestaudio[ext=m4a]", Extension: "m4a"},
109+
quality: model.QualityHigh,
110+
output: "/tmp/2",
111+
videoURL: "http://url1",
112+
expect: []string{"--audio-format", "m4a", "--format", "bestaudio[ext=m4a]", "--output", "/tmp/2", "http://url1"},
113+
},
104114
}
105115

106116
for _, tst := range tests {
107117
t.Run(tst.name, func(t *testing.T) {
108118
result := buildArgs(&feed.Config{
109119
Format: tst.format,
110120
Quality: tst.quality,
121+
CustomFormat: tst.customFormat,
111122
MaxHeight: tst.maxHeight,
112123
YouTubeDLArgs: tst.ytdlArgs,
113124
}, &model.Episode{

0 commit comments

Comments
 (0)