From a6b5401c0be94aab3bcae7aa59fc11fb2c975ef7 Mon Sep 17 00:00:00 2001 From: kaso17 Date: Thu, 9 Nov 2017 13:28:15 +0100 Subject: [PATCH] add support for magnet file download links --- src/Jackett.Common/Indexers/BaseIndexer.cs | 4 ++++ .../Services/Interfaces/IServerService.cs | 2 +- .../Controllers/BlackholeController.cs | 19 +++++++++++++++++-- src/Jackett/Controllers/DownloadController.cs | 19 ++++++++++++++++++- .../Controllers/IndexerApiController.cs | 2 +- src/Jackett/Controllers/ResultsController.cs | 6 +++--- src/Jackett/Services/ServerService.cs | 2 +- 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs index d096f6530..1a57c4121 100644 --- a/src/Jackett.Common/Indexers/BaseIndexer.cs +++ b/src/Jackett.Common/Indexers/BaseIndexer.cs @@ -286,6 +286,10 @@ namespace Jackett.Indexers protected async Task Download(Uri link, RequestType method) { + // return magnet link + if (link.Scheme == "magnet") + return Encoding.UTF8.GetBytes(link.OriginalString); + // do some extra escaping, needed for HD-Torrents var requestLink = link.ToString() .Replace("(", "%28") diff --git a/src/Jackett.Common/Services/Interfaces/IServerService.cs b/src/Jackett.Common/Services/Interfaces/IServerService.cs index d7c4a0d5e..508c8623f 100644 --- a/src/Jackett.Common/Services/Interfaces/IServerService.cs +++ b/src/Jackett.Common/Services/Interfaces/IServerService.cs @@ -10,7 +10,7 @@ namespace Jackett.Services.Interfaces void Start(); void Stop(); void ReserveUrls(bool doInstall = true); - Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent"); + Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t"); string BasePath(); string GetServerUrl(HttpRequestMessage Request); List notices { get; } diff --git a/src/Jackett/Controllers/BlackholeController.cs b/src/Jackett/Controllers/BlackholeController.cs index 008738bf4..1a3584c50 100644 --- a/src/Jackett/Controllers/BlackholeController.cs +++ b/src/Jackett/Controllers/BlackholeController.cs @@ -50,8 +50,23 @@ namespace Jackett.Controllers path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); path = protectionService.UnProtect(path); var remoteFile = new Uri(path, UriKind.RelativeOrAbsolute); + var fileExtension = ".torrent"; var downloadBytes = await indexer.Download(remoteFile); + // handle magnet URLs + if (downloadBytes.Length >= 7 + && downloadBytes[0] == 0x6d // m + && downloadBytes[1] == 0x61 // a + && downloadBytes[2] == 0x67 // g + && downloadBytes[3] == 0x6e // n + && downloadBytes[4] == 0x65 // e + && downloadBytes[5] == 0x74 // t + && downloadBytes[6] == 0x3a // : + ) + { + fileExtension = ".magnet"; + } + if (string.IsNullOrWhiteSpace(serverConfig.BlackholeDir)) { throw new Exception("Blackhole directory not set!"); @@ -64,9 +79,9 @@ namespace Jackett.Controllers var fileName = DateTime.Now.Ticks.ToString() + "-" + StringUtil.MakeValidFileName(indexer.DisplayName, '_', false); if (string.IsNullOrWhiteSpace(file)) - fileName += ".torrent"; + fileName += fileExtension; else - fileName += "-"+StringUtil.MakeValidFileName(file, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks + fileName += "-"+StringUtil.MakeValidFileName(file + fileExtension, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes); jsonReply["result"] = "success"; diff --git a/src/Jackett/Controllers/DownloadController.cs b/src/Jackett/Controllers/DownloadController.cs index bbe6443e6..a3f25822f 100644 --- a/src/Jackett/Controllers/DownloadController.cs +++ b/src/Jackett/Controllers/DownloadController.cs @@ -53,6 +53,23 @@ namespace Jackett.Controllers var target = new Uri(path, UriKind.RelativeOrAbsolute); var downloadBytes = await indexer.Download(target); + // handle magnet URLs + if (downloadBytes.Length >= 7 + && downloadBytes[0] == 0x6d // m + && downloadBytes[1] == 0x61 // a + && downloadBytes[2] == 0x67 // g + && downloadBytes[3] == 0x6e // n + && downloadBytes[4] == 0x65 // e + && downloadBytes[5] == 0x74 // t + && downloadBytes[6] == 0x3a // : + ) + { + var magneturi = Encoding.UTF8.GetString(downloadBytes); + var response = Request.CreateResponse(HttpStatusCode.Moved); + response.Headers.Location = new Uri(magneturi); + return response; + } + // This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr. var parser = new BencodeParser(); var torrentDictionary = parser.Parse(downloadBytes); @@ -63,7 +80,7 @@ namespace Jackett.Controllers result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { - FileName = StringUtil.MakeValidFileName(file, '_', false) // call MakeValidFileName again to avoid any kind of injection attack + FileName = StringUtil.MakeValidFileName(file, '_', false) + ".torrent" // call MakeValidFileName again to avoid any kind of injection attack }; return result; } diff --git a/src/Jackett/Controllers/IndexerApiController.cs b/src/Jackett/Controllers/IndexerApiController.cs index d54e3cc37..28f7cfa18 100644 --- a/src/Jackett/Controllers/IndexerApiController.cs +++ b/src/Jackett/Controllers/IndexerApiController.cs @@ -156,7 +156,7 @@ namespace Jackett.Controllers.V20 foreach (var result in results) { var link = result.Link; - var file = StringUtil.MakeValidFileName(result.Title, '_', false) + ".torrent"; + var file = StringUtil.MakeValidFileName(result.Title, '_', false); result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file); if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir)) result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file); diff --git a/src/Jackett/Controllers/ResultsController.cs b/src/Jackett/Controllers/ResultsController.cs index 2afd4b249..649488282 100644 --- a/src/Jackett/Controllers/ResultsController.cs +++ b/src/Jackett/Controllers/ResultsController.cs @@ -319,7 +319,7 @@ namespace Jackett.Controllers.V20 var proxiedReleases = result.Releases.Select(r => AutoMapper.Mapper.Map(r)).Select(r => { - r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title + ".torrent"); + r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title); return r; }); @@ -371,7 +371,7 @@ namespace Jackett.Controllers.V20 var potatoReleases = result.Releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r => { var release = AutoMapper.Mapper.Map(r); - release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title + ".torrent"); + release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title); var item = new Models.DTO.TorrentPotatoResponseItem() { release_name = release.Title + "[" + CurrentIndexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.> @@ -403,7 +403,7 @@ namespace Jackett.Controllers.V20 foreach (var result in results) { var link = result.Link; - var file = StringUtil.MakeValidFileName(result.Title, '_', false) + ".torrent"; + var file = StringUtil.MakeValidFileName(result.Title, '_', false); result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file); if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir)) result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file); diff --git a/src/Jackett/Services/ServerService.cs b/src/Jackett/Services/ServerService.cs index b28a562cb..4c07794b4 100644 --- a/src/Jackett/Services/ServerService.cs +++ b/src/Jackett/Services/ServerService.cs @@ -59,7 +59,7 @@ namespace Jackett.Services } } - public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent") + public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t") { if (link == null || (link.IsAbsoluteUri && link.Scheme == "magnet")) return link;