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