From ed87c2bbcc9ebefee18ea1f14dd9157eff248849 Mon Sep 17 00:00:00 2001 From: Ben Sarmiento Date: Wed, 10 Jan 2024 02:36:12 +0100 Subject: [PATCH] Access key computation without clearing data --- README.md | 12 +++--- config.example.yml | 79 +++++++++++++++++++++++++++++-------- internal/config/types.go | 6 +++ internal/dav/infuse.go | 2 +- internal/dav/listing.go | 6 +-- internal/dav/rename.go | 2 +- internal/http/listing.go | 2 +- internal/torrent/delete.go | 2 +- internal/torrent/manager.go | 26 ++++++++---- internal/torrent/refresh.go | 35 ++++++++-------- internal/torrent/repair.go | 48 +++++++++++----------- internal/torrent/types.go | 4 +- 12 files changed, 146 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 38732ce..0cbc142 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ # zurg -A self-hosted Real-Debrid webdav server written from scratch. Together with [rclone](https://rclone.org/) it can mount your Real-Debrid torrent library into your filesystem just like Dropbox. +A self-hosted Real-Debrid webdav server written from scratch. Together with [rclone](https://rclone.org/) it can mount your Real-Debrid torrent library into your file system like Dropbox. ## Download -### Latest version: v0.9.2-hotfix.4 +### Latest version: v0.9.3 -[Download the binary](https://github.com/debridmediamanager/zurg-testing/tree/main/releases/v0.9.2-hotfix.4) or use docker +[Download the binary](https://github.com/debridmediamanager/zurg-testing/tree/main/releases/v0.9.3) or use docker ```sh docker pull ghcr.io/debridmediamanager/zurg-testing:latest # or -docker pull ghcr.io/debridmediamanager/zurg-testing:v0.9.2-hotfix.4 +docker pull ghcr.io/debridmediamanager/zurg-testing:v0.9.3 ``` ## How to run zurg in 5 steps for Plex @@ -26,7 +26,7 @@ A webdav server is also exposed to your localhost via port `9999`. ## Why zurg? Why not X? -- Better performance than anything out there; changes in your library appear instantly (assuming Plex picks it up fast enough) +- Better performance than anything out there; changes in your library appear instantly ([assuming Plex picks it up fast enough](./plex_update.sh)) - You should be able to access every file even if the torrent names are the same so if you have a lot of these, you might notice that zurg will have more files compared to others (e.g. 2 torrents named "Simpsons" but have different seasons, zurg merges all contents in that directory) - You can configure a flexible directory structure in `config.yml`; you can select individual torrents that should appear on a directory by the ID you see in [DMM](https://debridmediamanager.com/). - If you've ever experienced Plex scanner being stuck on a file and thereby freezing Plex completely, it should not happen anymore because zurg does a comprehensive check if a torrent is dead or not. You can run `ps aux --sort=-time | grep "Plex Media Scanner"` to check for stuck scanner processes. @@ -35,6 +35,8 @@ A webdav server is also exposed to your localhost via port `9999`. - [@I-am-PUID-0](https://github.com/I-am-PUID-0) - [pd_zurg](https://github.com/I-am-PUID-0/pd_zurg) - [@Pukabyte](https://github.com/Pukabyte) - [Guide: Zurg + RDT + Prowlarr + Arrs + Petio + Autoscan + Plex + Scannarr](https://puksthepirate.notion.site/Guide-Zurg-RDT-Prowlarr-Arrs-Petio-Autoscan-Plex-Scannarr-eebe27d130fa400c8a0536cab9d46eb3) +- [u/pg988](https://www.reddit.com/user/pg988/) - [Windows + zurg + Plex guide](https://www.reddit.com/r/RealDebrid/comments/18so926/windows_zurg_plex_guide/) +- [@ignamiranda](https://github.com/ignamiranda) - [Plex Debrid Zurg Windows Guide](https://github.com/ignamiranda/plex_debrid_zurg_scripts/) ## Please read our [wiki](https://github.com/debridmediamanager/zurg-testing/wiki) for more information! diff --git a/config.example.yml b/config.example.yml index 4edb71b..999113e 100644 --- a/config.example.yml +++ b/config.example.yml @@ -2,18 +2,44 @@ zurg: v1 token: YOUR_RD_API_TOKEN # https://real-debrid.com/apitoken -# basic functionality -host: "[::]" # do not change this if you are running it inside a docker container -port: 9999 # do not change this if you are running it inside a docker container +# do not change this if you are running it inside a docker container +host: "[::]" +port: 9999 + +# you can protect zurg server with username+password auth +username: yowmamasita +password: 1234 + +# How many requests in parallel should we send to Real-Debrid API? concurrent_workers: 20 + +# How often should we check Real-Debrid API for file changes? check_for_changes_every_secs: 15 -# misc configs -retain_folder_name_extension: false # if true, zurg won't modify the filenames from real-debrid -retain_rd_torrent_name: false # if true, it will strictly follow RD API torrent name property w/c should make this more compatible with rdt-client -auto_delete_rar_torrents: false # if true, zurg will delete unstreamable rar files (these torrents will always be compressed in a rar archive no matter what files you select) -use_download_cache: true # if true, during zurg initialization, it will fetch all downloads to unrestrict links faster -enable_repair: true # BEWARE! THERE CAN ONLY BE 1 INSTANCE OF ZURG THAT SHOULD REPAIR YOUR TORRENTS +# if true, you can rename directories and files; if false, saved rename info (if it exists) will be ignored +allow_renames: true + +# if true, it will strictly follow Real-Debrid API filename property +# setting to true should make zurg more compatible with rdt-client +retain_rd_torrent_name: false + +# note: this is for cosmetic purposes only +# if true, zurg won't drop file extensions from directories +retain_folder_name_extension: false + +# if true, zurg will delete Real-Debrid rar'ed torrents +# they are always compressed in a rar archive no matter what files you select +auto_delete_rar_torrents: false + +# if true, during zurg initialization, it will fetch all downloads to unrestrict links faster +# it will also mount your download links in a special directory +use_download_cache: true + +# BEWARE! THERE CAN ONLY BE 1 INSTANCE OF ZURG THAT SHOULD REPAIR YOUR TORRENTS +enable_repair: true + +# this is useful for ensuring Plex adds your new content immediately +# uncomment the next line for triggering a partial scan # on_library_update: sh plex_update.sh "$@" on_library_update: | for arg in "$@" @@ -21,15 +47,34 @@ on_library_update: | echo "detected update on: $arg" done -# network configs +# buffer size when zurg is streaming files network_buffer_size: 1048576 # 1 MiB -serve_from_rclone: false # serve file data from rclone, not from zurg (zurg will only provide rclone the link to download) -verify_download_link: true # if true, zurg will check if the link is truly streamable; only relevant if serve_from_rclone is set to true (as it already does this all the time if serve_from_rclone is false) -force_ipv6: false # force connect to real-debrid ipv6 addresses -rate_limit_sleep_secs: 6 # wait time after getting a 429 from Real-Debrid API -realdebrid_timeout_secs: 60 # api timeout -retries_until_failed: 5 # api failures until considered failed -# preferred_hosts: # Run ./zurg network-test + +# true = send link to rclone and rclone will stream the file +# false = zurg will stream the file +serve_from_rclone: false + +# true = zurg will check if the link is really working +# only relevant if serve_from_rclone is set to true +# as it already does this all the time if serve_from_rclone is false +verify_download_link: true + +# force connect to real-debrid ipv6 addresses +# useful if you are blocked +force_ipv6: false + +# sleep time after getting a 429 from Real-Debrid API +rate_limit_sleep_secs: 6 + +# time to wait before timing out +realdebrid_timeout_secs: 60 + +# api response failures until considered failed +retries_until_failed: 5 + +# use the fastest hosts from your location +# Run ./zurg network-test +# preferred_hosts: # - 20.download.real-debrid.com # - 21.download.real-debrid.com # - 22.download.real-debrid.com diff --git a/internal/config/types.go b/internal/config/types.go index 3a08290..7c8d21d 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -19,6 +19,7 @@ type ConfigInterface interface { GetNetworkBufferSize() int EnableRetainFolderNameExtension() bool EnableRetainRDTorrentName() bool + ShouldAllowRenames() bool GetRandomPreferredHost() string ShouldServeFromRclone() bool ShouldVerifyDownloadLink() bool @@ -41,6 +42,7 @@ type ZurgConfig struct { NumOfWorkers int `yaml:"concurrent_workers" json:"concurrent_workers"` RefreshEverySeconds int `yaml:"check_for_changes_every_secs" json:"check_for_changes_every_secs"` + AllowRenames bool `yaml:"allow_renames" json:"allow_renames"` RetainRDTorrentName bool `yaml:"retain_rd_torrent_name" json:"retain_rd_torrent_name"` RetainFolderNameExtension bool `yaml:"retain_folder_name_extension" json:"retain_folder_name_extension"` @@ -127,6 +129,10 @@ func (z *ZurgConfig) EnableRetainRDTorrentName() bool { return z.RetainRDTorrentName } +func (z *ZurgConfig) ShouldAllowRenames() bool { + return z.AllowRenames +} + func (z *ZurgConfig) GetRandomPreferredHost() string { if len(z.PreferredHosts) == 0 { return "" diff --git a/internal/dav/infuse.go b/internal/dav/infuse.go index 9dfd6a4..2fc75a9 100644 --- a/internal/dav/infuse.go +++ b/internal/dav/infuse.go @@ -47,7 +47,7 @@ func ServeTorrentsListForInfuse(directory string, torMgr *torrent.TorrentManager if !ok || tor.AllInProgress() { continue } - buf.WriteString(dav.BaseDirectory(tor.AccessKey, tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(torMgr.GetKey(tor), tor.LatestAdded)) } buf.WriteString("") return buf.Bytes(), nil diff --git a/internal/dav/listing.go b/internal/dav/listing.go index ce340d6..d66fbc3 100644 --- a/internal/dav/listing.go +++ b/internal/dav/listing.go @@ -50,7 +50,7 @@ func ServeTorrentsList(directory string, torMgr *torrent.TorrentManager) ([]byte if !ok || tor.AllInProgress() { continue } - buf.WriteString(dav.Directory(tor.AccessKey, tor.LatestAdded)) + buf.WriteString(dav.Directory(torMgr.GetKey(tor), tor.LatestAdded)) } buf.WriteString("") return buf.Bytes(), nil @@ -74,7 +74,7 @@ func ServeFilesList(directory, torrentName string, torMgr *torrent.TorrentManage var buf bytes.Buffer buf.WriteString("") - buf.WriteString(dav.BaseDirectory(filepath.Join(directory, tor.AccessKey), tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.LatestAdded)) filenames := tor.SelectedFiles.Keys() sort.Strings(filenames) for _, filename := range filenames { @@ -113,7 +113,7 @@ func HandleSingleFile(directory, torrentName, fileName string, torMgr *torrent.T var buf bytes.Buffer buf.WriteString("") - buf.WriteString(dav.BaseDirectory(filepath.Join(directory, tor.AccessKey), tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.LatestAdded)) buf.WriteString(dav.File(fileName, file.Bytes, file.Ended)) buf.WriteString("") return buf.Bytes(), nil diff --git a/internal/dav/rename.go b/internal/dav/rename.go index d41d8ab..aa769a7 100644 --- a/internal/dav/rename.go +++ b/internal/dav/rename.go @@ -17,7 +17,7 @@ func HandleRenameTorrent(directory, torrentName, newName string, torMgr *torrent } torrents.Remove(torrentName) torrents.Set(newName, torrent) - torrent.AccessKey = newName + torrent.Rename = newName return nil } diff --git a/internal/http/listing.go b/internal/http/listing.go index 915a5c3..dba4058 100644 --- a/internal/http/listing.go +++ b/internal/http/listing.go @@ -48,7 +48,7 @@ func ServeTorrentsList(directory string, torMgr *torrent.TorrentManager) ([]byte if !ok || tor.AllInProgress() { continue } - buf.WriteString(fmt.Sprintf("
  • %s
  • ", filepath.Join(directory, url.PathEscape(tor.AccessKey)), tor.AccessKey)) + buf.WriteString(fmt.Sprintf("
  • %s
  • ", filepath.Join(directory, url.PathEscape(torMgr.GetKey(tor))), torMgr.GetKey(tor))) } return buf.Bytes(), nil } diff --git a/internal/torrent/delete.go b/internal/torrent/delete.go index 09d3f34..30aa4dc 100644 --- a/internal/torrent/delete.go +++ b/internal/torrent/delete.go @@ -15,7 +15,7 @@ func (t *TorrentManager) CheckDeletedStatus(torrent *Torrent) bool { infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) torrent.DownloadedIDs.Each(func(id string) bool { infoCache.Set(id, torrent) - t.writeTorrentToFile(id, torrent) + t.writeTorrentToFile(id, torrent, false) return false }) } diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index 7ab4fb2..f164722 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -51,7 +51,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, p // create internal directories t.DirectoryMap = cmap.New[cmap.ConcurrentMap[string, *Torrent]]() - t.DirectoryMap.Set(INT_ALL, cmap.New[*Torrent]()) // key is AccessKey + t.DirectoryMap.Set(INT_ALL, cmap.New[*Torrent]()) // key is GetAccessKey() t.DirectoryMap.Set(INT_INFO_CACHE, cmap.New[*Torrent]()) // key is Torrent ID // create directory maps for _, directory := range cfg.GetDirectories() { @@ -165,7 +165,7 @@ func (t *TorrentManager) assignedDirectoryCb(tor *Torrent, cb func(string)) { cb(config.UNPLAYABLE_TORRENTS) break } - if t.Config.MeetsConditions(directory, tor.AccessKey, tor.ComputeTotalSize(), torrentIDs, filenames, fileSizes) { + if t.Config.MeetsConditions(directory, t.GetKey(tor), tor.ComputeTotalSize(), torrentIDs, filenames, fileSizes) { cb(directory) break } @@ -174,21 +174,24 @@ func (t *TorrentManager) assignedDirectoryCb(tor *Torrent, cb func(string)) { } } -func (t *TorrentManager) computeAccessKey(name, originalName string) string { +func (t *TorrentManager) GetKey(torrent *Torrent) string { + if t.Config.ShouldAllowRenames() && torrent.Rename != "" { + return torrent.Rename + } if t.Config.EnableRetainRDTorrentName() { - return name + return torrent.Name } // drop the extension from the name - if t.Config.EnableRetainFolderNameExtension() && strings.Contains(name, originalName) { - return name + if t.Config.EnableRetainFolderNameExtension() && strings.Contains(torrent.Name, torrent.OriginalName) { + return torrent.Name } else { - ret := strings.TrimSuffix(originalName, ".mp4") + ret := strings.TrimSuffix(torrent.OriginalName, ".mp4") ret = strings.TrimSuffix(ret, ".mkv") return ret } } -func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent) { +func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent, overwriteNames bool) { filePath := "data/" + instanceID + ".json" file, err := os.Create(filePath) if err != nil { @@ -197,6 +200,13 @@ func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent) } defer file.Close() + if !overwriteNames { + infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) + if cachedTorrent, exists := infoCache.Get(instanceID); exists { + torrent.Name = cachedTorrent.Name + torrent.OriginalName = cachedTorrent.OriginalName + } + } torrent.Version = t.requiredVersion jsonData, err := json.Marshal(torrent) diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index 8e3b380..7dd7b5f 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -44,13 +44,13 @@ func (t *TorrentManager) RefreshTorrents() []string { continue } if !info.AnyInProgress() { - freshKeys.Add(info.AccessKey) + freshKeys.Add(t.GetKey(info)) } - if torrent, exists := allTorrents.Get(info.AccessKey); !exists { - allTorrents.Set(info.AccessKey, info) + if torrent, exists := allTorrents.Get(t.GetKey(info)); !exists { + allTorrents.Set(t.GetKey(info), info) } else if !info.DownloadedIDs.Difference(torrent.DownloadedIDs).IsEmpty() { mainTorrent := t.mergeToMain(torrent, info) - allTorrents.Set(info.AccessKey, &mainTorrent) + allTorrents.Set(t.GetKey(info), &mainTorrent) } } t.log.Infof("Compiled into %d torrents, %d were missing info", allTorrents.Count(), noInfoCount) @@ -130,9 +130,10 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { } torrent := Torrent{ - AccessKey: t.computeAccessKey(info.Name, info.OriginalName), - LatestAdded: info.Added, - Hash: info.Hash, + Name: info.Name, + OriginalName: info.OriginalName, + LatestAdded: info.Added, + Hash: info.Hash, } // SelectedFiles is a subset of Files with only the selected ones // it also has a Link field, which can be empty @@ -180,21 +181,23 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { torrent.InProgressIDs.Add(info.ID) } - t.writeTorrentToFile(rdTorrent.ID, &torrent) + t.writeTorrentToFile(rdTorrent.ID, &torrent, true) infoCache.Set(rdTorrent.ID, &torrent) return &torrent } func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent { - mainTorrent := Torrent{} - - mainTorrent.AccessKey = existing.AccessKey - mainTorrent.Hash = existing.Hash - mainTorrent.DownloadedIDs = mapset.NewSet[string]() - mainTorrent.InProgressIDs = mapset.NewSet[string]() - mainTorrent.Unfixable = existing.Unfixable || toMerge.Unfixable - mainTorrent.UnassignedLinks = existing.UnassignedLinks.Union(toMerge.UnassignedLinks) + mainTorrent := Torrent{ + Name: existing.Name, + OriginalName: existing.OriginalName, + Rename: existing.Rename, + Hash: existing.Hash, + DownloadedIDs: mapset.NewSet[string](), + InProgressIDs: mapset.NewSet[string](), + Unfixable: existing.Unfixable || toMerge.Unfixable, + UnassignedLinks: existing.UnassignedLinks.Union(toMerge.UnassignedLinks), + } // this function triggers only when we have a new DownloadedID toMerge.DownloadedIDs.Difference(existing.DownloadedIDs).Each(func(id string) bool { diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index f462cda..e6617e7 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -96,7 +96,7 @@ func (t *TorrentManager) repairAll() { t.log.Debugf("Found %d broken torrents to repair in total", len(toRepair)) for i := range toRepair { torrent := toRepair[i] - t.log.Infof("Repairing %s", torrent.AccessKey) + t.log.Infof("Repairing %s", t.GetKey(torrent)) t.repair(torrent) } } @@ -105,19 +105,19 @@ func (t *TorrentManager) Repair(torrent *Torrent) { infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) torrent.DownloadedIDs.Each(func(id string) bool { infoCache.Set(id, torrent) - t.writeTorrentToFile(id, torrent) + t.writeTorrentToFile(id, torrent, false) return false }) _ = t.repairWorker.Submit(func() { - t.log.Infof("Repairing torrent %s", torrent.AccessKey) + t.log.Infof("Repairing torrent %s", t.GetKey(torrent)) t.repair(torrent) - t.log.Infof("Finished repairing torrent %s", torrent.AccessKey) + t.log.Infof("Finished repairing torrent %s", t.GetKey(torrent)) }) } func (t *TorrentManager) repair(torrent *Torrent) { if torrent.AnyInProgress() { - t.log.Infof("Torrent %s is in progress, skipping repair until download is done", torrent.AccessKey) + t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent)) return } @@ -129,18 +129,18 @@ func (t *TorrentManager) repair(torrent *Torrent) { if torrent.OlderThanDuration(EXPIRED_LINK_TOLERANCE_HOURS * time.Hour) { // first solution: reinsert with same selection - t.log.Infof("Torrent %s is older than %d hours, reinserting it", torrent.AccessKey, EXPIRED_LINK_TOLERANCE_HOURS) + t.log.Infof("Torrent %s is older than %d hours, reinserting it", t.GetKey(torrent), EXPIRED_LINK_TOLERANCE_HOURS) if t.reinsertTorrent(torrent, "") { - t.log.Infof("Successfully downloaded torrent %s to repair it", torrent.AccessKey) + t.log.Infof("Successfully downloaded torrent %s to repair it", t.GetKey(torrent)) return } else if torrent.Unfixable { - t.log.Warnf("Cannot repair torrent %s", torrent.AccessKey) + t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent)) return } else { - t.log.Warnf("Failed to repair by reinserting torrent %s, will only redownload broken files...", torrent.AccessKey) + t.log.Warnf("Failed to repair by reinserting torrent %s, will only redownload broken files...", t.GetKey(torrent)) } } else { - t.log.Warnf("Torrent %s is not older than %d hours to be repaired by reinsertion, will only redownload broken files...", torrent.AccessKey, EXPIRED_LINK_TOLERANCE_HOURS) + t.log.Warnf("Torrent %s is not older than %d hours to be repaired by reinsertion, will only redownload broken files...", t.GetKey(torrent), EXPIRED_LINK_TOLERANCE_HOURS) } // sleep for 30 seconds to let the torrent accumulate more broken files if scanning @@ -174,12 +174,12 @@ func (t *TorrentManager) repair(torrent *Torrent) { }) if assignedCount > 0 { - t.log.Infof("Assigned %d links to selected files for torrent %s", assignedCount, torrent.AccessKey) + t.log.Infof("Assigned %d links to selected files for torrent %s", assignedCount, t.GetKey(torrent)) } else if rarCount > 0 { // this is a rar'ed torrent, nothing we can do if t.Config.ShouldDeleteRarFiles() { - t.log.Warnf("Torrent %s is rar'ed and we cannot repair it, deleting it as configured", torrent.AccessKey) - t.Delete(torrent.AccessKey, true) + t.log.Warnf("Torrent %s is rar'ed and we cannot repair it, deleting it as configured", t.GetKey(torrent)) + t.Delete(t.GetKey(torrent), true) } else { for _, unassigned := range unassignedDownloads { newFile := &File{ @@ -208,14 +208,14 @@ func (t *TorrentManager) repair(torrent *Torrent) { file.Link = "repairing" } }) - t.log.Debugf("During repair, zurg found %d broken files for torrent %s", len(brokenFiles), torrent.AccessKey) + t.log.Debugf("During repair, zurg found %d broken files for torrent %s", len(brokenFiles), t.GetKey(torrent)) if len(brokenFiles) == 1 && torrent.SelectedFiles.Count() > 2 { // if we download a single file, it will be named differently // so we need to download 1 extra file to preserve the name // this is only relevant if we enable retain_rd_torrent_name // add the first file link encountered with a prefix of http - t.log.Debugf("Torrent %s has only 1 broken file, adding 1 extra file to preserve the name", torrent.AccessKey) + t.log.Debugf("Torrent %s has only 1 broken file, adding 1 extra file to preserve the name", t.GetKey(torrent)) for _, file := range torrent.SelectedFiles.Items() { if strings.HasPrefix(file.Link, "http") { brokenFiles = append(brokenFiles, *file) @@ -225,15 +225,15 @@ func (t *TorrentManager) repair(torrent *Torrent) { } if len(brokenFiles) > 0 { - t.log.Infof("Redownloading %dof%d files for torrent %s", len(brokenFiles), torrent.SelectedFiles.Count(), torrent.AccessKey) + t.log.Infof("Redownloading %dof%d files for torrent %s", len(brokenFiles), torrent.SelectedFiles.Count(), t.GetKey(torrent)) brokenFileIDs := strings.Join(getFileIDs(brokenFiles), ",") if t.reinsertTorrent(torrent, brokenFileIDs) { - t.log.Infof("Successfully downloaded torrent %s to repair it", torrent.AccessKey) + t.log.Infof("Successfully downloaded torrent %s to repair it", t.GetKey(torrent)) } else { - t.log.Warnf("Cannot repair torrent %s", torrent.AccessKey) + t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent)) } } else { - t.log.Warnf("Torrent %s has no broken files to repair", torrent.AccessKey) + t.log.Warnf("Torrent %s has no broken files to repair", t.GetKey(torrent)) } } @@ -356,22 +356,22 @@ func (t *TorrentManager) canCapacityHandle() bool { } func (t *TorrentManager) markAsUnplayable(torrent *Torrent) { - t.log.Warnf("Marking torrent %s as unplayable", torrent.AccessKey) + t.log.Warnf("Marking torrent %s as unplayable", t.GetKey(torrent)) t.DirectoryMap.IterCb(func(directory string, torrents cmap.ConcurrentMap[string, *Torrent]) { - torrents.Remove(torrent.AccessKey) + torrents.Remove(t.GetKey(torrent)) }) torrents, _ := t.DirectoryMap.Get(config.UNPLAYABLE_TORRENTS) - torrents.Set(torrent.AccessKey, torrent) + torrents.Set(t.GetKey(torrent), torrent) } func (t *TorrentManager) markAsUnfixable(torrent *Torrent) { - t.log.Warnf("Marking torrent %s as unfixable", torrent.AccessKey) + t.log.Warnf("Marking torrent %s as unfixable", t.GetKey(torrent)) torrent.Unfixable = true infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) torrent.DownloadedIDs.Each(func(id string) bool { info, _ := infoCache.Get(id) info.Unfixable = true - t.writeTorrentToFile(id, torrent) + t.writeTorrentToFile(id, torrent, false) return false }) } diff --git a/internal/torrent/types.go b/internal/torrent/types.go index dcafb46..82ee021 100644 --- a/internal/torrent/types.go +++ b/internal/torrent/types.go @@ -14,7 +14,9 @@ import ( var json = jsoniter.ConfigCompatibleWithStandardLibrary type Torrent struct { - AccessKey string `json:"AccessKey"` + Name string `json:"Name"` + OriginalName string `json:"OriginalName"` + Rename string `json:"Rename"` Hash string `json:"Hash"` SelectedFiles cmap.ConcurrentMap[string, *File] `json:"-"` LatestAdded string `json:"LatestAdded"`