From beb0299a0bb7d01feb08a543fb8da83ff0b618db Mon Sep 17 00:00:00 2001 From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com> Date: Wed, 29 Jan 2025 11:07:20 +0000 Subject: [PATCH 1/3] revert changes to DownloadHelper.cs --- .../Helpers/DownloadHelper.cs | 78 +++++++++++-------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/server/RdtClient.Service/Helpers/DownloadHelper.cs b/server/RdtClient.Service/Helpers/DownloadHelper.cs index bac745f..06724ad 100644 --- a/server/RdtClient.Service/Helpers/DownloadHelper.cs +++ b/server/RdtClient.Service/Helpers/DownloadHelper.cs @@ -17,6 +17,7 @@ public static class DownloadHelper var directory = RemoveInvalidPathChars(torrent.RdName); var uri = new Uri(fileUrl); + var torrentPath = Path.Combine(downloadPath, directory); var fileName = download.FileName; @@ -29,42 +30,14 @@ public static class DownloadHelper fileName = FileHelper.RemoveInvalidFileNameChars(fileName); - var torrentPath = downloadPath; + var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList(); - if (torrent.Files.Count > 1) + if (matchingTorrentFiles.Count > 0) { - torrentPath = Path.Combine(downloadPath, directory); + var matchingTorrentFile = matchingTorrentFiles[0]; - var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList(); + var subPath = Path.GetDirectoryName(matchingTorrentFile.Path); - if (matchingTorrentFiles.Count > 0) - { - var matchingTorrentFile = matchingTorrentFiles[0]; - var subPath = Path.GetDirectoryName(matchingTorrentFile.Path); - - if (!String.IsNullOrWhiteSpace(subPath)) - { - subPath = subPath.Trim('/').Trim('\\'); - - torrentPath = Path.Combine(torrentPath, subPath); - } - } - } - else if (torrent.Files.Count == 1) - { - // Debrid servers such as RealDebrid store single file torrents in a subfolder, but AllDebrid doesn't. - // We should replicate this behavior so that both folder structures are equal. - // See issue: https://github.com/rogerfar/rdt-client/issues/648 - if (torrent.ClientKind != Torrent.TorrentClientKind.AllDebrid) - { - torrentPath = Path.Combine(downloadPath, directory); - } - - var torrentFile = torrent.Files[0]; - var subPath = Path.GetDirectoryName(torrentFile.Path); - - // What we think is a single file torrent may also be a folder with a single file in it. - // So make sure we handle that here. If this is not the case, torrentPath will be empty below. if (!String.IsNullOrWhiteSpace(subPath)) { subPath = subPath.Trim('/').Trim('\\'); @@ -73,7 +46,7 @@ public static class DownloadHelper } } - if (!String.IsNullOrWhiteSpace(torrentPath) && !Directory.Exists(torrentPath)) + if (!Directory.Exists(torrentPath)) { Directory.CreateDirectory(torrentPath); } @@ -85,7 +58,44 @@ public static class DownloadHelper public static String? GetDownloadPath(Torrent torrent, Download download) { - return GetDownloadPath("", torrent, download); + var fileUrl = download.Link; + + if (String.IsNullOrWhiteSpace(fileUrl) || torrent.RdName == null) + { + return null; + } + + var uri = new Uri(fileUrl); + var torrentPath = RemoveInvalidPathChars(torrent.RdName); + + var fileName = download.FileName; + + if (String.IsNullOrWhiteSpace(fileName)) + { + fileName = uri.Segments.Last(); + + fileName = HttpUtility.UrlDecode(fileName); + } + + var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList(); + + if (matchingTorrentFiles.Count > 0) + { + var matchingTorrentFile = matchingTorrentFiles[0]; + + var subPath = Path.GetDirectoryName(matchingTorrentFile.Path); + + if (!String.IsNullOrWhiteSpace(subPath)) + { + subPath = subPath.Trim('/').Trim('\\'); + + torrentPath = Path.Combine(torrentPath, subPath); + } + } + + var filePath = Path.Combine(torrentPath, fileName); + + return filePath; } private static String RemoveInvalidPathChars(String path) From 82f0bb8bbe43ba68cec0e0168d958ce696b71539 Mon Sep 17 00:00:00 2001 From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com> Date: Wed, 29 Jan 2025 12:11:25 +0000 Subject: [PATCH 2/3] Use static `GetSymlinkPath` on `AllDebridTorrentClient` to get the symlink (since the behaviour is unique to the debrid service) --- .../Helpers/DownloadHelper.cs | 34 ++++++--- .../Services/DownloadClient.cs | 9 ++- .../TorrentClients/AllDebridTorrentClient.cs | 73 ++++++++++++++----- 3 files changed, 85 insertions(+), 31 deletions(-) diff --git a/server/RdtClient.Service/Helpers/DownloadHelper.cs b/server/RdtClient.Service/Helpers/DownloadHelper.cs index 06724ad..73c2059 100644 --- a/server/RdtClient.Service/Helpers/DownloadHelper.cs +++ b/server/RdtClient.Service/Helpers/DownloadHelper.cs @@ -15,21 +15,16 @@ public static class DownloadHelper } var directory = RemoveInvalidPathChars(torrent.RdName); - - var uri = new Uri(fileUrl); + var torrentPath = Path.Combine(downloadPath, directory); - var fileName = download.FileName; + var fileName = GetFileName(download); - if (String.IsNullOrWhiteSpace(fileName)) + if (fileName == null) { - fileName = uri.Segments.Last(); - - fileName = HttpUtility.UrlDecode(fileName); + return null; } - fileName = FileHelper.RemoveInvalidFileNameChars(fileName); - var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList(); if (matchingTorrentFiles.Count > 0) @@ -98,8 +93,25 @@ public static class DownloadHelper return filePath; } - private static String RemoveInvalidPathChars(String path) + public static String? GetFileName(Download download) + { + if (String.IsNullOrWhiteSpace(download.Link)) + { + return null; + } + + var fileName = download.FileName; + + if (String.IsNullOrWhiteSpace(fileName)) + { + fileName = HttpUtility.UrlDecode(new Uri(download.Link).Segments.Last()); + } + + return FileHelper.RemoveInvalidFileNameChars(fileName); + } + + public static String RemoveInvalidPathChars(String path) { return String.Concat(path.Split(Path.GetInvalidPathChars())); } -} \ No newline at end of file +} diff --git a/server/RdtClient.Service/Services/DownloadClient.cs b/server/RdtClient.Service/Services/DownloadClient.cs index 6fdc3de..949271e 100644 --- a/server/RdtClient.Service/Services/DownloadClient.cs +++ b/server/RdtClient.Service/Services/DownloadClient.cs @@ -1,6 +1,7 @@ using RdtClient.Data.Models.Data; using RdtClient.Service.Helpers; using RdtClient.Service.Services.Downloaders; +using RdtClient.Service.Services.TorrentClients; namespace RdtClient.Service.Services; @@ -44,6 +45,12 @@ public class DownloadClient(Download download, Torrent torrent, String destinati throw new("Invalid download path"); } + var symlinkPath = torrent.ClientKind switch + { + Torrent.TorrentClientKind.AllDebrid => AllDebridTorrentClient.GetSymlinkPath(torrent, download), + _ => downloadPath + }; + Type = torrent.DownloadClient; if (Type != Data.Enums.DownloadClient.Symlink) @@ -56,7 +63,7 @@ public class DownloadClient(Download download, Torrent torrent, String destinati Data.Enums.DownloadClient.Internal => new InternalDownloader(download.Link, filePath), Data.Enums.DownloadClient.Bezzad => new BezzadDownloader(download.Link, filePath), Data.Enums.DownloadClient.Aria2c => new Aria2cDownloader(download.RemoteId, download.Link, filePath, downloadPath, category), - Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath, downloadPath, torrent.ClientKind), + Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath, symlinkPath, torrent.ClientKind), _ => throw new($"Unknown download client {Type}") }; diff --git a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs index 4f6c0aa..1eef8c2 100644 --- a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs +++ b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs @@ -6,6 +6,7 @@ using RdtClient.Data.Enums; using RdtClient.Data.Models.TorrentClient; using RdtClient.Service.Helpers; using System.Web; +using RdtClient.Data.Models.Data; using File = AllDebridNET.File; using LogLevel = Microsoft.Extensions.Logging.LogLevel; using Torrent = RdtClient.Data.Models.Data.Torrent; @@ -42,7 +43,7 @@ public class AllDebridTorrentClient(ILogger logger, IHtt { logger.LogError(ex, $"The connection to AllDebrid has timed out: {ex.Message}"); - throw; + throw; } } @@ -58,17 +59,18 @@ public class AllDebridTorrentClient(ILogger logger, IHtt OriginalBytes = torrent.Size, Host = null, Split = 0, - Progress = (Int64) Math.Round(torrent.Downloaded * 100.0 / torrent.Size), + Progress = (Int64)Math.Round(torrent.Downloaded * 100.0 / torrent.Size), Status = torrent.Status, StatusCode = torrent.StatusCode, Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate), Files = torrent.Links.Select((m, i) => new TorrentClientFile - { - Path = GetFiles(m.Files), - Bytes = m.Size, - Id = i, - Selected = true, - }).ToList(), + { + Path = GetFiles(m.Files), + Bytes = m.Size, + Id = i, + Selected = true, + }) + .ToList(), Links = torrent.Links.Select(m => m.LinkUrl.ToString()).ToList(), Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate), Speed = torrent.DownloadSpeed, @@ -79,6 +81,7 @@ public class AllDebridTorrentClient(ILogger logger, IHtt public async Task> GetTorrents() { var results = await GetClient().Magnet.StatusAllAsync(); + return results.Select(Map).ToList(); } @@ -245,15 +248,17 @@ public class AllDebridTorrentClient(ILogger logger, IHtt Log($"Found {links.Count} files that match the minimum file size criterea", torrent); } - + if (!String.IsNullOrWhiteSpace(torrent.IncludeRegex)) { Log($"Using regular expression {torrent.IncludeRegex} to include only files matching this regex", torrent); - + var newLinks = new List(); + foreach (var link in links) { var path = GetFiles(link.Files); + if (Regex.IsMatch(path, torrent.IncludeRegex)) { Log($"* Including {path}", torrent); @@ -264,19 +269,21 @@ public class AllDebridTorrentClient(ILogger logger, IHtt Log($"* Excluding {path}", torrent); } } - + links = newLinks; - + Log($"Found {newLinks.Count} files that match the regex", torrent); - } + } else if (!String.IsNullOrWhiteSpace(torrent.ExcludeRegex)) { Log($"Using regular expression {torrent.IncludeRegex} to ignore files matching this regex", torrent); - + var newLinks = new List(); + foreach (var link in links) { var path = GetFiles(link.Files); + if (!Regex.IsMatch(path, torrent.ExcludeRegex)) { Log($"* Including {path}", torrent); @@ -287,9 +294,9 @@ public class AllDebridTorrentClient(ILogger logger, IHtt Log($"* Excluding {path}", torrent); } } - + links = newLinks; - + Log($"Found {newLinks.Count} files that match the regex", torrent); } @@ -309,11 +316,12 @@ public class AllDebridTorrentClient(ILogger logger, IHtt Log($"{GetFiles(link.Files)} ({link.Size}b) {link.LinkUrl}"); } } - + Log("", torrent); return links.Select(m => m.LinkUrl.ToString()).ToList(); } + public Task GetFileName(String downloadUrl) { if (String.IsNullOrWhiteSpace(downloadUrl)) @@ -350,7 +358,7 @@ public class AllDebridTorrentClient(ILogger logger, IHtt { throw new("Unexpected number of nested files"); } - + result.AddRange(GetFiles(file.E.Value.PurpleEArray)); } } @@ -402,4 +410,31 @@ public class AllDebridTorrentClient(ILogger logger, IHtt logger.LogDebug(message); } -} \ No newline at end of file + + public static String? GetSymlinkPath(Torrent torrent, Download download) + { + var fileName = DownloadHelper.GetFileName(download); + + if (fileName == null || torrent.RdName == null) + { + return null; + } + + var directory = DownloadHelper.RemoveInvalidPathChars(torrent.RdName); + + var matchingTorrentFiles = torrent.Files.Where(m => m.Path.EndsWith(fileName)).Where(m => !String.IsNullOrWhiteSpace(m.Path)).ToList(); + + if (matchingTorrentFiles.Count == 0) + { + throw new Exception($"Could not find file {fileName} in {torrent.RdName}"); + } + + // Torrents with a single file in them don't need to have the `RdName` added + if (torrent.Files.Count == 1) + { + return matchingTorrentFiles[0].Path; + } + + return Path.Combine(directory, matchingTorrentFiles[0].Path); + } +} From 0c9de86531c750605dc06e3712ff9b80a0d94566 Mon Sep 17 00:00:00 2001 From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com> Date: Wed, 29 Jan 2025 12:19:52 +0000 Subject: [PATCH 3/3] rename symlinkPath -> symlinkSourcePath --- server/RdtClient.Service/Services/DownloadClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/RdtClient.Service/Services/DownloadClient.cs b/server/RdtClient.Service/Services/DownloadClient.cs index 949271e..5ea24b5 100644 --- a/server/RdtClient.Service/Services/DownloadClient.cs +++ b/server/RdtClient.Service/Services/DownloadClient.cs @@ -45,7 +45,7 @@ public class DownloadClient(Download download, Torrent torrent, String destinati throw new("Invalid download path"); } - var symlinkPath = torrent.ClientKind switch + var symlinkSourcePath = torrent.ClientKind switch { Torrent.TorrentClientKind.AllDebrid => AllDebridTorrentClient.GetSymlinkPath(torrent, download), _ => downloadPath @@ -63,7 +63,7 @@ public class DownloadClient(Download download, Torrent torrent, String destinati Data.Enums.DownloadClient.Internal => new InternalDownloader(download.Link, filePath), Data.Enums.DownloadClient.Bezzad => new BezzadDownloader(download.Link, filePath), Data.Enums.DownloadClient.Aria2c => new Aria2cDownloader(download.RemoteId, download.Link, filePath, downloadPath, category), - Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath, symlinkPath, torrent.ClientKind), + Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath, symlinkSourcePath, torrent.ClientKind), _ => throw new($"Unknown download client {Type}") };