refactor(wildcard): optimize and add caching (#1634)

* fix(wildcard): avoid excessive allocations every loop

* are you going to Scarborough Fair?

* ruby ruby ruby ruby

* ride on, little murphy

* shirley?

* to the moon

* reggie are you there?

* code 99

* my doctorate is in Art History

* helps to be consistent

* tidy

* slow and steady gets the clam

* oysters were better anyway

* DIAL TONE
This commit is contained in:
Kyle Sanderson 2024-09-02 02:18:14 -07:00 committed by GitHub
parent bc0f4cc055
commit 982f7ddf68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 177 additions and 60 deletions

View file

@ -112,6 +112,20 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryPar
return releases, nextCursor, total, nil
}
var reservedSearch = map[string]*regexp.Regexp{
"r.title": regexp.MustCompile(`(?i)(?:` + `title` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.release_group": regexp.MustCompile(`(?i)(?:` + `release_group` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.category": regexp.MustCompile(`(?i)(?:` + `category` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.season": regexp.MustCompile(`(?i)(?:` + `season` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.episode": regexp.MustCompile(`(?i)(?:` + `episode` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.year": regexp.MustCompile(`(?i)(?:` + `year` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.resolution": regexp.MustCompile(`(?i)(?:` + `resolution` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.source": regexp.MustCompile(`(?i)(?:` + `source` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.codec": regexp.MustCompile(`(?i)(?:` + `codec` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.hdr": regexp.MustCompile(`(?i)(?:` + `hdr` + `:)(?P<value>'.*?'|".*?"|\S+)`),
"r.filter": regexp.MustCompile(`(?i)(?:` + `filter` + `:)(?P<value>'.*?'|".*?"|\S+)`),
}
func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain.ReleaseQueryParams) ([]*domain.Release, int64, int64, error) {
whereQueryBuilder := sq.And{}
if params.Cursor > 0 {
@ -119,27 +133,12 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
}
if params.Search != "" {
reserved := map[string]string{
"title": "r.title",
"group": "r.release_group",
"category": "r.category",
"season": "r.season",
"episode": "r.episode",
"year": "r.year",
"resolution": "r.resolution",
"source": "r.source",
"codec": "r.codec",
"hdr": "r.hdr",
"filter": "r.filter",
}
search := strings.TrimSpace(params.Search)
for k, v := range reserved {
r := regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s:)(?P<value>'.*?'|".*?"|\S+)`, k))
if reskey := r.FindAllStringSubmatch(search, -1); len(reskey) != 0 {
for dbField, regex := range reservedSearch {
if reskey := regex.FindAllStringSubmatch(search, -1); len(reskey) != 0 {
filter := sq.Or{}
for _, found := range reskey {
filter = append(filter, repo.db.ILike(v, strings.ReplaceAll(strings.Trim(strings.Trim(found[1], `"`), `'`), ".", "_")+"%"))
filter = append(filter, repo.db.ILike(dbField, strings.ReplaceAll(strings.Trim(strings.Trim(found[1], `"`), `'`), ".", "_")+"%"))
}
if len(filter) == 0 {
@ -147,7 +146,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
}
whereQueryBuilder = append(whereQueryBuilder, filter)
search = strings.TrimSpace(r.ReplaceAllLiteralString(search, ""))
search = strings.TrimSpace(regex.ReplaceAllLiteralString(search, ""))
}
}

View file

@ -7,12 +7,12 @@ import (
"context"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
"github.com/autobrr/autobrr/pkg/errors"
"github.com/autobrr/autobrr/pkg/regexcache"
"github.com/autobrr/autobrr/pkg/sanitize"
"github.com/autobrr/autobrr/pkg/wildcard"
@ -774,7 +774,7 @@ func matchRegex(tag string, filterList string) bool {
if filter == "" {
continue
}
re, err := regexp.Compile(`(?i)(?:` + filter + `)`)
re, err := regexcache.Compile(`(?i)(?:` + filter + `)`)
if err != nil {
return false
}

View file

@ -205,6 +205,8 @@ func (p IRCParserOrpheus) replaceSeparator(s string) string {
return strings.ReplaceAll(s, "", "-")
}
var lastDecimalTag = regexp.MustCompile(`^\d{1,2}$|^100$`)
func (p IRCParserOrpheus) Parse(rls *Release, vars map[string]string) error {
// OPS uses en-dashes as separators, which causes moistari/rls to not parse the torrentName properly,
// we replace the en-dashes with hyphens here
@ -219,7 +221,7 @@ func (p IRCParserOrpheus) Parse(rls *Release, vars map[string]string) error {
// Check and replace the last tag if it's a number between 0 and 100
if len(splittedTags) > 0 {
lastTag := splittedTags[len(splittedTags)-1]
match, _ := regexp.MatchString(`^\d{1,2}$|^100$`, lastTag)
match := lastDecimalTag.MatchString(lastTag)
if match {
splittedTags[len(splittedTags)-1] = lastTag + "%"
}

View file

@ -7,8 +7,6 @@ import (
"fmt"
"regexp"
"strconv"
"github.com/autobrr/autobrr/pkg/errors"
)
var types map[string][]*TagInfo
@ -261,13 +259,9 @@ func init() {
// language `(?i)\b((DK|DKSUBS|DANiSH|DUTCH|NL|NLSUBBED|ENG|FI|FLEMiSH|FiNNiSH|DE|FRENCH|GERMAN|HE|HEBREW|HebSub|HiNDi|iCELANDiC|KOR|MULTi|MULTiSUBS|NORWEGiAN|NO|NORDiC|PL|PO|POLiSH|PLDUB|RO|ROMANiAN|RUS|SPANiSH|SE|SWEDiSH|SWESUB||))\b`)
// websites `(?i)\b((AMBC|AS|AMZN|AMC|ANPL|ATVP|iP|CORE|BCORE|CMOR|CN|CBC|CBS|CMAX|CNBC|CC|CRIT|CR|CSPN|CW|DAZN|DCU|DISC|DSCP|DSNY|DSNP|DPLY|ESPN|FOX|FUNI|PLAY|HBO|HMAX|HIST|HS|HOTSTAR|HULU|iT|MNBC|MTV|NATG|NBC|NF|NICK|NRK|PMNT|PMNP|PCOK|PBS|PBSK|PSN|QIBI|SBS|SHO|STAN|STZ|SVT|SYFY|TLC|TRVL|TUBI|TV3|TV4|TVL|VH1|VICE|VMEO|UFC|USAN|VIAP|VIAPLAY|VL|WWEN|XBOX|YHOO|YT|RED))\b`)
for s, infos := range types {
for _, infos := range types {
for _, info := range infos {
var err error
//if info.re, err = regexp.Compile(`(?i)^(?:` + info.RE() + `)$`); err != nil {
if info.re, err = regexp.Compile(`(?i)(?:` + info.RE() + `)`); err != nil {
errors.Wrap(err, "tag %q has invalid regexp %q\n", s, info.re)
}
info.re = regexp.MustCompile(`(?i)(?:` + info.RE() + `)`)
}
}
}

View file

@ -2,8 +2,8 @@ package indexer
import (
"errors"
"regexp"
"github.com/autobrr/autobrr/pkg/regexcache"
"github.com/rs/zerolog"
)
@ -12,7 +12,7 @@ type Logger interface {
}
func regExMatch(pattern string, value string) ([]string, error) {
rxp, err := regexp.Compile(pattern)
rxp, err := regexcache.Compile(pattern)
if err != nil {
return nil, err
}
@ -54,7 +54,7 @@ func parseExtract(logger Logger, pattern string, vars []string, tmpVars map[stri
}
func parseMatchRegexp(pattern string, tmpVars map[string]string, line string, ignore bool) (bool, error) {
var re = regexp.MustCompile(`(?mi)` + pattern)
var re = regexcache.MustCompile(`(?mi)` + pattern)
groupNames := re.SubexpNames()
for _, match := range re.FindAllStringSubmatch(line, -1) {

View file

@ -37,9 +37,10 @@ func (s *lunaSeaSender) Name() string {
return "lunasea"
}
var lunaWebhook = regexp.MustCompile(`/(radarr|sonarr|lidarr|tautulli|overseerr)/`)
func (s *lunaSeaSender) rewriteWebhookURL(url string) string {
re := regexp.MustCompile(`/(radarr|sonarr|lidarr|tautulli|overseerr)/`)
return re.ReplaceAllString(url, "/custom/")
return lunaWebhook.ReplaceAllString(url, "/custom/")
} // `custom` is not mentioned in their docs, so I thought this would be a good idea to add to avoid user errors
func NewLunaSeaSender(log zerolog.Logger, settings domain.Notification) domain.NotificationSender {