Fix directory mapping

This commit is contained in:
Ben Sarmiento
2023-10-25 17:59:32 +02:00
parent 800401729a
commit 9cffb9fc86
6 changed files with 112 additions and 42 deletions

View File

@@ -13,6 +13,7 @@ directories:
# Configuration for TV shows # Configuration for TV shows
shows: shows:
group: media # directories on different groups have duplicates of the same torrent group: media # directories on different groups have duplicates of the same torrent
group_order: 1
filters: filters:
- regex: /season[\s\.]?\d/i # Capture torrent names with the term 'season' in any case - regex: /season[\s\.]?\d/i # Capture torrent names with the term 'season' in any case
- regex: /saison[\s\.]?\d/i # For non-English namings - regex: /saison[\s\.]?\d/i # For non-English namings
@@ -24,7 +25,8 @@ directories:
# Configuration for movies # Configuration for movies
movies: movies:
group: media # because movies and shows are in the same group, and shows come first before movies, all torrents that doesn't fall into shows will fall into movies group: media # because movies and shows are in the same group,
group_order: 2 # and shows has a lower group_order number than movies, all torrents that doesn't fall into shows will fall into movies
filters: filters:
- regex: /.*/ # you cannot leave a directory without filters because it will not have any torrents in it - regex: /.*/ # you cannot leave a directory without filters because it will not have any torrents in it

View File

