wraps up duplicate names implementation

This commit is contained in:
Mukhtar Akere
2025-04-22 21:24:33 +01:00
parent fb39e92a88
commit 3cc8ad3cdc
9 changed files with 77 additions and 44 deletions

View File

@@ -27,6 +27,7 @@ DecyphArr includes several advanced features that extend its capabilities:
- [Repair Worker](repair-worker.md): Identifies and fixes issues with your media files - [Repair Worker](repair-worker.md): Identifies and fixes issues with your media files
- [WebDAV Server](webdav.md): Provides direct access to your Debrid files - [WebDAV Server](webdav.md): Provides direct access to your Debrid files
- [Using with Rclone](rclone.md): Mount the WebDAV server locally for easier access
## Supported Debrid Providers ## Supported Debrid Providers

View File

@@ -32,12 +32,11 @@ services:
image: cy01/blackhole:latest # or cy01/blackhole:beta image: cy01/blackhole:latest # or cy01/blackhole:beta
container_name: decypharr container_name: decypharr
ports: ports:
- "8282:8282" # qBittorrent - "8282:8282"
- "8181:8181" # Proxy
user: "1000:1000" user: "1000:1000"
volumes: volumes:
- /mnt/:/mnt - /mnt/:/mnt
- ./configs/:/app # config.json must be in this directory - ./config/:/app # config.json must be in this directory
environment: environment:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
@@ -65,7 +64,31 @@ Create a configuration file (see Configuration)
Run the binary: Run the binary:
```bash ```bash
chmod +x decypharr chmod +x decypharr
./decypharr --config /path/to/config ./decypharr --config /path/to/config/folder
``` ```
The config directory should contain your config.json file. The config directory should contain your config.json file.
## config.json
The `config.json` file is where you configure DecyphArr. You can find a sample configuration file in the `configs` directory of the repository.
```json
{
"debrids": [
{
"name": "realdebrid",
"api_key": "your_api_key_here",
"folder": "/mnt/remote/realdebrid/__all__/",
"use_webdav": true
}
],
"qbittorrent": {
"download_folder": "/mnt/symlinks/",
"categories": ["sonarr", "radarr"]
},
"use_auth": false,
"log_level": "info",
"port": "8282"
}
```

View File

