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); + } +}