diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88b2cc2..da04f8e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [2.0.90] - 2024-12-06
+### Changed
+- Download individual files from Torbox instead of a zip file.
+
+### Removed
+- Removed ability to select instant files from AllDebrid.
+
+## [2.0.89] - 2024-11-24
+### Changed
+- Disabled selecting of files as Real-Debrid was the only provider that supported that.
+
+## [2.0.88] - 2024-11-24
+### Changed
+- Catch disabled instant availability endpoint from Real Debrid.
+
+## [2.0.87] - 2024-11-18
+### Added
+- Torbox support.
+- qBittorrent API authentication when no authentication is used.
+### Changed
+- .NET version changed to .NET 9.
+- Changed download limit to be split by active torrents.
+
## [2.0.86] - 2024-09-03
### Changed
- Add potential fix for BASE_PATH.
diff --git a/Dockerfile b/Dockerfile
index 9bc6a22..e210c88 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,7 +21,7 @@ RUN \
RUN ls -FCla /appclient/root
# Stage 2 - Build the backend
-FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim-amd64 AS dotnet-build-env
+FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim-amd64 AS dotnet-build-env
ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
ARG BUILDPLATFORM
@@ -66,14 +66,14 @@ RUN \
RUN \
if [ "$TARGETPLATFORM" = "linux/arm/v7" ] ; then \
- wget https://download.visualstudio.microsoft.com/download/pr/c3bf3103-efdb-42e0-af55-bbf861a4215b/dc22eda8877933b8c6569e3823f18d21/aspnetcore-runtime-8.0.0-linux-musl-arm64.tar.gz && \
- tar zxf aspnetcore-runtime-8.0.0-linux-musl-arm64.tar.gz -C /usr/share/dotnet ; \
+ wget https://download.visualstudio.microsoft.com/download/pr/59a041e1-921e-405e-8092-95333f80f9ca/63e83e3feb70e05ca05ed5db3c579be2/aspnetcore-runtime-9.0.0-linux-musl-arm.tar.gz && \
+ tar zxf aspnetcore-runtime-9.0.0-linux-musl-arm.tar.gz -C /usr/share/dotnet ; \
elif [ "$TARGETPLATFORM" = "linux/arm64" ] ; then \
- wget https://download.visualstudio.microsoft.com/download/pr/c3bf3103-efdb-42e0-af55-bbf861a4215b/dc22eda8877933b8c6569e3823f18d21/aspnetcore-runtime-8.0.0-linux-musl-arm64.tar.gz && \
- tar zxf aspnetcore-runtime-8.0.0-linux-musl-arm64.tar.gz -C /usr/share/dotnet ; \
+ wget https://download.visualstudio.microsoft.com/download/pr/e137f557-83cb-4f55-b1c8-e5f59ccd3cba/b8ba6f2ab96d0961757b71b00c201f31/aspnetcore-runtime-9.0.0-linux-musl-arm64.tar.gz && \
+ tar zxf aspnetcore-runtime-9.0.0-linux-musl-arm64.tar.gz -C /usr/share/dotnet ; \
else \
- wget https://download.visualstudio.microsoft.com/download/pr/7aa33fc7-07fe-48c2-8e44-a4bfb4928535/3b96ec50970eee414895ef3a5b188bcd/aspnetcore-runtime-8.0.0-linux-musl-x64.tar.gz && \
- tar zxf aspnetcore-runtime-8.0.0-linux-musl-x64.tar.gz -C /usr/share/dotnet ; \
+ wget https://download.visualstudio.microsoft.com/download/pr/86d7a513-fe71-4f37-b9ec-fdcf5566cce8/e72574fc82d7496c73a61f411d967d8e/aspnetcore-runtime-9.0.0-linux-musl-x64.tar.gz && \
+ tar zxf aspnetcore-runtime-9.0.0-linux-musl-x64.tar.gz -C /usr/share/dotnet ; \
fi
RUN \
diff --git a/README.md b/README.md
index 9756351..22eaffc 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ This is a web interface to manage your torrents on Real-Debrid, AllDebrid or Pre
- Download all files from Real-Debrid, AllDebrid or Premiumize to your local machine automatically
- Unpack all files when finished downloading
- Implements a fake qBittorrent API so you can hook up other applications like Sonarr, Radarr or Couchpotato.
-- Built with Angular 15 and .NET 8
+- Built with Angular 15 and .NET 9
**You will need a Premium service at Real-Debrid, AllDebrid or Premiumize!**
@@ -30,7 +30,7 @@ Instead of running in Docker you can install it as a service in Windows or Linux
## Windows Service
-1. Make sure you have the ASP.NET Core Runtime 8 installed: [https://dotnet.microsoft.com/download/dotnet/8.0](https://dotnet.microsoft.com/download/dotnet/8.0)
+1. Make sure you have the **ASP.NET Core Runtime 9.0.0** installed: [https://dotnet.microsoft.com/download/dotnet/9.0](https://dotnet.microsoft.com/download/dotnet/9.0)
2. Get the latest zip file from the Releases page and extract it to your host.
3. Open the `appsettings.json` file and replace the `LogLevel` `Path` to a path on your host.
4. In `appsettings.json` replace the `Database` `Path` to a path on your host.
@@ -52,7 +52,7 @@ Instead of running in Docker you can install it as a service in Linux.
```rm packages-microsoft-prod.deb```
- ```sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0```
+ ```sudo apt-get update && sudo apt-get install -y dotnet-sdk-9.0```
2. Get latest archive from [releases](https://github.com/rogerfar/rdt-client/releases):
```wget ```
@@ -188,7 +188,7 @@ By default the application runs in the root of your hosted address (i.e. https:/
- NodeJS
- NPM
- Angular CLI
-- .NET 8
+- .NET 9
- Visual Studio 2022
- (optional) Resharper
diff --git a/client/src/app/add-new-torrent/add-new-torrent.component.html b/client/src/app/add-new-torrent/add-new-torrent.component.html
index 7d939e6..12df392 100644
--- a/client/src/app/add-new-torrent/add-new-torrent.component.html
+++ b/client/src/app/add-new-torrent/add-new-torrent.component.html
@@ -72,35 +72,6 @@
-
-
Post Torrent Download Action
-
-
- Download all files
- Download all available files
- Manually pick files
-
-
-
When a torrent is fully downloaded on the provider, perform this action.
-
- This option is only available for RealDebrid. AllDebrid and Premiumize will always download the full torrent.
-
-
-
- 0"
- >
- This torrent is available for immediate download.
-
-
-
- This torrent is not available for immediate download.
-
-
Minimum file size to download
@@ -221,39 +192,6 @@
-
-
-
Available files
-
- These files are available for immediate download from your debrid provider.
- It is possible that there are more files in the torrent, which are not shown here.
-
-
-
-
diff --git a/client/src/app/navbar/navbar.component.html b/client/src/app/navbar/navbar.component.html
index 8395feb..55ee2b7 100644
--- a/client/src/app/navbar/navbar.component.html
+++ b/client/src/app/navbar/navbar.component.html
@@ -55,7 +55,7 @@
Profile
Logout
-
Version 2.0.86
+
Version 2.0.90
diff --git a/client/src/app/navbar/navbar.component.ts b/client/src/app/navbar/navbar.component.ts
index c47e2b9..95c8067 100644
--- a/client/src/app/navbar/navbar.component.ts
+++ b/client/src/app/navbar/navbar.component.ts
@@ -15,7 +15,11 @@ export class NavbarComponent implements OnInit {
public profile: Profile;
public providerLink: string;
- constructor(private settingsService: SettingsService, private authService: AuthService, private router: Router) {}
+ constructor(
+ private settingsService: SettingsService,
+ private authService: AuthService,
+ private router: Router,
+ ) {}
ngOnInit(): void {
this.settingsService.getProfile().subscribe((result) => {
@@ -31,6 +35,9 @@ export class NavbarComponent implements OnInit {
case 'Premiumize':
this.providerLink = 'https://www.premiumize.me/';
break;
+ case 'TorBox':
+ this.providerLink = 'https://torbox.app/';
+ break;
}
});
}
@@ -40,7 +47,7 @@ export class NavbarComponent implements OnInit {
() => {
this.router.navigate(['/login']);
},
- (err) => {}
+ (err) => {},
);
}
}
diff --git a/client/src/app/setup/setup.component.html b/client/src/app/setup/setup.component.html
index 3de49e5..643e618 100644
--- a/client/src/app/setup/setup.component.html
+++ b/client/src/app/setup/setup.component.html
@@ -42,7 +42,7 @@
@@ -65,6 +67,7 @@
Real-Debrid
AllDebrid
Premiumize
+ TorBox
@@ -91,6 +94,10 @@
>https://www.premiumize.me/account.
+
+ You can find your API key here:
+ https://torbox.app/settings .
+
diff --git a/package.json b/package.json
index 4ea720f..8c177b6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rdt-client",
- "version": "2.0.86",
+ "version": "2.0.90",
"description": "This is a web interface to manage your torrents on Real-Debrid.",
"main": "index.js",
"dependencies": {
diff --git a/server/RdtClient.Data/Data/TorrentData.cs b/server/RdtClient.Data/Data/TorrentData.cs
index 63d6cf6..34f43a3 100644
--- a/server/RdtClient.Data/Data/TorrentData.cs
+++ b/server/RdtClient.Data/Data/TorrentData.cs
@@ -51,12 +51,12 @@ public class TorrentData(DataContext dataContext)
public async Task
GetByHash(String hash)
{
-#pragma warning disable CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons
+ hash = hash.ToLower();
+
var dbTorrent = await dataContext.Torrents
.AsNoTracking()
.Include(m => m.Downloads)
- .FirstOrDefaultAsync(m => m.Hash.ToLower() == hash.ToLower());
-#pragma warning restore CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons
+ .FirstOrDefaultAsync(m => m.Hash == hash);
if (dbTorrent == null)
{
diff --git a/server/RdtClient.Data/Enums/Provider.cs b/server/RdtClient.Data/Enums/Provider.cs
index 7422663..ff372dc 100644
--- a/server/RdtClient.Data/Enums/Provider.cs
+++ b/server/RdtClient.Data/Enums/Provider.cs
@@ -11,5 +11,8 @@ public enum Provider
AllDebrid,
[Description("Premiumize")]
- Premiumize
+ Premiumize,
+
+ [Description("TorBox")]
+ TorBox
}
\ No newline at end of file
diff --git a/server/RdtClient.Data/Models/Internal/DbSettings.cs b/server/RdtClient.Data/Models/Internal/DbSettings.cs
index 21a0f34..eb62b6b 100644
--- a/server/RdtClient.Data/Models/Internal/DbSettings.cs
+++ b/server/RdtClient.Data/Models/Internal/DbSettings.cs
@@ -155,10 +155,11 @@ http://127.0.0.1:6800/jsonrpc.")]
public class DbSettingsProvider
{
[DisplayName("Provider")]
- [Description(@"The following 3 providers are supported:
+ [Description(@"The following 4 providers are supported:
https://real-debrid.com
https://alldebrid.com
https://www.premiumize.me/
+https://torbox.app/
At this point only 1 provider can be used at the time.")]
public Provider Provider { get; set; } = Provider.RealDebrid;
@@ -168,7 +169,9 @@ At this point only 1 provider can be used at the time.")]
or
https://alldebrid.com/apikeys/
or
-https://www.premiumize.me/account/ ")]
+https://www.premiumize.me/account/
+or
+https://torbox.app/settings/ ")]
public String ApiKey { get; set; } = "";
[DisplayName("Automatically import and process torrents added to provider")]
diff --git a/server/RdtClient.Data/RdtClient.Data.csproj b/server/RdtClient.Data/RdtClient.Data.csproj
index 81e9430..aebafe5 100644
--- a/server/RdtClient.Data/RdtClient.Data.csproj
+++ b/server/RdtClient.Data/RdtClient.Data.csproj
@@ -1,22 +1,22 @@
- net8.0
+ net9.0
enable
enable
latest
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/server/RdtClient.Service/DiConfig.cs b/server/RdtClient.Service/DiConfig.cs
index e5f7aa2..695443f 100644
--- a/server/RdtClient.Service/DiConfig.cs
+++ b/server/RdtClient.Service/DiConfig.cs
@@ -24,6 +24,7 @@ public static class DiConfig
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
services.AddScoped();
services.AddScoped();
diff --git a/server/RdtClient.Service/RdtClient.Service.csproj b/server/RdtClient.Service/RdtClient.Service.csproj
index 578fdd6..30f2067 100644
--- a/server/RdtClient.Service/RdtClient.Service.csproj
+++ b/server/RdtClient.Service/RdtClient.Service.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
enable
latest
@@ -11,17 +11,18 @@
-
+
-
-
+
+
-
+
-
+
+
diff --git a/server/RdtClient.Service/Services/Downloaders/InternalDownloader.cs b/server/RdtClient.Service/Services/Downloaders/InternalDownloader.cs
index 98cc1ba..11e02da 100644
--- a/server/RdtClient.Service/Services/Downloaders/InternalDownloader.cs
+++ b/server/RdtClient.Service/Services/Downloaders/InternalDownloader.cs
@@ -26,7 +26,7 @@ public class InternalDownloader : IDownloader
_uri = uri;
_filePath = filePath;
-
+
_downloadConfiguration = new();
SetSettings();
@@ -131,14 +131,14 @@ public class InternalDownloader : IDownloader
{
settingDownloadParallelCount = 1;
}
-
+
var settingDownloadMaxSpeed = Settings.Get.DownloadClient.MaxSpeed;
if (settingDownloadMaxSpeed <= 0)
{
settingDownloadMaxSpeed = 0;
}
-
+ settingDownloadMaxSpeed /= Math.Max(TorrentRunner.ActiveDownloadClients.Count, 1);
settingDownloadMaxSpeed = settingDownloadMaxSpeed * 1024 * 1024;
var settingDownloadTimeout = Settings.Get.DownloadClient.Timeout;
diff --git a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs
index a46e3fe..bc0102c 100644
--- a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs
+++ b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs
@@ -118,23 +118,9 @@ public class AllDebridTorrentClient(ILogger logger, IHtt
return resultId;
}
- public async Task> GetAvailableFiles(String hash)
+ public Task> GetAvailableFiles(String hash)
{
- var isAvailable = await GetClient().Magnet.InstantAvailabilityAsync(hash);
-
- if (isAvailable)
- {
- return
- [
- new()
- {
- Filename = "All files",
- Filesize = 0
- }
- ];
- }
-
- return [];
+ return Task.FromResult>([]);
}
public Task SelectFiles(Torrent torrent)
diff --git a/server/RdtClient.Service/Services/TorrentClients/PremiumizeTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/PremiumizeTorrentClient.cs
index b7e8382..cb170c2 100644
--- a/server/RdtClient.Service/Services/TorrentClients/PremiumizeTorrentClient.cs
+++ b/server/RdtClient.Service/Services/TorrentClients/PremiumizeTorrentClient.cs
@@ -117,8 +117,7 @@ public class PremiumizeTorrentClient(ILogger logger, IH
public Task> GetAvailableFiles(String hash)
{
- var result = new List();
- return Task.FromResult>(result);
+ return Task.FromResult>([]);
}
public Task SelectFiles(Torrent torrent)
diff --git a/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs
index 2b09057..9cc8ad0 100644
--- a/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs
+++ b/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs
@@ -137,49 +137,27 @@ public class RealDebridTorrentClient(ILogger logger, IH
return result.Id;
}
- public async Task> GetAvailableFiles(String hash)
+ public Task> GetAvailableFiles(String hash)
{
- var result = await GetClient().Torrents.GetAvailableFiles(hash);
-
- var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values);
-
- var groups = files.Where(m => m.Filename != null).GroupBy(m => $"{m.Filename}-{m.Filesize}");
-
- var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile
- {
- Filename = m.First().Filename!,
- Filesize = m.First().Filesize
- }).ToList();
-
- return torrentClientAvailableFiles;
+ return Task.FromResult>([]);
}
public async Task SelectFiles(Data.Models.Data.Torrent torrent)
{
- var files = torrent.Files;
+ IList files;
Log("Seleting files", torrent);
- if (torrent.DownloadAction == TorrentDownloadAction.DownloadAvailableFiles)
- {
- Log($"Determining which files are already available on RealDebrid", torrent);
-
- var availableFiles = await GetAvailableFiles(torrent.Hash);
-
- Log($"Found {files.Count}/{torrent.Files.Count} available files on RealDebrid", torrent);
-
- files = torrent.Files.Where(m => availableFiles.Any(f => m.Path.EndsWith(f.Filename))).ToList();
- }
- else if (torrent.DownloadAction == TorrentDownloadAction.DownloadAll)
- {
- Log("Selecting all files", torrent);
- files = [.. torrent.Files];
- }
- else if (torrent.DownloadAction == TorrentDownloadAction.DownloadManual)
+ if (torrent.DownloadAction == TorrentDownloadAction.DownloadManual)
{
Log("Selecting manual selected files", torrent);
files = torrent.Files.Where(m => torrent.ManualFiles.Any(f => m.Path.EndsWith(f))).ToList();
}
+ else
+ {
+ Log("Selecting all files", torrent);
+ files = [.. torrent.Files];
+ }
Log($"Selecting {files.Count}/{torrent.Files.Count} files", torrent);
diff --git a/server/RdtClient.Service/Services/TorrentClients/TorBoxTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/TorBoxTorrentClient.cs
new file mode 100644
index 0000000..088c928
--- /dev/null
+++ b/server/RdtClient.Service/Services/TorrentClients/TorBoxTorrentClient.cs
@@ -0,0 +1,319 @@
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using TorBoxNET;
+using RdtClient.Data.Enums;
+using RdtClient.Data.Models.TorrentClient;
+
+namespace RdtClient.Service.Services.TorrentClients;
+
+public class TorBoxTorrentClient(ILogger logger, IHttpClientFactory httpClientFactory) : ITorrentClient
+{
+ private TimeSpan? _offset;
+ private TorBoxNetClient GetClient()
+ {
+ try
+ {
+ var apiKey = Settings.Get.Provider.ApiKey;
+
+ if (String.IsNullOrWhiteSpace(apiKey))
+ {
+ throw new("TorBox API Key not set in the settings");
+ }
+
+ var httpClient = httpClientFactory.CreateClient();
+ httpClient.Timeout = TimeSpan.FromSeconds(Settings.Get.Provider.Timeout);
+
+ var torBoxNetClient = new TorBoxNetClient(null, httpClient, 5);
+ torBoxNetClient.UseApiAuthentication(apiKey);
+
+ // Get the server time to fix up the timezones on results
+ if (_offset == null)
+ {
+ var serverTime = DateTimeOffset.UtcNow;
+ _offset = serverTime.Offset;
+ }
+
+ return torBoxNetClient;
+ }
+ catch (AggregateException ae)
+ {
+ foreach (var inner in ae.InnerExceptions)
+ {
+ logger.LogError(inner, $"The connection to RealDebrid has failed: {inner.Message}");
+ }
+
+ throw;
+ }
+ catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
+ {
+ logger.LogError(ex, $"The connection to RealDebrid has timed out: {ex.Message}");
+
+ throw;
+ }
+ catch (TaskCanceledException ex)
+ {
+ logger.LogError(ex, $"The connection to RealDebrid has timed out: {ex.Message}");
+
+ throw;
+ }
+ }
+
+ private TorrentClientTorrent Map(TorrentInfoResult torrent)
+ {
+ return new()
+ {
+ Id = torrent.Hash,
+ Filename = torrent.Name,
+ OriginalFilename = torrent.Name,
+ Hash = torrent.Hash,
+ Bytes = torrent.Size,
+ OriginalBytes = torrent.Size,
+ Host = torrent.DownloadPresent.ToString(),
+ Split = 0,
+ Progress = (Int64)((torrent.Progress) * 100.0),
+ Status = torrent.DownloadState,
+ Added = ChangeTimeZone(torrent.CreatedAt)!.Value,
+ Files = (torrent.Files ?? []).Select(m => new TorrentClientFile
+ {
+ Path = String.Join("/", m.Name.Split('/').Skip(1)),
+ Bytes = m.Size,
+ Id = m.Id,
+ Selected = true
+ }).ToList(),
+ Links = [],
+ Ended = ChangeTimeZone(torrent.UpdatedAt),
+ Speed = torrent.DownloadSpeed,
+ Seeders = torrent.Seeds,
+ };
+ }
+
+ public async Task> GetTorrents()
+ {
+ var torrents = new List();
+
+ var currentTorrents = await GetClient().Torrents.GetCurrentAsync(true);
+ if (currentTorrents != null)
+ {
+ torrents.AddRange(currentTorrents);
+ }
+
+ var queuedTorrents = await GetClient().Torrents.GetQueuedAsync(true);
+ if (queuedTorrents != null)
+ {
+ torrents.AddRange(queuedTorrents);
+ }
+
+ return torrents.Select(Map).ToList();
+ }
+
+ public async Task GetUser()
+ {
+ var user = await GetClient().User.GetAsync(false);
+
+ return new()
+ {
+ Username = user.Data!.Email,
+ Expiration = user.Data!.Plan != 0 ? user.Data!.PremiumExpiresAt!.Value : null
+ };
+ }
+
+ public async Task AddMagnet(String magnetLink)
+ {
+ // var seeding = Settings.Get.Integrations.Default.FinishedAction;
+
+ // Line is not working right now, will disable seeding and fix in december when I have time again.
+ // var seed = (seeding == TorrentFinishedAction.RemoveAllTorrents || seeding == TorrentFinishedAction.RemoveRealDebrid) ? 3 : 2;
+
+ var seed = 3;
+ var result = await GetClient().Torrents.AddMagnetAsync(magnetLink, seed, false);
+
+ if (result.Error == "ACTIVE_LIMIT")
+ {
+ var magnetLinkInfo = MonoTorrent.MagnetLink.Parse(magnetLink);
+ return magnetLinkInfo.InfoHashes.V1!.ToHex().ToLowerInvariant();
+ }
+ else
+ {
+ return result.Data!.Hash!;
+ }
+ }
+
+ public async Task AddFile(Byte[] bytes)
+ {
+ // Line is not working right now, will disable seeding and fix in december when I have time again.
+ // var seed = (seeding == TorrentFinishedAction.RemoveAllTorrents || seeding == TorrentFinishedAction.RemoveRealDebrid) ? 3 : 2;
+ const Int32 seed = 3;
+
+ var result = await GetClient().Torrents.AddFileAsync(bytes, seed);
+ if (result.Error == "ACTIVE_LIMIT")
+ {
+ using var stream = new MemoryStream(bytes);
+
+ var torrent = await MonoTorrent.Torrent.LoadAsync(stream);
+ return torrent.InfoHashes.V1!.ToHex().ToLowerInvariant();
+ }
+
+ return result.Data!.Hash!;
+ }
+
+ public async Task> GetAvailableFiles(String hash)
+ {
+ var availability = await GetClient().Torrents.GetAvailabilityAsync(hash, listFiles: true);
+
+ if (availability.Data != null)
+ {
+ return (availability.Data[0]?.Files ?? []).Select(file => new TorrentClientAvailableFile
+ {
+ Filename = file.Name,
+ Filesize = file.Size
+ })
+ .ToList();
+ }
+
+ return [];
+ }
+
+ public Task SelectFiles(Data.Models.Data.Torrent torrent)
+ {
+ return Task.CompletedTask;
+ }
+
+ public async Task Delete(String torrentId)
+ {
+ await GetClient().Torrents.ControlAsync(torrentId, "delete");
+ }
+
+ public async Task Unrestrict(String link)
+ {
+ var segments = link.Split('/');
+
+ var zipped = segments[5] == "zip";
+ var fileId = zipped ? "0" : segments[5];
+
+ var result = await GetClient().Torrents.RequestDownloadAsync(Convert.ToInt32(segments[4]), Convert.ToInt32(fileId), zipped);
+
+ if (result.Error != null)
+ {
+ throw new("Unrestrict returned an invalid download");
+ }
+
+ return result.Data!;
+ }
+
+ public async Task UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent? torrentClientTorrent)
+ {
+ try
+ {
+ if (torrent.RdId == null)
+ {
+ return torrent;
+ }
+
+ var rdTorrent = await GetInfo(torrent.Hash) ?? throw new($"Resource not found");
+
+ if (!String.IsNullOrWhiteSpace(rdTorrent.Filename))
+ {
+ torrent.RdName = rdTorrent.Filename;
+ }
+
+ if (!String.IsNullOrWhiteSpace(rdTorrent.OriginalFilename))
+ {
+ torrent.RdName = rdTorrent.OriginalFilename;
+ }
+
+ if (rdTorrent.Bytes > 0)
+ {
+ torrent.RdSize = rdTorrent.Bytes;
+ }
+ else if (rdTorrent.OriginalBytes > 0)
+ {
+ torrent.RdSize = rdTorrent.OriginalBytes;
+ }
+
+ if (rdTorrent.Files != null)
+ {
+ torrent.RdFiles = JsonConvert.SerializeObject(rdTorrent.Files);
+ }
+
+ torrent.RdHost = rdTorrent.Host;
+ torrent.RdSplit = rdTorrent.Split;
+ torrent.RdProgress = rdTorrent.Progress;
+ torrent.RdAdded = rdTorrent.Added;
+ torrent.RdEnded = rdTorrent.Ended;
+ torrent.RdSpeed = rdTorrent.Speed;
+ torrent.RdSeeders = rdTorrent.Seeders;
+ torrent.RdStatusRaw = rdTorrent.Status;
+
+ if (rdTorrent.Host == "True")
+ {
+ torrent.RdStatus = TorrentStatus.Finished;
+ }
+ else
+ {
+ torrent.RdStatus = rdTorrent.Status switch
+ {
+ "queued" => TorrentStatus.Processing,
+ "metaDL" => TorrentStatus.Processing,
+ "checking" => TorrentStatus.Processing,
+ "checkingResumeData" => TorrentStatus.Processing,
+ "paused" => TorrentStatus.Downloading,
+ "downloading" => TorrentStatus.Downloading,
+ "completed" => TorrentStatus.Downloading,
+ "uploading" => TorrentStatus.Downloading,
+ "uploading (no peers)" => TorrentStatus.Downloading,
+ "stalled" => TorrentStatus.Downloading,
+ "stalled (no seeds)" => TorrentStatus.Downloading,
+ "processing" => TorrentStatus.Downloading,
+ "cached" => TorrentStatus.Finished,
+ _ => TorrentStatus.Error
+ };
+ }
+
+ }
+ catch (Exception ex)
+ {
+ if (ex.Message == "Resource not found")
+ {
+ torrent.RdStatusRaw = "deleted";
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ return torrent;
+ }
+
+ public async Task?> GetDownloadLinks(Data.Models.Data.Torrent torrent)
+ {
+ var files = new List();
+
+ var torrentId = await GetClient().Torrents.GetHashInfoAsync(torrent.Hash, skipCache: true);
+
+ foreach (var file in torrent.Files)
+ {
+ var newFile = $"https://torbox.app/fakedl/{torrentId?.Id}/{file.Id}";
+ files.Add(newFile);
+ }
+
+ return files;
+ }
+
+ private DateTimeOffset? ChangeTimeZone(DateTimeOffset? dateTimeOffset)
+ {
+ if (_offset == null)
+ {
+ return dateTimeOffset;
+ }
+
+ return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value);
+ }
+
+ private async Task GetInfo(String torrentHash)
+ {
+ var result = await GetClient().Torrents.GetHashInfoAsync(torrentHash, skipCache: true);
+
+ return Map(result!);
+ }
+}
diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs
index d1ff70d..25817cf 100644
--- a/server/RdtClient.Service/Services/Torrents.cs
+++ b/server/RdtClient.Service/Services/Torrents.cs
@@ -22,7 +22,8 @@ public class Torrents(
Downloads downloads,
AllDebridTorrentClient allDebridTorrentClient,
PremiumizeTorrentClient premiumizeTorrentClient,
- RealDebridTorrentClient realDebridTorrentClient)
+ RealDebridTorrentClient realDebridTorrentClient,
+ TorBoxTorrentClient torBoxTorrentClient)
{
private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1);
@@ -40,6 +41,7 @@ public class Torrents(
Provider.Premiumize => premiumizeTorrentClient,
Provider.RealDebrid => realDebridTorrentClient,
Provider.AllDebrid => allDebridTorrentClient,
+ Provider.TorBox => torBoxTorrentClient,
_ => throw new("Invalid Provider")
};
}
diff --git a/server/RdtClient.Web/Controllers/QBittorrentController.cs b/server/RdtClient.Web/Controllers/QBittorrentController.cs
index 4fdfd77..fe162b2 100644
--- a/server/RdtClient.Web/Controllers/QBittorrentController.cs
+++ b/server/RdtClient.Web/Controllers/QBittorrentController.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+using RdtClient.Data.Enums;
using RdtClient.Data.Models.QBittorrent;
using RdtClient.Service.Services;
@@ -21,6 +22,11 @@ public class QBittorrentController(ILogger logger, QBitto
{
logger.LogDebug($"Auth login");
+ if (Settings.Get.General.AuthenticationType == AuthenticationType.None)
+ {
+ return Ok("Ok.");
+ }
+
if (String.IsNullOrWhiteSpace(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return Ok("Fails.");
diff --git a/server/RdtClient.Web/Program.cs b/server/RdtClient.Web/Program.cs
index e65ad0c..d1d676a 100644
--- a/server/RdtClient.Web/Program.cs
+++ b/server/RdtClient.Web/Program.cs
@@ -1,5 +1,4 @@
using System.Diagnostics;
-using System.Net;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Hosting.WindowsServices;
@@ -136,8 +135,6 @@ builder.Host.UseWindowsService();
RdtClient.Data.DiConfig.Config(builder.Services, appSettings);
builder.Services.RegisterRdtServices();
-ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
-
try
{
// Build the app
diff --git a/server/RdtClient.Web/RdtClient.Web.csproj b/server/RdtClient.Web/RdtClient.Web.csproj
index 9de70e8..adfbda3 100644
--- a/server/RdtClient.Web/RdtClient.Web.csproj
+++ b/server/RdtClient.Web/RdtClient.Web.csproj
@@ -1,10 +1,10 @@
- net8.0
+ net9.0
Exe
94c24cba-f03f-4453-a671-3640b517c573
- 2.0.86
+ 2.0.90
enable
enable
latest
@@ -29,17 +29,17 @@
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
+
+
+
+
diff --git a/server/RdtClient.sln.DotSettings b/server/RdtClient.sln.DotSettings
index b248b47..46b2271 100644
--- a/server/RdtClient.sln.DotSettings
+++ b/server/RdtClient.sln.DotSettings
@@ -199,10 +199,12 @@
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ True
True
True
True
True
True
True
+ True
\ No newline at end of file