Fix directory mapping
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user