2022-01-02 14:57:10 +02:00
|
|
|
package main
|
2019-10-26 22:43:30 -07:00
|
|
|
|
|
|
|
import (
|
2019-11-23 13:25:07 -08:00
|
|
|
"fmt"
|
2020-04-20 18:38:52 -07:00
|
|
|
"io/ioutil"
|
2019-12-01 15:32:51 -08:00
|
|
|
"path/filepath"
|
2020-10-27 13:29:42 +08:00
|
|
|
"regexp"
|
2019-10-26 22:43:30 -07:00
|
|
|
|
2019-10-29 15:07:59 -07:00
|
|
|
"github.com/hashicorp/go-multierror"
|
2022-01-02 13:46:43 +02:00
|
|
|
"github.com/pelletier/go-toml"
|
2019-10-26 22:43:30 -07:00
|
|
|
"github.com/pkg/errors"
|
2019-10-29 12:50:06 -07:00
|
|
|
|
2022-01-02 14:57:10 +02:00
|
|
|
"github.com/mxpv/podsync/pkg/db"
|
|
|
|
"github.com/mxpv/podsync/pkg/feed"
|
2019-10-29 14:38:29 -07:00
|
|
|
"github.com/mxpv/podsync/pkg/model"
|
2022-01-02 14:57:10 +02:00
|
|
|
"github.com/mxpv/podsync/pkg/ytdl"
|
2019-10-29 12:50:06 -07:00
|
|
|
)
|
|
|
|
|
2022-01-02 14:57:10 +02:00
|
|
|
type ServerConfig struct {
|
2019-10-29 14:38:29 -07:00
|
|
|
// Hostname to use for download links
|
2019-11-13 22:54:43 -08:00
|
|
|
Hostname string `toml:"hostname"`
|
2019-10-26 22:43:30 -07:00
|
|
|
// Port is a server port to listen to
|
|
|
|
Port int `toml:"port"`
|
2020-10-27 13:29:42 +08:00
|
|
|
// Bind a specific IP addresses for server
|
|
|
|
// "*": bind all IP addresses which is default option
|
|
|
|
// localhost or 127.0.0.1 bind a single IPv4 address
|
|
|
|
BindAddress string `toml:"bind_address"`
|
|
|
|
// Specify path for reverse proxy and only [A-Za-z0-9]
|
|
|
|
Path string `toml:"path"`
|
2019-10-29 12:50:06 -07:00
|
|
|
// DataDir is a path to a directory to keep XML feeds and downloaded episodes,
|
|
|
|
// that will be available to user via web server for download.
|
|
|
|
DataDir string `toml:"data_dir"`
|
|
|
|
}
|
|
|
|
|
2020-04-17 15:47:02 +01:00
|
|
|
type Log struct {
|
|
|
|
// Filename to write the log to (instead of stdout)
|
|
|
|
Filename string `toml:"filename"`
|
|
|
|
// MaxSize is the maximum size of the log file in MB
|
|
|
|
MaxSize int `toml:"max_size"`
|
|
|
|
// MaxBackups is the maximum number of log file backups to keep after rotation
|
|
|
|
MaxBackups int `toml:"max_backups"`
|
|
|
|
// MaxAge is the maximum number of days to keep the logs for
|
|
|
|
MaxAge int `toml:"max_age"`
|
|
|
|
// Compress old backups
|
|
|
|
Compress bool `toml:"compress"`
|
|
|
|
}
|
|
|
|
|
2019-10-29 12:50:06 -07:00
|
|
|
type Config struct {
|
|
|
|
// Server is the web server configuration
|
2022-01-02 14:57:10 +02:00
|
|
|
Server ServerConfig `toml:"server"`
|
2020-04-17 15:47:02 +01:00
|
|
|
// Log is the optional logging configuration
|
|
|
|
Log Log `toml:"log"`
|
2019-12-01 15:32:51 -08:00
|
|
|
// Database configuration
|
2022-01-02 14:57:10 +02:00
|
|
|
Database db.Config `toml:"database"`
|
2019-10-26 22:43:30 -07:00
|
|
|
// Feeds is a list of feeds to host by this app.
|
|
|
|
// ID will be used as feed ID in http://podsync.net/{FEED_ID}.xml
|
2022-01-02 14:57:10 +02:00
|
|
|
Feeds map[string]*feed.Config
|
2019-10-26 22:43:30 -07:00
|
|
|
// Tokens is API keys to use to access YouTube/Vimeo APIs.
|
2022-01-02 13:46:43 +02:00
|
|
|
Tokens map[model.Provider][]string `toml:"tokens"`
|
2020-04-19 13:19:31 -07:00
|
|
|
// Downloader (youtube-dl) configuration
|
2022-01-02 14:57:10 +02:00
|
|
|
Downloader ytdl.Config `toml:"downloader"`
|
2019-10-26 22:43:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadConfig loads TOML configuration from a file path
|
|
|
|
func LoadConfig(path string) (*Config, error) {
|
2020-04-20 18:38:52 -07:00
|
|
|
data, err := ioutil.ReadFile(path)
|
2019-10-26 22:43:30 -07:00
|
|
|
if err != nil {
|
2020-04-20 18:38:52 -07:00
|
|
|
return nil, errors.Wrapf(err, "failed to read config file: %s", path)
|
|
|
|
}
|
|
|
|
|
|
|
|
config := Config{}
|
|
|
|
if err := toml.Unmarshal(data, &config); err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to unmarshal toml")
|
2019-10-29 12:50:06 -07:00
|
|
|
}
|
|
|
|
|
2022-01-02 14:57:10 +02:00
|
|
|
for id, f := range config.Feeds {
|
|
|
|
f.ID = id
|
2019-10-30 00:13:02 -07:00
|
|
|
}
|
|
|
|
|
2019-12-01 15:32:51 -08:00
|
|
|
config.applyDefaults(path)
|
2019-10-29 14:44:59 -07:00
|
|
|
|
2019-10-29 15:07:59 -07:00
|
|
|
if err := config.validate(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-10-29 14:44:59 -07:00
|
|
|
return &config, nil
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:07:59 -07:00
|
|
|
func (c *Config) validate() error {
|
|
|
|
var result *multierror.Error
|
|
|
|
|
|
|
|
if c.Server.DataDir == "" {
|
|
|
|
result = multierror.Append(result, errors.New("data directory is required"))
|
|
|
|
}
|
|
|
|
|
2020-10-27 13:29:42 +08:00
|
|
|
if c.Server.Path != "" {
|
|
|
|
var pathReg = regexp.MustCompile(model.PathRegex)
|
|
|
|
if !pathReg.MatchString(c.Server.Path) {
|
|
|
|
result = multierror.Append(result, errors.Errorf("Server handle path must be match %s or empty", model.PathRegex))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:07:59 -07:00
|
|
|
if len(c.Feeds) == 0 {
|
2020-10-27 13:29:42 +08:00
|
|
|
result = multierror.Append(result, errors.New("at least one feed must be specified"))
|
2019-10-29 15:07:59 -07:00
|
|
|
}
|
|
|
|
|
2022-01-02 14:57:10 +02:00
|
|
|
for id, f := range c.Feeds {
|
|
|
|
if f.URL == "" {
|
2019-10-29 15:07:59 -07:00
|
|
|
result = multierror.Append(result, errors.Errorf("URL is required for %q", id))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result.ErrorOrNil()
|
|
|
|
}
|
|
|
|
|
2019-12-01 15:32:51 -08:00
|
|
|
func (c *Config) applyDefaults(configPath string) {
|
2019-10-29 14:44:59 -07:00
|
|
|
if c.Server.Hostname == "" {
|
2019-11-23 13:25:07 -08:00
|
|
|
if c.Server.Port != 0 && c.Server.Port != 80 {
|
|
|
|
c.Server.Hostname = fmt.Sprintf("http://localhost:%d", c.Server.Port)
|
|
|
|
} else {
|
|
|
|
c.Server.Hostname = "http://localhost"
|
|
|
|
}
|
2019-10-29 14:38:29 -07:00
|
|
|
}
|
|
|
|
|
2020-04-17 15:47:02 +01:00
|
|
|
if c.Log.Filename != "" {
|
|
|
|
if c.Log.MaxSize == 0 {
|
|
|
|
c.Log.MaxSize = model.DefaultLogMaxSize
|
|
|
|
}
|
|
|
|
if c.Log.MaxAge == 0 {
|
|
|
|
c.Log.MaxAge = model.DefaultLogMaxAge
|
|
|
|
}
|
|
|
|
if c.Log.MaxBackups == 0 {
|
|
|
|
c.Log.MaxBackups = model.DefaultLogMaxBackups
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 15:32:51 -08:00
|
|
|
if c.Database.Dir == "" {
|
|
|
|
c.Database.Dir = filepath.Join(filepath.Dir(configPath), "db")
|
|
|
|
}
|
|
|
|
|
2019-10-29 14:44:59 -07:00
|
|
|
for _, feed := range c.Feeds {
|
2022-01-02 13:46:43 +02:00
|
|
|
if feed.UpdatePeriod == 0 {
|
|
|
|
feed.UpdatePeriod = model.DefaultUpdatePeriod
|
2019-10-29 12:50:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if feed.Quality == "" {
|
2019-10-29 14:44:59 -07:00
|
|
|
feed.Quality = model.DefaultQuality
|
2019-10-29 12:50:06 -07:00
|
|
|
}
|
|
|
|
|
2020-10-04 14:16:29 -07:00
|
|
|
if feed.Custom.CoverArtQuality == "" {
|
|
|
|
feed.Custom.CoverArtQuality = model.DefaultQuality
|
|
|
|
}
|
|
|
|
|
2019-10-29 12:50:06 -07:00
|
|
|
if feed.Format == "" {
|
2019-10-29 14:44:59 -07:00
|
|
|
feed.Format = model.DefaultFormat
|
2019-10-29 12:50:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if feed.PageSize == 0 {
|
2019-10-29 14:44:59 -07:00
|
|
|
feed.PageSize = model.DefaultPageSize
|
2019-10-29 12:50:06 -07:00
|
|
|
}
|
2021-12-28 08:06:10 +01:00
|
|
|
|
|
|
|
if feed.PlaylistSort == "" {
|
|
|
|
feed.PlaylistSort = model.SortingAsc
|
|
|
|
}
|
2019-10-26 22:43:30 -07:00
|
|
|
}
|
|
|
|
}
|