- Add support for merging files from torrents with the same name

- Add infohash as a folder naming
- Other minor bugs
This commit is contained in:
Mukhtar Akere
2025-04-22 19:32:55 +01:00
parent 2139d3a175
commit fb39e92a88
5 changed files with 45 additions and 13 deletions

View File

@@ -54,5 +54,8 @@ func IsMediaFile(path string) bool {
} }
func IsSampleFile(path string) bool { func IsSampleFile(path string) bool {
if strings.HasSuffix(strings.ToLower(path), "sample.mkv") {
return true
}
return RegexMatch(SAMPLEMATCH, path) return RegexMatch(SAMPLEMATCH, path)
} }

View File

@@ -17,6 +17,7 @@ import (
"os" "os"
path "path/filepath" path "path/filepath"
"strconv" "strconv"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -30,6 +31,7 @@ const (
WebDavUseFileNameNoExt WebDavFolderNaming = "filename_no_ext" WebDavUseFileNameNoExt WebDavFolderNaming = "filename_no_ext"
WebDavUseOriginalNameNoExt WebDavFolderNaming = "original_no_ext" WebDavUseOriginalNameNoExt WebDavFolderNaming = "original_no_ext"
WebDavUseID WebDavFolderNaming = "id" WebDavUseID WebDavFolderNaming = "id"
WebdavUseHash WebDavFolderNaming = "infohash"
) )
type PropfindResponse struct { type PropfindResponse struct {
@@ -396,6 +398,8 @@ func (c *Cache) GetTorrentFolder(torrent *types.Torrent) string {
return path.Clean(utils.RemoveExtension(torrent.OriginalFilename)) return path.Clean(utils.RemoveExtension(torrent.OriginalFilename))
case WebDavUseID: case WebDavUseID:
return torrent.Id return torrent.Id
case WebdavUseHash:
return strings.ToLower(torrent.InfoHash)
default: default:
return path.Clean(torrent.Filename) return path.Clean(torrent.Filename)
} }
@@ -404,13 +408,12 @@ func (c *Cache) GetTorrentFolder(torrent *types.Torrent) string {
func (c *Cache) setTorrent(t *CachedTorrent) { func (c *Cache) setTorrent(t *CachedTorrent) {
c.torrents.Store(t.Id, t) c.torrents.Store(t.Id, t)
torrentKey := c.GetTorrentFolder(t.Torrent) torrentKey := c.GetTorrentFolder(t.Torrent)
if o, ok := c.torrentsNames.Load(torrentKey); ok && o.Id != t.Id { if o, ok := c.torrentsNames.Load(torrentKey); ok {
// Save the most recent torrent // If another torrent with the same name exists, merge the files, if the same file exists,
if t.AddedOn.After(o.AddedOn) { // keep the one with the most recent added date
c.torrentsNames.Delete(torrentKey)
} else { mergedFiles := mergeFiles(t, o)
t = o t.Files = mergedFiles
}
} }
c.torrentsNames.Store(torrentKey, t) c.torrentsNames.Store(torrentKey, t)
c.SaveTorrent(t) c.SaveTorrent(t)
@@ -420,13 +423,10 @@ func (c *Cache) setTorrents(torrents map[string]*CachedTorrent) {
for _, t := range torrents { for _, t := range torrents {
c.torrents.Store(t.Id, t) c.torrents.Store(t.Id, t)
torrentKey := c.GetTorrentFolder(t.Torrent) torrentKey := c.GetTorrentFolder(t.Torrent)
if o, ok := c.torrentsNames.Load(torrentKey); ok && o.Id != t.Id { if o, ok := c.torrentsNames.Load(torrentKey); ok {
// Save the most recent torrent // Save the most recent torrent
if t.AddedOn.After(o.AddedOn) { mergedFiles := mergeFiles(t, o)
c.torrentsNames.Delete(torrentKey) t.Files = mergedFiles
} else {
t = o
}
} }
c.torrentsNames.Store(torrentKey, t) c.torrentsNames.Store(torrentKey, t)
} }

27
pkg/debrid/debrid/misc.go Normal file
View File

@@ -0,0 +1,27 @@
package debrid
import (
"github.com/sirrobot01/decypharr/pkg/debrid/types"
"sort"
)
// MergeFiles merges the files from multiple torrents into a single map.
// It uses the file name as the key and the file object as the value.
// This is useful for deduplicating files across multiple torrents.
// The order of the torrents is determined by the AddedOn time, with the earliest added torrent first.
// If a file with the same name exists in multiple torrents, the last one will be used.
func mergeFiles(torrents ...*CachedTorrent) map[string]types.File {
merged := make(map[string]types.File)
// order torrents by added time
sort.Slice(torrents, func(i, j int) bool {
return torrents[i].AddedOn.Before(torrents[j].AddedOn)
})
for _, torrent := range torrents {
for _, file := range torrent.Files {
merged[file.Name] = file
}
}
return merged
}

View File

@@ -77,6 +77,7 @@ func (t *Torrent) GetMountFolder(rClonePath string) (string, error) {
} }
type File struct { type File struct {
TorrentId string `json:"torrent_id"`
Id string `json:"id"` Id string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Size int64 `json:"size"` Size int64 `json:"size"`

View File

@@ -291,6 +291,7 @@
<option value="original">Original name</option> <option value="original">Original name</option>
<option value="original_no_ext">Original name with No Ext</option> <option value="original_no_ext">Original name with No Ext</option>
<option value="id">Use ID</option> <option value="id">Use ID</option>
<option value="infohash">Use Infohash</option>
</select> </select>
</div> </div>
<div class="col-md-3 mb-3"> <div class="col-md-3 mb-3">