From 2b0d13cadfd32b64e791917bdc3988cb9bac750d Mon Sep 17 00:00:00 2001 From: Timon Ringwald Date: Thu, 4 Aug 2022 15:44:33 +0200 Subject: [PATCH] features added --- errors.go | 9 +++ feature.go | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 +- go.sum | 4 +- 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 errors.go create mode 100644 feature.go diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..332f8cf --- /dev/null +++ b/errors.go @@ -0,0 +1,9 @@ +package model + +import "git.milar.in/milarin/adverr" + +var ( + ErrFeatureAlreadyCreated = adverr.NewErrTmpl("ErrFeatureAlreadyCreated", "duplicate feature: '%s'") + ErrFeatureWithoutValue = adverr.NewErrTmpl("ErrFeatureWithoutValue", "feature needs a value: '%s'") + ErrInvalidFeatureValue = adverr.NewErrTmpl("ErrInvalidFeatureValue", "feature needs a value of type %s") +) diff --git a/feature.go b/feature.go new file mode 100644 index 0000000..3125e27 --- /dev/null +++ b/feature.go @@ -0,0 +1,207 @@ +package model + +import ( + "fmt" + "strconv" + "strings" +) + +type Feature[T any] struct { + name string + value T + priority int + essential bool +} + +var ( + Feature1080p = &Feature[bool]{ + name: "1080p", + value: true, + } + Feature720p = &Feature[bool]{ + name: "720p", + value: true, + } + FeatureTrusted = &Feature[bool]{ + name: "trusted", + value: true, + } +) + +var ( + featureLangOther = Feature[string]{ + name: "lang", + value: "_", + } + featureSubOther = Feature[string]{ + name: "sub", + value: "_", + } +) + +func PrintAllFeatures() { + fmt.Printf("string features: %#v\n", stringFeatures) + fmt.Printf("bool features: %#v\n", boolFeatures) +} + +var ( + // string features are user-defined. 'primary key' is name and value + stringFeatures = []*Feature[string]{} + + // bool features are known at compile time. 'primary key' is value only + boolFeatures = []*Feature[bool]{Feature1080p, Feature720p, FeatureTrusted} +) + +func makeStringFeature(name, value string, priority int, essential bool) *Feature[string] { + for _, feature := range stringFeatures { + if feature.name == name && feature.value == value { + panic(ErrFeatureAlreadyCreated.New(fmt.Sprintf("%s:%s", name, value))) + } + } + + feature := &Feature[string]{ + name: name, + value: value, + priority: priority, + essential: essential, + } + + stringFeatures = append(stringFeatures, feature) + return feature +} + +func GetStringFeature(name, value string) *Feature[string] { + for _, feature := range stringFeatures { + if feature.name == name && feature.value == value { + return feature + } + } + + // lang and sub features have their special '_' value + if name == "lang" { + return makeStringFeature(name, value, featureLangOther.priority, featureLangOther.essential) + } else if name == "sub" { + return makeStringFeature(name, value, featureSubOther.priority, featureSubOther.essential) + } + + panic("TODO") +} + +func GetBoolFeature(name string, value bool) *Feature[bool] { + for _, feature := range boolFeatures { + if feature.name == name { + return feature + } + } + + panic("TODO") +} + +func ParseEssentialFeatures(essentialFeatureString string) { + featureSpecs := strings.Split(essentialFeatureString, ",") + + for _, featureSpec := range featureSpecs { + handleFeatureSpec(featureSpec, -1, true) + } +} + +func handleFeatureSpec(featureSpec string, priority int, essential bool) { + data := strings.Split(featureSpec, ":") + name := data[0] + + if name == "lang" || name == "sub" { + if len(data) < 2 { + panic(ErrFeatureWithoutValue.New(featureSpec)) + } + value := data[1] + + makeStringFeature(name, value, priority, essential) + return + } + + value := "" + if len(data) >= 2 { + value = data[1] + } + + var err error + + switch name { + + case "1080p": + { + Feature1080p.value, err = strconv.ParseBool(value) + if err != nil { + panic(ErrInvalidFeatureValue.New("bool")) + } + Feature1080p.priority = priority + Feature1080p.essential = essential + } + + case "720p": + { + Feature720p.value, err = strconv.ParseBool(value) + if err != nil { + panic(ErrInvalidFeatureValue.New("bool")) + } + Feature720p.priority = priority + Feature720p.essential = essential + } + + case "trusted": + { + FeatureTrusted.value, err = strconv.ParseBool(value) + if err != nil { + panic(ErrInvalidFeatureValue.New("bool")) + } + FeatureTrusted.priority = priority + FeatureTrusted.essential = essential + } + + } +} + +/* +examples for feature priorization: + +# if multiple torrents are available, the torrent with most features of this list will be prioritized. +# when a new torrent with more features is uploaded, it will replace the files of the old torrent. +# that ensures availability of latest episodes but highest preferred quality on the long run +# +# This list is ordered by the separator '|'. Features within the same '|' block (separated by comma) get same priority. +# the first '|' block is prioritized highest. +# +# '_' is a placeholder for all other features not directly mentioned in the list. +# It can be used for a default priority. If not default priority is given, it will be set to 0. +# +# This example basically means: +# torrents with japanese language have priority 3 +# torrents with english or german languages or subtitles in english or german have priority 2 +# torrents with any other languages or subtitles will have priority 1 +TORRENT_PRIORITIZED_FEATURES="sub:ja|lang:en,sub:en,lang:de,sub:de|lang:_,sub:_" + +# torrents without these features will never be downloaded ('_' features not supported)- +# +# essential features will be parsed before prioritized features. +# a feature cannot be both essential and prioritized. +# +# This example basically means: Only download torrents with japanese language and subtitles +TORRENT_ESSENTIAL_FEATURES="lang:ja,1080p" + +# complete feature list: +# "lang:": language (audio) +# "sub:": subtitles +# "1080p[:]": full hd resolution with optional bool flag +# "720p[:]": hd resolution +# "trusted[:]": trusted torrent uploader (highlighted in green on nyaa.si) + +TODO: add feature min-seeders: +TODO: add feature max-seeders: +TODO: add feature min-leechers: +TODO: add feature max-leechers: +TODO: add feature min-downloads: +TODO: add feature max-downloads: +TODO: add feature min-upload-time: +TODO: add feature max-upload-time: + +*/ diff --git a/go.mod b/go.mod index da45494..153402b 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module git.milar.in/animan/model go 1.18 -require git.milar.in/milarin/anilist v1.4.1 +require ( + git.milar.in/milarin/adverr v0.2.1 + git.milar.in/milarin/anilist v1.4.1 +) diff --git a/go.sum b/go.sum index cb2e815..ab76918 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ +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.4.1 h1:XxpKZ3CZiwKf7tUW2z+OMktWt/fLKMd8xAGPr+eodQE= -git.milar.in/milarin/anilist v1.4.1/go.mod h1:8PTHXFMA45JpfRFIpcdrKwDHue8fbT/wwV1BuHFn6c0= \ No newline at end of file +git.milar.in/milarin/anilist v1.4.1/go.mod h1:8PTHXFMA45JpfRFIpcdrKwDHue8fbT/wwV1BuHFn6c0=