From e6a22f6780a1ba6bd88737c953211869b5c03770 Mon Sep 17 00:00:00 2001 From: MentalBlank Date: Mon, 12 May 2025 01:23:13 +1000 Subject: [PATCH] Magnet Enrichment Add magnet link enrichment using configurable tracker lists from ngosang/trackerslist --- .../RdtClient.Data/Enums/MagnetTrackerList.cs | 36 ++++++++++++ .../Models/Internal/DbSettings.cs | 6 +- server/RdtClient.Service/Services/Torrents.cs | 56 +++++++++++++++---- 3 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 server/RdtClient.Data/Enums/MagnetTrackerList.cs diff --git a/server/RdtClient.Data/Enums/MagnetTrackerList.cs b/server/RdtClient.Data/Enums/MagnetTrackerList.cs new file mode 100644 index 0000000..5a0dab2 --- /dev/null +++ b/server/RdtClient.Data/Enums/MagnetTrackerList.cs @@ -0,0 +1,36 @@ +using System.ComponentModel; + +namespace RdtClient.Data.Enums; + +public enum MagnetTrackerEnrichment +{ + [Description("None (do not modify magnet links)")] + None, + + [Description("Best trackers")] + trackers_best, + + [Description("All trackers")] + trackers_all, + + [Description("All UDP trackers")] + trackers_all_udp, + + [Description("All HTTP trackers")] + trackers_all_http, + + [Description("All HTTPS trackers")] + trackers_all_https, + + [Description("All WebSocket (WS) trackers")] + trackers_all_ws, + + [Description("Best IP-only trackers")] + trackers_best_ip, + + [Description("All I2P trackers")] + trackers_all_i2p, + + [Description("All IP-only trackers")] + trackers_all_ip +} diff --git a/server/RdtClient.Data/Models/Internal/DbSettings.cs b/server/RdtClient.Data/Models/Internal/DbSettings.cs index 14c8606..136b6b3 100644 --- a/server/RdtClient.Data/Models/Internal/DbSettings.cs +++ b/server/RdtClient.Data/Models/Internal/DbSettings.cs @@ -74,7 +74,11 @@ Supports the following parameters: [DisplayName("Copy added torrent files")] [Description("When a torrent file or magnet is added, create a copy in this directory.")] public String? CopyAddedTorrents { get; set; } = null; - + + [DisplayName("Magnet tracker enrichment")] + [Description(@"Choose which tracker list to append to magnet links, see this README for more info.")] + public MagnetTrackerEnrichment MagnetTrackerEnrichment { get; set; } = MagnetTrackerEnrichment.None; + [DisplayName("Disable update notifications")] [Description("Ignore update notifications. You will still be notified if the version you are running has a security vulnerability.")] public Boolean DisableUpdateNotifications { get; set; } = false; diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs index 1e200bf..ec18b0e 100644 --- a/server/RdtClient.Service/Services/Torrents.cs +++ b/server/RdtClient.Service/Services/Torrents.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; +using System.Web; using Microsoft.Extensions.Logging; using MonoTorrent; using RdtClient.Data.Data; @@ -31,7 +32,6 @@ public class Torrents( TorBoxTorrentClient torBoxTorrentClient) { private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1); - private static readonly JsonSerializerOptions JsonSerializerOptions = new() { ReferenceHandler = ReferenceHandler.IgnoreCycles @@ -107,13 +107,51 @@ public class Torrents( await torrentData.UpdateCategory(torrent.TorrentId, category); } - public async Task AddMagnetToDebridQueue(String magnetLink, Torrent torrent) + public static async Task EnrichMagnetLink(string magnetLink) { - MagnetLink magnet; + var enrichment = Settings.Get.General.MagnetTrackerEnrichment; + if (enrichment == MagnetTrackerEnrichment.None) { return magnetLink; } + var url = $"https://github.com/ngosang/trackerslist/raw/refs/heads/master/{enrichment}.txt"; + var newTrackers = (await new HttpClient().GetStringAsync(url)).Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + + var originalUri = new Uri(magnetLink); + var decodedParams = HttpUtility.ParseQueryString(originalUri.Query); + var rawXt = decodedParams["xt"]!; + decodedParams.Remove("xt"); + + var existingTrackers = decodedParams.GetValues("tr") ?? Array.Empty(); + decodedParams.Remove("tr"); + var allTrackers = existingTrackers.Concat(newTrackers).Distinct(StringComparer.OrdinalIgnoreCase); + + var pieces = new List { $"xt={rawXt}" }; + var allKeys = decodedParams.AllKeys; + if (allKeys != null) + { + foreach (string? key in allKeys) + { + if (key == null) continue; + foreach (var val in decodedParams.GetValues(key)!) + { + pieces.Add($"{key}={HttpUtility.UrlEncode(val)}"); + } + } + } + foreach (var tr in allTrackers) { pieces.Add($"tr={HttpUtility.UrlEncode(tr)}"); } + + var basePart = originalUri.GetLeftPart(UriPartial.Path); + var enriched = $"{basePart}?{string.Join("&", pieces)}"; + + return enriched; + } + + public async Task AddMagnetToDebridQueue(string magnetLink, Torrent torrent) + { + var enriched = await EnrichMagnetLink(magnetLink); + MagnetLink magnet; try { - magnet = MagnetLink.Parse(magnetLink); + magnet = MagnetLink.Parse(enriched); } catch (Exception ex) { @@ -125,12 +163,10 @@ public class Torrents( torrent.RdName = magnet.Name; var hash = magnet.InfoHashes.V1OrV2.ToHex(); - - var newTorrent = await AddQueued(hash, magnetLink, false, torrent); + var newTorrent = await AddQueued(hash, enriched, false, torrent); Log($"Adding {hash} (magnet link) to queue", newTorrent); - - await CopyAddedTorrent(magnet.Name!, magnetLink); + await CopyAddedTorrent(magnet.Name!, enriched); return newTorrent; } @@ -224,7 +260,7 @@ public class Torrents( { throw new("Torrent has no torrent file or magnet link"); } - + logger.LogDebug("Adding {hash} to debrid provider {torrentInfo}", torrent.Hash, torrent.ToLog()); var id = torrent.IsFile @@ -426,7 +462,7 @@ public class Torrents( { var download = await downloads.GetById(downloadId) ?? throw new($"Download with ID {downloadId} not found"); - Log($"Unrestricting link", download, download.Torrent); + Log("Unrestricting link", download, download.Torrent); var unrestrictedLink = await TorrentClient.Unrestrict(download.Path);