From 0cfebb86fa130d61c76b2d212c46db0278bff8ab Mon Sep 17 00:00:00 2001 From: Mathieu Cornic Date: Wed, 2 Apr 2025 18:26:54 +0200 Subject: [PATCH] feat: remove osdb (dead project) + add option to not have the language in the subtitle filename --- README.md | 30 +++--- cmd/dl.go | 21 +++- go.mod | 3 - go.sum | 8 -- subtitles/addic7ed.go | 14 ++- subtitles/languages.go | 8 +- subtitles/opensubtitles.go | 13 ++- subtitles/subdb.go | 186 ------------------------------------ subtitles/subtitles.go | 38 ++++++-- subtitles/subtitles_test.go | 8 +- 10 files changed, 93 insertions(+), 236 deletions(-) delete mode 100644 subtitles/subdb.go diff --git a/README.md b/README.md index 2b6def7..301ac38 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,12 @@ Subify is a tool to download subtitles for your favorite TV shows and movies. It is directly able to open the video with your default player, once the subtitle is downloaded. -Subify combines [SubDB Web API](http://thesubdb.com/), [OpenSubtitles API](http://trac.opensubtitles.org/projects/opensubtitles/wiki) and [Addic7ed](http://www.addic7ed.com/) to get the best subtitles for your video. It also considers that you use a default player interpreting srt subtitles when the video file name is the same than the srt file (ex: [VLC](http://www.videolan.org/vlc/)). +Subify combines [OpenSubtitles API](http://trac.opensubtitles.org/projects/opensubtitles/wiki) and [Addic7ed](http://www.addic7ed.com/) to get the best subtitles for your video. It also considers that you use a default player interpreting srt subtitles when the video file name is the same than the srt file (ex: [VLC](http://www.videolan.org/vlc/)). Subify gets the best match from several APIs in this order. This default behavior can easily be changed. See the documentation below -1. SubDB -2. OpenSubtitles -3. Addic7ed +1. OpenSubtitles +2. Addic7ed ## Installing @@ -71,16 +70,16 @@ Issues: Note : the binary is usable as is. If you want to run the command from anywhere on your OS, make sure to add Subify home installation to your PATH environment variable ```shell -# Download subtitle with default language (English) from default APIs (SubDB, then OpenSubtitles, then Addic7ed) +# Download subtitle with default language (English) from default APIs (OpenSubtitles, then Addic7ed) subify dl -# Download subtitle with default language (English), from default APIs (SubDB, then OpenSubtitles, then Addic7ed), then open video with your default player +# Download subtitle with default language (English), from default APIs (OpenSubtitles, then Addic7ed), then open video with your default player subify dl -o -# Download subtitle with french language, from default APIs (SubDB, then OpenSubtitles, then Addic7ed), and open with your default player +# Download subtitle with french language, from default APIs (OpenSubtitles, then Addic7ed), and open with your default player subify dl -o -l fr -# Download subtitle with french language, if not found spanish, if not found english, from default APIs (SubDB, then OpenSubtitles, then Addic7ed) +# Download subtitle with french language, if not found spanish, if not found english, from default APIs (OpenSubtitles, then Addic7ed) subify dl -l fr,es,en -# Download subtitle with default language, by searching first in OpenSubtitles, then in SubDB -subify dl -a os,subdb +# Download subtitle with default language, by searching first in Addic7ed then OpenSubtitles +subify dl -a add,os # Download subtitle with default language, by searching only in OpenSubtitles subify dl -a OpenSubtitles ``` @@ -121,9 +120,10 @@ Aliases: dl, download Flags: - -a, --apis string Overwrite default searching APIs behavior, hence the subtitles are downloaded. Available APIs at 'subify list apis' (default "SubDB,OpenSubtitles,Addic7ed") + -a, --apis string Overwrite default searching APIs behavior, hence the subtitles are downloaded. Available APIs at 'subify list apis' (default "OpenSubtitles,Addic7ed") -h, --help help for dl - -l, --languages string Languages of the subtitle separate by a comma (First to match is downloaded). Available languages at 'subify list languages' (default "en") + --lang-in-filename Language is in the filename (e.g. if enabled: 'xxx.English.srt' for English), else 'xxx.srt' (default true) + -l, --languages string Languages of the subtitle separated by a comma (First to match is downloaded). Available languages at 'subify list languages' (default "en") -n, --notify Display desktop notification (default true) -o, --open Once the subtitle is downloaded, open the video with your default video player (OSX: "open", Windows: "start", Linux/Other: "xdg-open") @@ -131,6 +131,7 @@ Global Flags: --config string Config file (default is $HOME/.subify.yaml|json|toml). Edit to change default behavior --dev Instantiate development sandbox instead of production variables -v, --verbose Print more information while executing + ``` ### Listing command @@ -188,11 +189,14 @@ dev = false # Don't turn on, just for development purpose # download for the download/dl command [download] languages = "en" # Searching for theses languages. Can be a list like : "fr,es,en" -apis = "SubDB,OpenSubtitles,Addic7ed" # Searching from these sites +apis = "OpenSubtitles,Addic7ed" # Searching from these sites notify = false ``` ## Release Notes +* **0.6.0** Apr 2, 2025 + * Implemented # + * Removed Subdb (project is dead) * **0.5.0** Apr 2, 2025 * Migrate to Go 1.23 * Updated Addic7ed library (again), as they changed implementation of the download button diff --git a/cmd/dl.go b/cmd/dl.go index e3f2657..c10e443 100644 --- a/cmd/dl.go +++ b/cmd/dl.go @@ -3,18 +3,21 @@ package cmd import ( "strings" - "github.com/matcornic/subify/common/utils" - "github.com/matcornic/subify/subtitles" "github.com/skratchdot/open-golang/open" "github.com/spf13/cobra" logger "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" + + "github.com/matcornic/subify/common/utils" + "github.com/matcornic/subify/subtitles" ) var openVideo bool var notify bool +var langInFileName bool + // dlCmd represents the dl command var dlCmd = &cobra.Command{ Use: "dl ", @@ -31,7 +34,14 @@ Give the path of your video as first parameter and let's go !`, apis := strings.Split(viper.GetString("download.apis"), ",") languages := strings.Split(viper.GetString("download.languages"), ",") - err := subtitles.Download(videoPath, apis, languages, notify) + options := []func(*subtitles.DownloadOptions){} + if langInFileName { + options = append(options, subtitles.WithLangInFileName()) + } + if notify { + options = append(options, subtitles.WithOSNotification()) + } + err := subtitles.Download(videoPath, apis, languages, options...) if err != nil { utils.ExitPrintError(err, "Sadly, we could not download any subtitle for you. Try another time or contribute to the apis. See 'subify upload -h'") } @@ -45,12 +55,13 @@ Give the path of your video as first parameter and let's go !`, } func init() { - dlCmd.Flags().StringP("languages", "l", "en", "Languages of the subtitle separate by a comma (First to match is downloaded). Available languages at 'subify list languages'") - dlCmd.Flags().StringP("apis", "a", "SubDB,OpenSubtitles,Addic7ed", "Overwrite default searching APIs behavior, hence the subtitles are downloaded. Available APIs at 'subify list apis'") + dlCmd.Flags().StringP("languages", "l", "en", "Languages of the subtitle separated by a comma (First to match is downloaded). Available languages at 'subify list languages'") + dlCmd.Flags().StringP("apis", "a", "OpenSubtitles,Addic7ed", "Overwrite default searching APIs behavior, hence the subtitles are downloaded. Available APIs at 'subify list apis'") dlCmd.Flags().BoolVarP(&openVideo, "open", "o", false, "Once the subtitle is downloaded, open the video with your default video player"+ ` (OSX: "open", Windows: "start", Linux/Other: "xdg-open")`) dlCmd.Flags().BoolVarP(¬ify, "notify", "n", true, "Display desktop notification") + dlCmd.Flags().BoolVar(&langInFileName, "lang-in-filename", true, "Language is in the filename (e.g. if enabled: 'xxx.English.srt' for English), else 'xxx.srt'") _ = viper.BindPFlag("download.languages", dlCmd.Flags().Lookup("languages")) _ = viper.BindPFlag("download.apis", dlCmd.Flags().Lookup("apis")) diff --git a/go.mod b/go.mod index fdc9b80..0659dc4 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,7 @@ go 1.23.8 require ( github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb - github.com/google/go-querystring v1.1.0 github.com/jacobmarshall/go-toast v0.0.0-20190211030409-01e6764cf0a4 - github.com/lafikl/fluent v0.0.0-20141109195914-392b95b3b5b2 github.com/matcornic/addic7ed v0.2.1 github.com/olekukonko/tablewriter v0.0.5 github.com/oz/osdb v0.0.0-20221214175751-f169057712ec @@ -26,7 +24,6 @@ require ( github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect - github.com/lafikl/backoff v0.0.0-20150814094333-4dc77674acea // indirect github.com/masatana/go-textdistance v0.0.0-20191005053614-738b0edac985 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect diff --git a/go.sum b/go.sum index 7ad6bde..7272076 100644 --- a/go.sum +++ b/go.sum @@ -16,11 +16,8 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jacobmarshall/go-toast v0.0.0-20190211030409-01e6764cf0a4 h1:OMNCPYu0cq+d1aM/RrQAcggZySgC7tYltYz4G1C6bLo= @@ -31,10 +28,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lafikl/backoff v0.0.0-20150814094333-4dc77674acea h1:BVM4DiWqlVWFfp9Smd5hr2ntgWjmQ8Y7v+Pa+vVSdQ0= -github.com/lafikl/backoff v0.0.0-20150814094333-4dc77674acea/go.mod h1:6QVfeSMvsSeGKj76ZIg7cxkSvMZgxjGWkBB9iQ+OIVw= -github.com/lafikl/fluent v0.0.0-20141109195914-392b95b3b5b2 h1:eRcUPoD8nHzgmNR/Oqb06uYKSkNa+W7J6NKgmVHC0eY= -github.com/lafikl/fluent v0.0.0-20141109195914-392b95b3b5b2/go.mod h1:XqgOzp3xB8IvokkubmN6YY1ylcNqt1WvRINPyPVc86Q= github.com/masatana/go-textdistance v0.0.0-20191005053614-738b0edac985 h1:Pz8zZjVRvKxISYimNzLGnzSNl5hYXFSN80FPQ+qt1HE= github.com/masatana/go-textdistance v0.0.0-20191005053614-738b0edac985/go.mod h1:1nU7rI+iBPtzc9ZKOqeQacD290rA0wcJLu5AtOSBBPw= github.com/matcornic/addic7ed v0.2.1 h1:44bNquok3pls5vpwcaeUxz/ZaMxpqnxEX7AxmFRmQZY= @@ -153,7 +146,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/subtitles/addic7ed.go b/subtitles/addic7ed.go index 13be879..2e8fc87 100644 --- a/subtitles/addic7ed.go +++ b/subtitles/addic7ed.go @@ -80,9 +80,12 @@ func Addic7ed() Addic7edAPI { } // Download downloads the Addic7ed subtitle from a video -func (s Addic7edAPI) Download(videoPath string, language Language) (subtitlePath string, err error) { +func (s Addic7edAPI) Download(videoPath string, language Language, downloadOptions ...func(*DownloadOptions)) (subtitlePath string, err error) { c := addic7ed.New() - + options := &DownloadOptions{} + for _, o := range downloadOptions { + o(options) + } lang, ok := addic7edLangs[language.ID] if !ok { return "", errors.New("Language exists but is not available for Addic7ed") @@ -94,7 +97,12 @@ func (s Addic7edAPI) Download(videoPath string, language Language) (subtitlePath } // Saving to disk - subtitlePath = videoPath[0:len(videoPath)-len(path.Ext(videoPath))] + "." + lang + ".srt" + basePath := videoPath[0 : len(videoPath)-len(path.Ext(videoPath))] + if options.langInFileName { + subtitlePath = basePath + "." + lang + ".srt" + } else { + subtitlePath = basePath + ".srt" + } if err := subtitle.DownloadTo(subtitlePath); err != nil { return "", err } diff --git a/subtitles/languages.go b/subtitles/languages.go index ea2b6c1..a9275fb 100644 --- a/subtitles/languages.go +++ b/subtitles/languages.go @@ -77,11 +77,11 @@ func (l Langs) Print(all bool) { sort.Sort(ByName(langs)) for _, l := range langs { - _, subOK := subdbLangs[l.ID] + _, addOK := addic7edLangs[l.ID] _, osOK := osLangs[l.ID] if all { available := "No" - if subOK || osOK { + if addOK || osOK { available = "Yes" } values := []string{ @@ -90,7 +90,7 @@ func (l Langs) Print(all bool) { available, // Available ? } table.Append(values) - } else if subOK || osOK { + } else if addOK || osOK { values := []string{ l.Description, // Language strings.Join(append(l.Alias, l.ID), ", "), // Available Id(s) @@ -103,7 +103,7 @@ func (l Langs) Print(all bool) { table.Render() // Send output } -//Languages is the list of all languages +// Languages is the list of all languages var Languages = Langs{ {"aar", []string{"aa"}, "Afar, afar"}, {"abk", []string{"ab"}, "Abkhazian"}, diff --git a/subtitles/opensubtitles.go b/subtitles/opensubtitles.go index 9c08867..0564e1a 100644 --- a/subtitles/opensubtitles.go +++ b/subtitles/opensubtitles.go @@ -91,13 +91,17 @@ func OpenSubtitles() OSDBAPI { } // Download downloads the OpenSubtitles subtitle from a video -func (s OSDBAPI) Download(videoPath string, language Language) (subtitlePath string, err error) { +func (s OSDBAPI) Download(videoPath string, language Language, downloadOptions ...func(*DownloadOptions)) (subtitlePath string, err error) { c, err := osdb.NewClient() if err != nil { return "", err } c.UserAgent = osdbUserAgent + options := &DownloadOptions{} + for _, o := range downloadOptions { + o(options) + } // Anonymous login if err = c.LogIn("", "", ""); err != nil { return "", err @@ -121,7 +125,12 @@ func (s OSDBAPI) Download(videoPath string, language Language) (subtitlePath str } // Saving to disk - subtitlePath = videoPath[0:len(videoPath)-len(path.Ext(videoPath))] + "." + lang + ".srt" + basePath := videoPath[0 : len(videoPath)-len(path.Ext(videoPath))] + if options.langInFileName { + subtitlePath = basePath + "." + lang + ".srt" + } else { + subtitlePath = basePath + ".srt" + } if err := c.DownloadTo(best, subtitlePath); err != nil { return "", err } diff --git a/subtitles/subdb.go b/subtitles/subdb.go deleted file mode 100644 index 0d5dd9e..0000000 --- a/subtitles/subdb.go +++ /dev/null @@ -1,186 +0,0 @@ -package subtitles - -import ( - "crypto/md5" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "time" - - "github.com/google/go-querystring/query" - "github.com/lafikl/fluent" - "github.com/matcornic/subify/common/config" -) - -const ( - subDbUserAgent = "SubDB/1.0 (Subify/0.1; http://github.com/matcornic/subify)" - subdbDevURL = "http://sandbox.thesubdb.com/" - subdbProdURL = "http://api.thesubdb.com/" -) - -var subdbLangs = map[string]string{ - "dut": "nl", - "eng": "en", - "fre": "fr", - "ita": "it", - "pol": "pl", - "spa": "es", - "swe": "sv", - "tur": "tr", - "rum": "ro", - "pob": "pt", -} - -// SubDBAPI entry point -type SubDBAPI struct { - Name string - Aliases []string -} - -// SubDB creates a new API for OpenSubtitles -func SubDB() SubDBAPI { - return SubDBAPI{ - Name: "SubDB", - Aliases: []string{"subdb"}, - } -} - -// Download downloads the SubDB subtitle from a video -func (s SubDBAPI) Download(videoPath string, language Language) (subtitlePath string, err error) { - // Get unique hash to identify video - hash, err := getHashOfVideo(videoPath) - if err != nil { - return "", err - } - // Call SubDB API to get subtitle - lang, ok := subdbLangs[language.ID] - if !ok { - return "", errors.New("Language exists but is not available for SubDB") - } - subtitle, err := subtitles(hash, lang) - if err != nil { - return "", err - } - - // Save the content to file - subtitlePath = videoPath[0:len(videoPath)-len(path.Ext(videoPath))] + "." + lang + ".srt" - - err = ioutil.WriteFile(subtitlePath, subtitle, 0644) - if err != nil { - return "", fmt.Errorf("Can't save the file %v because of : %v", subtitlePath, err) - } - - return subtitlePath, nil -} - -// Upload uploads the subtitle to SubDB, for the given video -func (s SubDBAPI) Upload(subtitlePath string, language Language, videoPath string) error { - return errors.New("Not yet implemented") -} - -// GetName returns the name of the api -func (s SubDBAPI) GetName() string { - return s.Name -} - -// GetAliases returns aliases to identify this API -func (s SubDBAPI) GetAliases() []string { - return s.Aliases -} - -// options describes parameters to the SubDB API -type options struct { - Action string `url:"action,omitempty"` - Hash string `url:"hash,omitempty"` - Language string `url:"language,omitempty"` -} - -//getHashOfVideo gets the hash used by SubDb to identify a video. Absolutely needed either to download or upload subtitles. -//The hash is composed by taking the first and the last 64kb of the video file, putting all together and generating a md5 of the resulting data (128kb). -func getHashOfVideo(filename string) (string, error) { - readsize := 64 * 1024 // 64kb - - // Open Video - file, err := os.Open(filename) - if err != nil { - return "", fmt.Errorf("Can't open file %v because of : %v ", filename, err.Error()) - } - defer file.Close() - - // Get stats of file - fi, err := file.Stat() - if err != nil { - return "", fmt.Errorf("Can't get stats for file %v because of : %v", filename, err.Error()) - } - - // Fill a buffer with first bytes of file - bufB := make([]byte, readsize) - _, err = file.Read(bufB) - if err != nil { - return "", fmt.Errorf("Can't read content of file %v because of : %v", filename, err.Error()) - } - - //Fill a buffer with last bytes of file - bufE := make([]byte, readsize) - n, err := file.ReadAt(bufE, fi.Size()-int64(len(bufE))) - if err != nil { - return "", fmt.Errorf("File is probably too small, can't read content of file %v because of : %v", filename, err.Error()) - } - bufE = bufE[:n] - - // Generates MD5 of both bytes chain - bufB = append(bufB, bufE...) - hash := fmt.Sprintf("%x", md5.Sum(bufB)) - - return hash, nil -} - -func buildURL(hash string, language string) string { - baseURL := subdbProdURL - if config.Dev { - fmt.Println("Dev mode") - baseURL = subdbDevURL - } else { - fmt.Println("Prod mode") - } - opt := options{ - Action: "download", - Hash: hash, - Language: language} - v, _ := query.Values(opt) - - url := baseURL + "?" + v.Encode() - - return url -} - -// Subtitles get the subtitles from the hash of a video -func subtitles(hash string, language string) ([]byte, error) { - - // Build request - req := fluent.New() - req.Get(buildURL(hash, language)). - SetHeader("User-Agent", subDbUserAgent). - InitialInterval(time.Duration(time.Millisecond)). - Retry(3) - - // Execute the request - res, err := req.Send() - if err != nil { - return []byte{}, fmt.Errorf("Can't reach the SubDB Web API. Are you connected to the Internet ? %v", err.Error()) - } - if res.StatusCode != 200 { - return []byte{}, fmt.Errorf(`Subtitle not stored by SubDB`) - } - - // Extract the subtitles from the response - defer res.Body.Close() - content, err := ioutil.ReadAll(res.Body) - if err != nil { - return []byte{}, fmt.Errorf("The content of the subtitles dowloaded from Subdb is corrupted") - } - - return content, nil -} diff --git a/subtitles/subtitles.go b/subtitles/subtitles.go index 537f5ab..f92c556 100644 --- a/subtitles/subtitles.go +++ b/subtitles/subtitles.go @@ -6,14 +6,32 @@ import ( "strconv" "strings" - "github.com/matcornic/subify/notif" "github.com/olekukonko/tablewriter" logger "github.com/spf13/jwalterweatherman" + + "github.com/matcornic/subify/notif" ) +type DownloadOptions struct { + langInFileName bool + notify bool +} + +func WithLangInFileName() func(*DownloadOptions) { + return func(s *DownloadOptions) { + s.langInFileName = true + } +} + +func WithOSNotification() func(*DownloadOptions) { + return func(s *DownloadOptions) { + s.notify = true + } +} + // Client defines the interface to get subtitles from API type Client interface { - Download(videoPath string, language Language) (subtitlePath string, err error) + Download(videoPath string, language Language, options ...func(*DownloadOptions)) (subtitlePath string, err error) Upload(subtitlePath string, language Language, videoPath string) error GetName() string GetAliases() []string @@ -25,7 +43,6 @@ type Clients []Client // DefaultAPIs represents the available APIs // Is also used as the default var DefaultAPIs = Clients{ - SubDB(), OpenSubtitles(), Addic7ed(), } @@ -62,7 +79,7 @@ func (c Clients) Print() { table.Render() // Send output } -//String prints a nice representation of clients +// String prints a nice representation of clients func (c Clients) String() (s string) { for i, v := range c { s = s + v.GetName() @@ -74,7 +91,7 @@ func (c Clients) String() (s string) { } // Download the subtitle from the video identified by its path -func Download(videoPath string, apiAliases []string, languages []string, notify bool) error { +func Download(videoPath string, apiAliases []string, languages []string, downloadOptions ...func(*DownloadOptions)) error { // APIs to download subtitles. var subtitlePath string var err error @@ -98,6 +115,11 @@ func Download(videoPath string, apiAliases []string, languages []string, notify logger.WARN.Println("Some languages are not recognized. Given:", languages, "Found:", l.GetDescriptions()) } + options := &DownloadOptions{} + for _, o := range downloadOptions { + o(options) + } + // Run through languages browselang: for i, lang := range l { @@ -105,9 +127,9 @@ browselang: logger.INFO.Println("===> ("+strconv.Itoa(i+1)+") Searching subtitles for", lang.Description, "language") for j, api := range a { logger.INFO.Println("=> (" + strconv.Itoa(i+1) + "." + strconv.Itoa(j+1) + ") Downloading subtitle with " + api.GetName() + "...") - subtitlePath, err = api.Download(videoPath, lang) + subtitlePath, err = api.Download(videoPath, lang, downloadOptions...) if err == nil { - if notify { + if options.notify { notif.SendSubtitleDownloadSuccess(api.GetName()) } logger.INFO.Println(lang.Description, "subtitle found and saved to ", subtitlePath) @@ -128,7 +150,7 @@ browselang: } if err != nil { - if notify { + if options.notify { notif.SendSubtitleCouldNotBeDownloaded(a.String()) } return fmt.Errorf("No %v subtitle found, even after searching in all APIs (%v)", strings.Join(l.GetDescriptions(), ", nor "), a.String()) diff --git a/subtitles/subtitles_test.go b/subtitles/subtitles_test.go index 34a43cf..26d97d6 100644 --- a/subtitles/subtitles_test.go +++ b/subtitles/subtitles_test.go @@ -7,15 +7,15 @@ import ( ) func TestInitAPIsShouldExists(t *testing.T) { - apis := InitAPIs([]string{"subdb", "oS"}) + apis := InitAPIs([]string{"addic7ed", "oS"}) assert.Equal(t, len(apis), 2, "Should have two apis") - assert.Equal(t, apis[0].GetName(), "SubDB", "Should be SubDB") + assert.Equal(t, apis[0].GetName(), "Addic7ed", "Should be Addic7ed") assert.Equal(t, apis[1].GetName(), "OpenSubtitles", "Should be OpenSubtitles") } func TestInitAPIsShouldExistsWithOneThatDoesNotExist(t *testing.T) { - apis := InitAPIs([]string{"subDB", "os", "dontexist"}) + apis := InitAPIs([]string{"addic7ed", "os", "dontexist"}) assert.Equal(t, len(apis), 2, "Should have two apis") - assert.Equal(t, apis[0].GetName(), "SubDB", "Should be SubDB") + assert.Equal(t, apis[0].GetName(), "Addic7ed", "Should be Addic7ed") assert.Equal(t, apis[1].GetName(), "OpenSubtitles", "Should be OpenSubtitles") }