diff --git a/anime_episode_filepath.go b/anime_episode_filepath.go new file mode 100644 index 0000000..4b03aee --- /dev/null +++ b/anime_episode_filepath.go @@ -0,0 +1,22 @@ +package logic + +import ( + "path/filepath" + "strings" + + "git.milar.in/nyaanime/model" +) + +func GetAnimeEpFilepath(animeEp model.AnimeEpisode, ext string) string { + tmplData := AnimePathPatternData{ + Title: animeEp.Anime.Title, + Episode: animeEp.Episode, + Ext: ext, + } + + b := new(strings.Builder) + if err := AnimeEpFilepathPattern.Execute(b, tmplData); err != nil { + panic(err) + } + return filepath.Join(AnimePath, b.String()) +} diff --git a/envvars.go b/envvars.go index a7cf3cf..df647f1 100644 --- a/envvars.go +++ b/envvars.go @@ -1,13 +1,56 @@ package logic import ( + "html/template" + "math" + "git.milar.in/milarin/envvars/v2" "git.milar.in/nyaanime/model" ) var ( + AnimePath = envvars.String("ANIME_PATH", "") + + AnimeEpFilepathPattern = envvars.Object( + "EPISODE_FILEPATH_PATTERN", + template.Must(template.New("anime-episode-filepath-pattern").Parse(`{{.Title.UserPreferred}}/{{.Title.UserPreferred}} Episode {{.Episode}}.{{.Ext}}`)), + template.New("anime-episode-filepath-pattern").Parse, + ) + + // essential torrent properties + + MaxResolution = envvars.Object("MAX_RESOLUTION", model.Resolution4K, model.ParseResolution) + MinResolution = envvars.Object("MIN_RESOLUTION", model.ResolutionHD, model.ParseResolution) + + EssentialLanguages = envvars.StringSlice("ESSENTIAL_LANGUAGES", "|", []string{}) + EssentialSubtitles = envvars.StringSlice("ESSENTIAL_SUBTITLES", "|", []string{}) + + MaxSeeders = envvars.Int("MAX_SEEDERS", math.MaxInt) + MinSeeders = envvars.Int("MIN_SEEDERS", 0) + + MaxLeechers = envvars.Int("MAX_LEECHERS", math.MaxInt) + MinLeechers = envvars.Int("MIN_LEECHERS", 0) + + MaxDownloads = envvars.Int("MAX_DOWNLOADS", math.MaxInt) + MinDownloads = envvars.Int("MIN_DOWNLOADS", 0) + + TrustedOnly = envvars.Bool("TRUSTED_ONLY", false) + // preferred torrent properties PreferredLanguages = ParsePreferredStringProps(envvars.StringSlice("PREFERRED_LANGUAGES", "|", []string{})) PreferredSubtitles = ParsePreferredStringProps(envvars.StringSlice("PREFERRED_SUBTITLES", "|", []string{})) PreferredResolutions = ParsePreferredProps(envvars.StringSlice("PREFERRED_RESOLUTIONS", "|", []string{}), model.ParseResolution) + + /* + TODO + + better idea? implementation in torrent_sort.go (sort.Slice) + PreferredTorrents = envvars.StringSlice("PREFERRED_TORRENTS", []string{"seeders", "subtitles", "languages", "downloads"}) + + old idea? + PreferMoreLanguages = envvars.Bool("PREFERER_MORE_LANGUAGES", false) + PreferMoreSubtitles = envvars.Bool("PREFERER_MORE_SUBTITLES", false) + PreferMoreSeeders = envvars.Bool("PREFERER_MORE_SEEDERS", false) + PreferMoreDownloads = envvars.Bool("PREFERER_MORE_DOWNLOADS", false) + */ ) diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..202d91b --- /dev/null +++ b/errors.go @@ -0,0 +1,7 @@ +package logic + +import "git.milar.in/milarin/adverr" + +var ( + ErrInvalidGlobSyntax = adverr.NewErrTmpl("ErrInvalidGlobSyntax", "invalid filepath.Glob syntax: '%s'") +) diff --git a/file_priority.go b/file_priority.go new file mode 100644 index 0000000..1a1d844 --- /dev/null +++ b/file_priority.go @@ -0,0 +1,21 @@ +package logic + +import ( + "git.milar.in/nyaanime/model" +) + +type FilePriority struct { + Properties model.PropertyHolder + Priority int + PreferredProperties map[string]int +} + +func NewFilePriority(props model.PropertyHolder) *FilePriority { + priority, preferredProperties := DeterminePriority(props) + + return &FilePriority{ + Properties: props, + Priority: priority, + PreferredProperties: preferredProperties, + } +} diff --git a/file_props.go b/file_props.go new file mode 100644 index 0000000..981e39c --- /dev/null +++ b/file_props.go @@ -0,0 +1,65 @@ +package logic + +import ( + "path/filepath" + + "git.milar.in/milarin/anilist" + "git.milar.in/milarin/slices" + "git.milar.in/nyaanime/model" + "git.milar.in/nyaanime/parsers" +) + +type AnimePathPatternData struct { + Title anilist.MediaTitle + Episode int + Ext string +} + +func GetAnimeEpProps(animeEp model.AnimeEpisode) (*FilePriority, bool) { + animeEpPath := GetAnimeEpFilepath(animeEp, "*") + files, err := filepath.Glob(animeEpPath) + if err != nil { + panic(ErrInvalidGlobSyntax.Wrap(err, animeEpPath)) + } + + var mostPrio *FilePriority + + for _, file := range files { + props, err := parsers.AnalyzeFile(file) + if err != nil { + continue + } + + if !HasFileEssentialProperties(props) { + continue + } + + fp := NewFilePriority(props) + + if mostPrio == nil || fp.Priority > mostPrio.Priority { + mostPrio = fp + } + } + + return mostPrio, mostPrio != nil +} + +func HasFileEssentialProperties(props model.PropertyHolder) bool { + if props.GetResolution() < MinResolution || props.GetResolution() > MaxResolution { + return false + } + + for _, essentialLanguage := range EssentialLanguages { + if !slices.Contains(props.GetLanguages(), essentialLanguage) { + return false + } + } + + for _, essentialSubtitle := range EssentialSubtitles { + if !slices.Contains(props.GetSubtitles(), essentialSubtitle) { + return false + } + } + + return true +} diff --git a/go.mod b/go.mod index d70f5c0..241ee25 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,13 @@ module git.milar.in/nyaanime/logic go 1.19 require ( + git.milar.in/milarin/adverr v0.2.1 + git.milar.in/milarin/anilist v1.5.0 git.milar.in/milarin/envvars/v2 v2.0.0 git.milar.in/milarin/gmath v0.0.3 git.milar.in/milarin/slices v0.0.6 git.milar.in/nyaanime/model v0.0.0-20221008104642-466e1111ddea + git.milar.in/nyaanime/parsers v0.0.0-20221207192513-e7bce7c418d8 ) -require git.milar.in/milarin/anilist v1.5.0 // indirect +require gopkg.in/vansante/go-ffprobe.v2 v2.1.1 // indirect diff --git a/go.sum b/go.sum index 763cd13..35bccd8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +git.milar.in/milarin/adverr v0.2.1 h1:eyXFGC+Ui/kcNt2+NqP3HiAplwxzqeNr9DfitsUb3c4= +git.milar.in/milarin/adverr v0.2.1/go.mod h1:wwfglcey4R3vqjNL/d8mbnvFJGzETRXzAEolIHZY32w= git.milar.in/milarin/anilist v1.5.0 h1:fSiAXY/topNk4ISEp2QtcG9HHKLJfMc8w05iqc+Paf0= git.milar.in/milarin/anilist v1.5.0/go.mod h1:8PTHXFMA45JpfRFIpcdrKwDHue8fbT/wwV1BuHFn6c0= git.milar.in/milarin/envvars/v2 v2.0.0 h1:DWRQCWaHqzDD8NGpSgv5tYLuF9A/dVFPAtTvz3oiIqE= @@ -8,3 +10,7 @@ git.milar.in/milarin/slices v0.0.6 h1:AQoSarZ58WHYol9c6woWJSe8wFpPC2RC4cvIlZpfg9 git.milar.in/milarin/slices v0.0.6/go.mod h1:NOr53AOeur/qscu/FBj3lsFR262PNYBccLYSTCAXRk4= git.milar.in/nyaanime/model v0.0.0-20221008104642-466e1111ddea h1:iBwxI3vZ+Hix/5HHB3k9f9/R0nkwR0EvVJ3o5RJEKP4= git.milar.in/nyaanime/model v0.0.0-20221008104642-466e1111ddea/go.mod h1:kPWLDvFrhc1Uf77gxsBOxNeJ5JTVF2HhVs1IdVcw0tg= +git.milar.in/nyaanime/parsers v0.0.0-20221207192513-e7bce7c418d8 h1:vb7jasvTdan0E8VY5snnRj1Xe+60NA7Lpn+GSYE6pW0= +git.milar.in/nyaanime/parsers v0.0.0-20221207192513-e7bce7c418d8/go.mod h1:GG4vtUIfxopZc/+Y8OAa//vWJw/m6aeoGN7fw6SLiEM= +gopkg.in/vansante/go-ffprobe.v2 v2.1.1 h1:DIh5fMn+tlBvG7pXyUZdemVmLdERnf2xX6XOFF+0BBU= +gopkg.in/vansante/go-ffprobe.v2 v2.1.1/go.mod h1:qF0AlAjk7Nqzqf3y333Ly+KxN3cKF2JqA3JT5ZheUGE=