Detect arithmetic progression

This commit is contained in:
Ben Sarmiento
2023-11-21 18:16:37 +01:00
parent a288f08ff7
commit 1995a86f29
5 changed files with 128 additions and 22 deletions

View File

@@ -4,8 +4,10 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"sort" "sort"
"strconv"
"strings" "strings"
"github.com/debridmediamanager.com/zurg/pkg/utils"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -88,13 +90,23 @@ func (z *ZurgConfigV1) matchFilter(torrentName string, torrentIDs, fileNames []s
if filter.RegexStr != "" { if filter.RegexStr != "" {
regex, err := compilePattern(filter.RegexStr) regex, err := compilePattern(filter.RegexStr)
if err != nil { if err != nil {
z.log.Errorf("Failed to compile regex: %v", err) z.log.Errorf("Failed to compile regex %s error: %v", filter.RegexStr, err)
return false return false
} }
if regex.MatchString(torrentName) { if regex.MatchString(torrentName) {
return true return true
} }
} }
if filter.NotRegexStr != "" {
regex, err := compilePattern(filter.NotRegexStr)
if err != nil {
z.log.Errorf("Failed to compile not_regex %s error: %v", filter.NotRegexStr, err)
return false
}
if !regex.MatchString(torrentName) {
return true
}
}
if filter.ContainsStrict != "" && strings.Contains(torrentName, filter.ContainsStrict) { if filter.ContainsStrict != "" && strings.Contains(torrentName, filter.ContainsStrict) {
return true return true
} }
@@ -127,7 +139,7 @@ func (z *ZurgConfigV1) matchFilter(torrentName string, torrentIDs, fileNames []s
if filter.FileInsideRegexStr != "" { if filter.FileInsideRegexStr != "" {
regex, err := compilePattern(filter.FileInsideRegexStr) regex, err := compilePattern(filter.FileInsideRegexStr)
if err != nil { if err != nil {
z.log.Errorf("Failed to compile regex: %v", err) z.log.Errorf("Failed to compile any_file_inside_regex %s error: %v", filter.FileInsideRegexStr, err)
return false return false
} }
for _, filename := range fileNames { for _, filename := range fileNames {
@@ -136,12 +148,34 @@ func (z *ZurgConfigV1) matchFilter(torrentName string, torrentIDs, fileNames []s
} }
} }
} }
if filter.FileInsideNotRegexStr != "" {
regex, err := compilePattern(filter.FileInsideNotRegexStr)
if err != nil {
z.log.Errorf("Failed to compile any_file_inside_not_regex %s error: %v", filter.FileInsideNotRegexStr, err)
return false
}
for _, filename := range fileNames {
if !regex.MatchString(filename) {
return true
}
}
return false
}
if filter.FileInsideContains != "" { if filter.FileInsideContains != "" {
for _, filename := range fileNames { for _, filename := range fileNames {
if strings.Contains(strings.ToLower(filename), strings.ToLower(filter.FileInsideContains)) { if strings.Contains(strings.ToLower(filename), strings.ToLower(filter.FileInsideContains)) {
return true return true
} }
} }
return false
}
if filter.FileInsideNotContains != "" {
for _, filename := range fileNames {
if !strings.Contains(strings.ToLower(filename), strings.ToLower(filter.FileInsideNotContains)) {
return true
}
}
return false
} }
if filter.FileInsideContainsStrict != "" { if filter.FileInsideContainsStrict != "" {
for _, filename := range fileNames { for _, filename := range fileNames {
@@ -149,6 +183,24 @@ func (z *ZurgConfigV1) matchFilter(torrentName string, torrentIDs, fileNames []s
return true return true
} }
} }
return false
}
if filter.FileInsideNotContainsStrict != "" {
for _, filename := range fileNames {
if !strings.Contains(filename, filter.FileInsideNotContainsStrict) {
return true
}
}
return false
}
if filter.HasEpisodes {
regex := regexp.MustCompile(`(?i)s\d\de\d\d`)
for _, filename := range fileNames {
if regex.MatchString(filename) {
return true
}
}
return checkArithmeticSequenceInFilenames(fileNames)
} }
return false return false
} }
@@ -188,3 +240,54 @@ func compilePattern(pattern string) (*regexp.Regexp, error) {
return regexp.Compile(finalPattern) return regexp.Compile(finalPattern)
} }
func hasIncreasingSequence(arr []int) bool {
if len(arr) < 3 {
return false
}
for i := 0; i < len(arr)-2; i++ {
if arr[i] < arr[i+1] && arr[i+1] < arr[i+2] {
return true
}
}
return false
}
func checkArithmeticSequenceInFilenames(files []string) bool {
if len(files) < 3 {
return false
}
r := regexp.MustCompile(`\d+`)
for _, file := range files {
if !utils.IsStreamable(file) {
continue
}
matches := r.FindAllStringIndex(file, -1)
for _, match := range matches {
numSet := make(map[int]struct{})
for _, file := range files {
if !utils.IsStreamable(file) {
continue
}
if match[0] >= 0 && match[1] <= len(file) {
num, err := strconv.Atoi(file[match[0]:match[1]])
if err == nil {
numSet[num] = struct{}{}
}
} else {
// out of bounds, ignore
continue
}
}
numList := make([]int, 0, len(numSet))
for num := range numSet {
numList = append(numList, num)
}
sort.Ints(numList)
if hasIncreasingSequence(numList) {
return true
}
}
}
return false
}