@@ -16,7 +16,7 @@ type ConfigInterface interface {
EnableRepair() bool EnableRepair() bool
GetPort() string GetPort() string
GetDirectories() []string GetDirectories() []string
MeetsConditions(directory, fileID, fileName string) bool MeetsConditions(directory, torrentID, torrentName string, fileNames []string) bool
} }
func LoadZurgConfig(filename string) (ConfigInterface, error) { func LoadZurgConfig(filename string) (ConfigInterface, error) {

View File

@@ -2,6 +2,7 @@ package config
import ( import (
"regexp" "regexp"
"sort"
"strings" "strings"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -56,25 +57,38 @@ func (z *ZurgConfigV1) GetDirectories() []string {
func (z *ZurgConfigV1) GetGroupMap() map[string][]string { func (z *ZurgConfigV1) GetGroupMap() map[string][]string {
var groupMap = make(map[string][]string) var groupMap = make(map[string][]string)
var groupOrderMap = make(map[string]int) // To store GroupOrder for each group
// Populate the groupMap and groupOrderMap
for directory, val := range z.Directories { for directory, val := range z.Directories {
groupMap[val.Group] = append(groupMap[val.Group], directory) groupMap[val.Group] = append(groupMap[val.Group], directory)
groupOrderMap[val.Group] = val.GroupOrder
} }
// Sort the slice based on GroupOrder
for group, dirs := range groupMap {
sort.Slice(dirs, func(i, j int) bool {
return groupOrderMap[dirs[i]] < groupOrderMap[dirs[j]]
})
groupMap[group] = dirs
}
return groupMap return groupMap
} }
func (z *ZurgConfigV1) MeetsConditions(directory, fileID, torrentName string) bool { func (z *ZurgConfigV1) MeetsConditions(directory, torrentID, torrentName string, fileNames []string) bool {
if _, ok := z.Directories[directory]; !ok { if _, ok := z.Directories[directory]; !ok {
return false return false
} }
for _, filter := range z.Directories[directory].Filters { for _, filter := range z.Directories[directory].Filters {
if z.matchFilter(fileID, torrentName, filter) { if z.matchFilter(torrentID, torrentName, fileNames, filter) {
return true return true
} }
} }
return false return false
} }
func (z *ZurgConfigV1) matchFilter(fileID, torrentName string, filter *FilterConditionsV1) bool { func (z *ZurgConfigV1) matchFilter(fileID, torrentName string, fileNames []string, filter *FilterConditionsV1) bool {
if filter.ID != "" && fileID == filter.ID { if filter.ID != "" && fileID == filter.ID {
return true return true
} }
@@ -99,7 +113,7 @@ func (z *ZurgConfigV1) matchFilter(fileID, torrentName string, filter *FilterCon
if len(filter.And) > 0 { if len(filter.And) > 0 {
andResult := true andResult := true
for _, andFilter := range filter.And { for _, andFilter := range filter.And {
andResult = andResult && z.matchFilter(fileID, torrentName, andFilter) andResult = andResult && z.matchFilter(fileID, torrentName, fileNames, andFilter)
if !andResult { if !andResult {
return false return false
} }
@@ -108,7 +122,29 @@ func (z *ZurgConfigV1) matchFilter(fileID, torrentName string, filter *FilterCon
} }
if len(filter.Or) > 0 { if len(filter.Or) > 0 {
for _, orFilter := range filter.Or { for _, orFilter := range filter.Or {
if z.matchFilter(fileID, torrentName, orFilter) { if z.matchFilter(fileID, torrentName, fileNames, orFilter) {
return true
}
}
}
if filter.FileInsideRegexStr != "" {
for _, filename := range fileNames {
regex := compilePattern(filter.FileInsideRegexStr)
if regex.MatchString(filename) {
return true
}
}
}
if filter.FileInsideContains != "" {
for _, filename := range fileNames {
if strings.Contains(strings.ToLower(filename), strings.ToLower(filter.FileInsideContains)) {
return true
}
}
}
if filter.FileInsideContainsStrict != "" {
for _, filename := range fileNames {
if strings.Contains(filename, filter.FileInsideContainsStrict) {
return true return true
} }
} }

View File

@@ -5,17 +5,23 @@ type ZurgConfigV1 struct {
Directories map[string]*DirectoryFilterConditionsV1 `yaml:"directories"` Directories map[string]*DirectoryFilterConditionsV1 `yaml:"directories"`
} }
type DirectoryFilterConditionsV1 struct { type DirectoryFilterConditionsV1 struct {
Group string `yaml:"group"` GroupOrder int `yaml:"group_order"`
Filters []*FilterConditionsV1 `yaml:"filters"` Group string `yaml:"group"`
Filters []*FilterConditionsV1 `yaml:"filters"`
} }
type FilterConditionsV1 struct { type FilterConditionsV1 struct {
RegexStr string `yaml:"regex"` ID string `yaml:"id"`
Contains string `yaml:"contains"` RegexStr string `yaml:"regex"`
ContainsStrict string `yaml:"contains_strict"` Contains string `yaml:"contains"`
NotContains string `yaml:"not_contains"` ContainsStrict string `yaml:"contains_strict"`
NotContainsStrict string `yaml:"not_contains_strict"` NotContains string `yaml:"not_contains"`
ID string `yaml:"id"` NotContainsStrict string `yaml:"not_contains_strict"`
And []*FilterConditionsV1 `yaml:"and"`
Or []*FilterConditionsV1 `yaml:"or"` And []*FilterConditionsV1 `yaml:"and"`
Or []*FilterConditionsV1 `yaml:"or"`
FileInsideRegexStr string `yaml:"any_file_inside_regex"`
FileInsideContains string `yaml:"any_file_inside_contains"`
FileInsideContainsStrict string `yaml:"any_file_inside_contains_strict"`
} }

View File

@@ -16,13 +16,15 @@ import (
) )
type TorrentManager struct { type TorrentManager struct {
requiredVersion string requiredVersion string
torrents []Torrent torrents []Torrent
inProgress []string inProgress []string
checksum string checksum string
config config.ConfigInterface config config.ConfigInterface
cache *expirable.LRU[string, string] cache *expirable.LRU[string, string]
workerPool chan bool workerPool chan bool
TorrentDirectoriesMap map[string][]string
processedTorrents map[string]bool
} }
// NewTorrentManager creates a new torrent manager // NewTorrentManager creates a new torrent manager
@@ -30,10 +32,12 @@ type TorrentManager struct {
// and store them in-memory // and store them in-memory
func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string]) *TorrentManager { func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string]) *TorrentManager {
t := &TorrentManager{ t := &TorrentManager{
requiredVersion: "24.10.2023", requiredVersion: "24.10.2023",
config: config, config: config,
cache: cache, cache: cache,
workerPool: make(chan bool, config.GetNumOfWorkers()), workerPool: make(chan bool, config.GetNumOfWorkers()),
TorrentDirectoriesMap: make(map[string][]string),
processedTorrents: make(map[string]bool),
} }
// Initialize torrents for the first time // Initialize torrents for the first time
@@ -85,7 +89,7 @@ func (t *TorrentManager) repairAll(wg *sync.WaitGroup) {
func (t *TorrentManager) GetByDirectory(directory string) []Torrent { func (t *TorrentManager) GetByDirectory(directory string) []Torrent {
var torrents []Torrent var torrents []Torrent
for i := range t.torrents { for i := range t.torrents {
for _, dir := range t.torrents[i].Directories { for _, dir := range t.TorrentDirectoriesMap[t.torrents[i].Name] {
if dir == directory { if dir == directory {
torrents = append(torrents, t.torrents[i]) torrents = append(torrents, t.torrents[i])
} }
@@ -567,35 +571,58 @@ func (t *TorrentManager) repair(torrentID string, selectedFiles []File, tryReins
} }
func (t *TorrentManager) mapToDirectories() { func (t *TorrentManager) mapToDirectories() {
// Map to directories // Map torrents to directories
version := t.config.GetVersion() switch t.config.GetVersion() {
if version == "v1" { case "v1":
configV1 := t.config.(*config.ZurgConfigV1) configV1 := t.config.(*config.ZurgConfigV1)
groupMap := configV1.GetGroupMap() groupMap := configV1.GetGroupMap()
// for every group, iterate over every torrent
// and then sprinkle/distribute the torrents to the directories of the group
for group, directories := range groupMap { for group, directories := range groupMap {
log.Printf("Processing directory group: %s\n", group) log.Printf("Processing directory group '%s', sequence: %s\n", group, strings.Join(directories, " > "))
var directoryMap = make(map[string]int) counter := make(map[string]int)
for i := range t.torrents { for i := range t.torrents {
// don't process torrents that are already mapped if it is not the first run
if _, exists := t.processedTorrents[t.torrents[i].ID]; exists {
continue
}
for _, directory := range directories { for _, directory := range directories {
if configV1.MeetsConditions(directory, t.torrents[i].ID, t.torrents[i].Name) { var filenames []string
// append to t.torrents[i].Directories if not yet there for _, file := range t.torrents[i].Files {
filenames = append(filenames, file.Path)
}
if configV1.MeetsConditions(directory, t.torrents[i].ID, t.torrents[i].Name, filenames) {
found := false found := false
for _, dir := range t.torrents[i].Directories { for _, dir := range t.TorrentDirectoriesMap[t.torrents[i].Name] {
if dir == directory { if dir == directory {
found = true found = true
break break
} }
} }
if !found { if !found {
t.torrents[i].Directories = append(t.torrents[i].Directories, directory) counter[directory]++
t.TorrentDirectoriesMap[t.torrents[i].Name] = append(t.TorrentDirectoriesMap[t.torrents[i].Name], directory)
break
} }
directoryMap[directory]++
break
} }
} }
} }
log.Printf("Directory group: %v\n", directoryMap) sum := 0
for _, count := range counter {
sum += count
}
if sum > 0 {
log.Printf("Directory group processed: %s %v %d\n", group, counter, sum)
} else {
log.Println("No new additions to directory group", group)
}
} }
default:
log.Println("Unknown config version")
}
for _, torrent := range t.torrents {
t.processedTorrents[torrent.ID] = true
} }
log.Println("Finished mapping to directories") log.Println("Finished mapping to directories")
} }

View File

@@ -5,7 +5,6 @@ import "github.com/debridmediamanager.com/zurg/pkg/realdebrid"
type Torrent struct { type Torrent struct {
Version string Version string
realdebrid.Torrent realdebrid.Torrent
Directories []string
SelectedFiles []File SelectedFiles []File
ForRepair bool ForRepair bool
} }