@@ -122,7 +122,7 @@ func getAlldebridStatus(statusCode int) string {
} }
} }
func flattenFiles(files []MagnetFile, parentPath string, index *int) map[string]types.File { func flattenFiles(torrentId string, files []MagnetFile, parentPath string, index *int) map[string]types.File {
result := make(map[string]types.File) result := make(map[string]types.File)
cfg := config.Get() cfg := config.Get()
@@ -135,7 +135,7 @@ func flattenFiles(files []MagnetFile, parentPath string, index *int) map[string]
if f.Elements != nil { if f.Elements != nil {
// This is a folder, recurse into it // This is a folder, recurse into it
subFiles := flattenFiles(f.Elements, currentPath, index) subFiles := flattenFiles(torrentId, f.Elements, currentPath, index)
for k, v := range subFiles { for k, v := range subFiles {
if _, ok := result[k]; ok { if _, ok := result[k]; ok {
// File already exists, use path as key // File already exists, use path as key
@@ -162,11 +162,12 @@ func flattenFiles(files []MagnetFile, parentPath string, index *int) map[string]
*index++ *index++
file := types.File{ file := types.File{
Id: strconv.Itoa(*index), TorrentId: torrentId,
Name: fileName, Id: strconv.Itoa(*index),
Size: f.Size, Name: fileName,
Path: currentPath, Size: f.Size,
Link: f.Link, Path: currentPath,
Link: f.Link,
} }
result[file.Name] = file result[file.Name] = file
} }
@@ -203,7 +204,7 @@ func (ad *AllDebrid) UpdateTorrent(t *types.Torrent) error {
if status == "downloaded" { if status == "downloaded" {
t.Progress = 100 t.Progress = 100
index := -1 index := -1
files := flattenFiles(data.Files, "", &index) files := flattenFiles(t.Id, data.Files, "", &index)
t.Files = files t.Files = files
} else { } else {
t.Progress = float64(data.Downloaded) / float64(data.Size) * 100 t.Progress = float64(data.Downloaded) / float64(data.Size) * 100

View File

@@ -223,6 +223,7 @@ func (c *Cache) load() (map[string]*CachedTorrent, error) {
if len(ct.Files) != 0 { if len(ct.Files) != 0 {
// Check if all files are valid, if not, delete the file.json and remove from cache. // Check if all files are valid, if not, delete the file.json and remove from cache.
for _, f := range ct.Files { for _, f := range ct.Files {
f.TorrentId = ct.Id
if f.Link == "" { if f.Link == "" {
isComplete = false isComplete = false
break break

View File

@@ -134,7 +134,9 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
torrent, err = c.client.CheckStatus(torrent, true) torrent, err = c.client.CheckStatus(torrent, true)
if err != nil && torrent != nil { if err != nil && torrent != nil {
// Torrent is likely uncached, delete it // Torrent is likely uncached, delete it
_ = c.client.DeleteTorrent(torrent.Id) // Delete the newly added un-cached torrent if err := c.client.DeleteTorrent(torrent.Id); err != nil {
c.logger.Error().Err(err).Str("torrentId", torrent.Id).Msg("Failed to delete torrent")
} // Delete the newly added un-cached torrent
return ct, fmt.Errorf("failed to check status: %w", err) return ct, fmt.Errorf("failed to check status: %w", err)
} }
if torrent == nil { if torrent == nil {
@@ -153,7 +155,7 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
return ct, fmt.Errorf("failed to reinsert torrent: empty link") return ct, fmt.Errorf("failed to reinsert torrent: empty link")
} }
} }
// We can safely delete the old torrent here // We can safely delete the old torrent here
if oldID != "" { if oldID != "" {
if err := c.DeleteTorrent(oldID); err != nil { if err := c.DeleteTorrent(oldID); err != nil {

View File

@@ -137,10 +137,11 @@ func (dl *DebridLink) UpdateTorrent(t *types.Torrent) error {
continue continue
} }
file := types.File{ file := types.File{
Id: f.ID, TorrentId: t.Id,
Name: f.Name, Id: f.ID,
Size: f.Size, Name: f.Name,
Path: f.Name, Size: f.Size,
Path: f.Name,
DownloadLink: &types.DownloadLink{ DownloadLink: &types.DownloadLink{
Filename: f.Name, Filename: f.Name,
Link: f.DownloadURL, Link: f.DownloadURL,
@@ -189,11 +190,12 @@ func (dl *DebridLink) SubmitMagnet(t *types.Torrent) (*types.Torrent, error) {
t.Debrid = dl.Name t.Debrid = dl.Name
for _, f := range data.Files { for _, f := range data.Files {
file := types.File{ file := types.File{
Id: f.ID, TorrentId: t.Id,
Name: f.Name, Id: f.ID,
Size: f.Size, Name: f.Name,
Path: f.Name, Size: f.Size,
Link: f.DownloadURL, Path: f.Name,
Link: f.DownloadURL,
DownloadLink: &types.DownloadLink{ DownloadLink: &types.DownloadLink{
Filename: f.Name, Filename: f.Name,
Link: f.DownloadURL, Link: f.DownloadURL,
@@ -370,10 +372,11 @@ func (dl *DebridLink) getTorrents(page, perPage int) ([]*types.Torrent, error) {
continue continue
} }
file := types.File{ file := types.File{
Id: f.ID, TorrentId: torrent.Id,
Name: f.Name, Id: f.ID,
Size: f.Size, Name: f.Name,
Path: f.Name, Size: f.Size,
Path: f.Name,
DownloadLink: &types.DownloadLink{ DownloadLink: &types.DownloadLink{
Filename: f.Name, Filename: f.Name,
Link: f.DownloadURL, Link: f.DownloadURL,

View File

@@ -111,10 +111,11 @@ func getSelectedFiles(t *types.Torrent, data torrentInfo) map[string]types.File
if f.Selected == 1 { if f.Selected == 1 {
name := filepath.Base(f.Path) name := filepath.Base(f.Path)
file := types.File{ file := types.File{
Name: name, TorrentId: t.Id,
Path: name, Name: name,
Size: f.Bytes, Path: name,
Id: strconv.Itoa(f.ID), Size: f.Bytes,
Id: strconv.Itoa(f.ID),
} }
selectedFiles = append(selectedFiles, file) selectedFiles = append(selectedFiles, file)
} }
@@ -153,10 +154,11 @@ func getTorrentFiles(t *types.Torrent, data torrentInfo) map[string]types.File {
} }
file := types.File{ file := types.File{
Name: name, TorrentId: t.Id,
Path: name, Name: name,
Size: f.Bytes, Path: name,
Id: strconv.Itoa(f.ID), Size: f.Bytes,
Id: strconv.Itoa(f.ID),
} }
files[name] = file files[name] = file
idx++ idx++

View File

@@ -220,10 +220,11 @@ func (tb *Torbox) UpdateTorrent(t *types.Torrent) error {
continue continue
} }
file := types.File{ file := types.File{
Id: strconv.Itoa(f.Id), TorrentId: t.Id,
Name: fileName, Id: strconv.Itoa(f.Id),
Size: f.Size, Name: fileName,
Path: fileName, Size: f.Size,
Path: fileName,
} }
t.Files[fileName] = file t.Files[fileName] = file
} }

View File

@@ -183,9 +183,9 @@ func (h *Handler) OpenFile(ctx context.Context, name string, flag int, perm os.F
// Torrent file level // Torrent file level
filename := strings.Join(parts[2:], "/") filename := strings.Join(parts[2:], "/")
if file, ok := cachedTorrent.Files[filename]; ok { if file, ok := cachedTorrent.Files[filename]; ok {
fi := &File{ return &File{
cache: h.cache, cache: h.cache,
torrentId: cachedTorrent.Id, torrentId: file.TorrentId,
fileId: file.Id, fileId: file.Id,
isDir: false, isDir: false,
name: file.Name, name: file.Name,
@@ -193,8 +193,7 @@ func (h *Handler) OpenFile(ctx context.Context, name string, flag int, perm os.F
link: file.Link, link: file.Link,
metadataOnly: metadataOnly, metadataOnly: metadataOnly,
modTime: cachedTorrent.AddedOn, modTime: cachedTorrent.AddedOn,
} }, nil
return fi, nil
} }
} }