Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#74 limit maximal resolution of videos #80

Merged
merged 3 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ vimeo = "{VIMEO_API_TOKEN}"
quality = "high" # or "low"
format = "video" # or "audio"
cover_art = "{IMAGE_URL}" # Optional URL address of an image file
max_height = "720" # Optional maximal height of video, example: 720, 1080, 1440, 2160, ...
```

Episodes files will be kept at: `/path/to/data/directory/ID1`, feed will be accessible from: `http://localhost/ID1.xml`
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type Feed struct {
UpdatePeriod Duration `toml:"update_period"`
// Quality to use for this feed
Quality model.Quality `toml:"quality"`
// Maximum height of video
MaxHeight int `toml:"max_height"`
// Format to use for this feed
Format model.Format `toml:"format"`
// Custom image to use
Expand Down
39 changes: 39 additions & 0 deletions pkg/ytdl/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ytdl

import (
"fmt"
"path/filepath"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

type Options interface {
GetConfig() []string
}

type OptionsDl struct{}

func (o OptionsDl) New(feedConfig *config.Feed, episode *model.Episode, feedPath string) []string {

var (
arguments []string
options Options
)

if feedConfig.Format == model.FormatVideo {
options = NewOptionsVideo(feedConfig)
} else {
options = NewOptionsAudio(feedConfig)
}

arguments = options.GetConfig()
arguments = append(arguments, "--output", o.makeOutputTemplate(feedPath, episode), episode.VideoURL)

return arguments
}

func (o OptionsDl) makeOutputTemplate(feedPath string, episode *model.Episode) string {
filename := fmt.Sprintf("%s.%s", episode.ID, "%(ext)s")
return filepath.Join(feedPath, filename)
}
33 changes: 33 additions & 0 deletions pkg/ytdl/options_audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ytdl

import (
"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

type OptionsAudio struct {
quality model.Quality
}

func NewOptionsAudio(feedConfig *config.Feed) *OptionsAudio {
options := &OptionsAudio{}
options.quality = feedConfig.Quality

return options
}

func (options OptionsAudio) GetConfig() []string {
var arguments []string

arguments = append(arguments, "--extract-audio", "--audio-format", "mp3")

switch options.quality {
case model.QualityLow:
// really? somebody use it?
arguments = append(arguments, "--format", "worstaudio")
default:
arguments = append(arguments, "--format", "bestaudio")
}

return arguments
}
67 changes: 67 additions & 0 deletions pkg/ytdl/options_audio_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ytdl

import (
"reflect"
"testing"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

func TestNewOptionsAudio(t *testing.T) {
type args struct {
feedConfig *config.Feed
}
tests := []struct {
name string
args args
want *OptionsAudio
}{
{
"Get OptionsAudio in low quality",
args{
feedConfig: &config.Feed{Quality: model.QualityLow},
},
&OptionsAudio{quality: model.QualityLow},
},
{
"Get OptionsAudio in high quality",
args{
feedConfig: &config.Feed{Quality: model.QualityHigh},
},
&OptionsAudio{quality: model.QualityHigh},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewOptionsAudio(tt.args.feedConfig); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewOptionsAudio() = %v, want %v", got, tt.want)
}
})
}
}

func TestOptionsAudio_GetConfig(t *testing.T) {
type fields struct {
quality model.Quality
}
tests := []struct {
name string
fields fields
want []string
}{
{"OptionsAudio in unknown quality", fields{quality: model.Quality("unknown")}, []string{"--extract-audio", "--audio-format", "mp3", "--format", "bestaudio"}},
{"OptionsAudio in low quality", fields{quality: model.Quality("low")}, []string{"--extract-audio", "--audio-format", "mp3", "--format", "worstaudio"}},
{"OptionsAudio in high quality", fields{quality: model.Quality("high")}, []string{"--extract-audio", "--audio-format", "mp3", "--format", "bestaudio"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
options := OptionsAudio{
quality: tt.fields.quality,
}
if got := options.GetConfig(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetConfig() = %v, want %v", got, tt.want)
}
})
}
}
50 changes: 50 additions & 0 deletions pkg/ytdl/options_video.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ytdl

import (
"fmt"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

type OptionsVideo struct {
quality model.Quality
maxHeight int
}

func NewOptionsVideo(feedConfig *config.Feed) *OptionsVideo {
options := &OptionsVideo{}

options.quality = feedConfig.Quality
options.maxHeight = feedConfig.MaxHeight

return options
}

func (options OptionsVideo) GetConfig() []string {
var (
arguments []string
format string
)

switch options.quality {
// I think after enabling MaxHeight param QualityLow option don't need.
// If somebody want download video in low quality then can set MaxHeight to 360p
// ¯\_(ツ)_/¯
case model.QualityLow:
format = "worstvideo[ext=mp4]+worstaudio[ext=m4a]/worst[ext=mp4]/worst"
default:
format = "bestvideo%s[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"

if options.maxHeight > 0 {
format = fmt.Sprintf(format, fmt.Sprintf("[height<=%d]", options.maxHeight))
} else {
// unset replace pattern
format = fmt.Sprintf(format, "")
}
}

arguments = append(arguments, "--format", format)

return arguments
}
110 changes: 110 additions & 0 deletions pkg/ytdl/options_video_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package ytdl

import (
"reflect"
"testing"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

func TestNewOptionsVideo(t *testing.T) {
type args struct {
feedConfig *config.Feed
}
tests := []struct {
name string
args args
want *OptionsVideo
}{
{
"Get OptionsVideo in low quality",
args{
feedConfig: &config.Feed{Quality: model.QualityLow},
},
&OptionsVideo{quality: model.QualityLow},
},
{
"Get OptionsVideo in low quality with maxheight",
args{
feedConfig: &config.Feed{Quality: model.QualityLow, MaxHeight: 720},
},
&OptionsVideo{quality: model.QualityLow, maxHeight: 720},
},
{
"Get OptionsVideo in high quality",
args{
feedConfig: &config.Feed{Quality: model.QualityHigh},
},
&OptionsVideo{quality: model.QualityHigh},
},
{
"Get OptionsVideo in high quality with maxheight",
args{
feedConfig: &config.Feed{Quality: model.QualityHigh, MaxHeight: 720},
},
&OptionsVideo{quality: model.QualityHigh, maxHeight: 720},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewOptionsVideo(tt.args.feedConfig); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewOptionsVideo() = %v, want %v", got, tt.want)
}
})
}
}

func TestOptionsVideo_GetConfig(t *testing.T) {
type fields struct {
quality model.Quality
maxHeight int
}
tests := []struct {
name string
fields fields
want []string
}{
{
"OptionsVideo in unknown quality",
fields{quality: model.Quality("unknown")},
[]string{"--format", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"},
},
{
"OptionsVideo in unknown quality with maxheight",
fields{quality: model.Quality("unknown"), maxHeight: 720},
[]string{"--format", "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"},
},
{
"OptionsVideo in low quality",
fields{quality: model.QualityLow},
[]string{"--format", "worstvideo[ext=mp4]+worstaudio[ext=m4a]/worst[ext=mp4]/worst"},
},
{
"OptionsVideo in low quality with maxheight",
fields{quality: model.QualityLow, maxHeight: 720},
[]string{"--format", "worstvideo[ext=mp4]+worstaudio[ext=m4a]/worst[ext=mp4]/worst"},
},
{
"OptionsVideo in high quality",
fields{quality: model.QualityHigh},
[]string{"--format", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"},
},
{
"OptionsVideo in high quality with maxheight",
fields{quality: model.QualityHigh, maxHeight: 720},
[]string{"--format", "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
options := OptionsVideo{
quality: tt.fields.quality,
maxHeight: tt.fields.maxHeight,
}
if got := options.GetConfig(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetConfig() = %v, want %v", got, tt.want)
}
})
}
}
Loading