View File

@@ -18,13 +18,19 @@ type FilterConditionsV1 struct {
RegexStr string `yaml:"regex"` RegexStr string `yaml:"regex"`
Contains string `yaml:"contains"` Contains string `yaml:"contains"`
ContainsStrict string `yaml:"contains_strict"` ContainsStrict string `yaml:"contains_strict"`
NotRegexStr string `yaml:"not_regex"`
NotContains string `yaml:"not_contains"` NotContains string `yaml:"not_contains"`
NotContainsStrict string `yaml:"not_contains_strict"` NotContainsStrict string `yaml:"not_contains_strict"`
And []*FilterConditionsV1 `yaml:"and"` And []*FilterConditionsV1 `yaml:"and"`
Or []*FilterConditionsV1 `yaml:"or"` Or []*FilterConditionsV1 `yaml:"or"`
FileInsideRegexStr string `yaml:"any_file_inside_regex"` FileInsideRegexStr string `yaml:"any_file_inside_regex"`
FileInsideContains string `yaml:"any_file_inside_contains"` FileInsideContains string `yaml:"any_file_inside_contains"`
FileInsideContainsStrict string `yaml:"any_file_inside_contains_strict"` FileInsideContainsStrict string `yaml:"any_file_inside_contains_strict"`
FileInsideNotRegexStr string `yaml:"any_file_inside_not_regex"`
FileInsideNotContains string `yaml:"any_file_inside_not_contains"`
FileInsideNotContainsStrict string `yaml:"any_file_inside_not_contains_strict"`
HasEpisodes bool `yaml:"has_episodes"`
} }

View File

@@ -15,6 +15,7 @@ import (
"github.com/debridmediamanager.com/zurg/internal/config" "github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/pkg/logutil" "github.com/debridmediamanager.com/zurg/pkg/logutil"
"github.com/debridmediamanager.com/zurg/pkg/realdebrid" "github.com/debridmediamanager.com/zurg/pkg/realdebrid"
"github.com/debridmediamanager.com/zurg/pkg/utils"
cmap "github.com/orcaman/concurrent-map/v2" cmap "github.com/orcaman/concurrent-map/v2"
"github.com/panjf2000/ants/v2" "github.com/panjf2000/ants/v2"
"go.uber.org/zap" "go.uber.org/zap"
@@ -96,9 +97,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, p
} }
} }
anotherCt := 0
allTorrents.IterCb(func(accessKey string, torrent *Torrent) { allTorrents.IterCb(func(accessKey string, torrent *Torrent) {
anotherCt++
// get IDs // get IDs
var torrentIDs []string var torrentIDs []string
for _, instance := range torrent.Instances { for _, instance := range torrent.Instances {
@@ -293,11 +292,7 @@ func (t *TorrentManager) startRefreshJob() {
} }
// get filenames // get filenames
var filenames []string filenames := torrent.SelectedFiles.Keys()
torrent.SelectedFiles.IterCb(func(_ string, file *File) {
filenames = append(filenames, file.Path)
})
// Map torrents to directories // Map torrents to directories
switch t.cfg.GetVersion() { switch t.cfg.GetVersion() {
case "v1": case "v1":
@@ -593,7 +588,7 @@ func (t *TorrentManager) Repair(accessKey string) {
var links []string var links []string
streamableCount := 0 streamableCount := 0
torrent.SelectedFiles.IterCb(func(_ string, file *File) { torrent.SelectedFiles.IterCb(func(_ string, file *File) {
if isStreamable(file.Path) { if utils.IsStreamable(file.Path) {
streamableCount++ streamableCount++
} }
fileCopy := &File{ fileCopy := &File{

View File

@@ -3,7 +3,6 @@ package torrent
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
) )
func getFileIDs(files []File) []string { func getFileIDs(files []File) []string {
@@ -16,14 +15,6 @@ func getFileIDs(files []File) []string {
return fileIDs return fileIDs
} }
func isStreamable(filePath string) bool {
return strings.HasSuffix(filePath, ".mkv") ||
strings.HasSuffix(filePath, ".mp4") ||
strings.HasSuffix(filePath, ".avi") ||
strings.HasSuffix(filePath, ".wmv") ||
strings.HasSuffix(filePath, ".m4v")
}
func ensureDir(dirName string) error { func ensureDir(dirName string) error {
if _, err := os.Stat(dirName); os.IsNotExist(err) { if _, err := os.Stat(dirName); os.IsNotExist(err) {
err := os.Mkdir(dirName, 0755) err := os.Mkdir(dirName, 0755)

11
pkg/utils/streamable.go Normal file
View File

@@ -0,0 +1,11 @@
package utils
import "strings"
func IsStreamable(filePath string) bool {
return strings.HasSuffix(filePath, ".mkv") ||
strings.HasSuffix(filePath, ".mp4") ||
strings.HasSuffix(filePath, ".avi") ||
strings.HasSuffix(filePath, ".wmv") ||
strings.HasSuffix(filePath, ".m4v")
}