Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Sam Heinz 2024-09-08 23:57:33 +10:00
commit 0987b1f18c
18 changed files with 101 additions and 96 deletions

View file

@ -4,6 +4,34 @@ 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.86] - 2024-09-03
### Changed
- Add potential fix for BASE_PATH.
- Fixed creation of empty folders.
## [2.0.85] - 2024-09-03
### Changed
- Reverted: Prevent the creation of download folders when using symlink.
## [2.0.84] - 2024-09-02
### Changed
- Replace docker libssl1.1 with libssl3
## [2.0.83] - 2024-09-02
### Changed
- Fixed progress reporting to the qBittorrent API endpoint.
- Prevent the creation of download folders when using symlink.
## [2.0.82] - 2024-09-02
### Changed
- Update packages and docker alpine version.
## [2.0.81] - 2024-07-28
### Changed
- Improved handling of infringed torrents from real debrid.
- Force update of torrent data from real-debrid when no filename is found in the local DB.
- Fixed real-debrid deserialization issue when checking for instant available files.
## [2.0.80] - 2024-07-13
### Changed
- Add rate limiter to retry requests that are rate limited from Real-Debrid.

View file

@ -38,7 +38,7 @@ RUN \
dotnet restore --no-cache RdtClient.sln && dotnet publish --no-restore -c Release -o out ;
# Stage 3 - Build runtime image
FROM ghcr.io/linuxserver/baseimage-alpine:3.18
FROM ghcr.io/linuxserver/baseimage-alpine:3.20
ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
ARG BUILDPLATFORM
@ -60,7 +60,7 @@ RUN \
echo "**** Updating package information ****" && \
apk update && \
echo "**** Install pre-reqs ****" && \
apk add bash icu-libs krb5-libs libgcc libintl libssl1.1 libstdc++ zlib && \
apk add bash icu-libs krb5-libs libgcc libintl libssl3 libstdc++ zlib && \
echo "**** Installing dotnet ****" && \
mkdir -p /usr/share/dotnet

View file

@ -20,64 +20,24 @@ This is a web interface to manage your torrents on Real-Debrid, AllDebrid or Pre
## Docker Setup
You can run the docker container on Windows, Linux. To get started either use _Docker Run_ or _Docker Compose_.
Please see our separate Docker setup Read Me.
### Docker Run
```console
docker run --pull=always
--volume /your/download/path/:/data/downloads \
--volume /your/storage/path/:/data/db \
--log-driver json-file \
--log-opt max-size=10m \
-p 6500:6500 \
--name rdtclient \
rogerfar/rdtclient:latest
```
Replace `/your/download/path/` with your local path to download files to. For Windows i.e. `C:/Downloads`.
Replace `/your/storage/path/` with your local path to store persistent database and log files in. For Windows i.e. `C:/Docker/rdt-client`.
### Docker Compose
You can use the provided docker compose to run:
```yaml
version: '3.3'
services:
rdtclient:
container_name: rdtclient
volumes:
- 'D:/Downloads/:/data/downloads'
- 'D:/Docker/rdt-client/:/data/db'
image: rogerfar/rdtclient
restart: always
logging:
driver: json-file
options:
max-size: 10m
ports:
- '6500:6500'
```
And to run:
```console
docker-compose up -d
```
Replace the paths in `volumes` as in the above step.
[Readme for Docker](README-DOCKER.md)
## Run as a Service
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. Get the latest zip file from the Releases page and extract it to your host.
1. Open the `appsettings.json` file and replace the `LogLevel` `Path` to a path on your host.
1. In `appsettings.json` replace the `Database` `Path` to a path on your host.
1. When using Windows paths, make sure to escape the slashes. For example: `D:\\RdtClient\\db\\rdtclient.db`
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.
5. When using Windows paths, make sure to escape the slashes. For example: `D:\\RdtClient\\db\\rdtclient.db`
6. Do one of these:
* Run `RdtClient.Web.exe` to start the client.
* Run `service-install.bat` to install the client as a service. This will install `RdtClient.Web.exe` as a service which make the client start in the backgorund when the computer starts. (You probably want to do this if you are going to use this with Sonarr etc...)
## Linux Service

View file

@ -55,7 +55,7 @@
<a class="navbar-item" routerLink="profile"> Profile </a>
<a class="navbar-item" (click)="logout()"> Logout </a>
<hr class="navbar-divider" />
<a href="https://github.com/rogerfar/rdt-client" target="_blank" class="navbar-item">Version 2.0.80</a>
<a href="https://github.com/rogerfar/rdt-client" target="_blank" class="navbar-item">Version 2.0.86</a>
</div>
</div>
</div>

View file

@ -1,6 +1,6 @@
{
"name": "rdt-client",
"version": "2.0.80",
"version": "2.0.86",
"description": "This is a web interface to manage your torrents on Real-Debrid.",
"main": "index.js",
"dependencies": {

View file

@ -8,15 +8,15 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog" Version="4.0.1" />
</ItemGroup>
</Project>

View file

@ -118,11 +118,6 @@ public static class DownloadHelper
}
}
if (!Directory.Exists(torrentPath))
{
Directory.CreateDirectory(torrentPath);
}
var filePath = Path.Combine(torrentPath, fileName);
return filePath;

View file

@ -13,15 +13,15 @@
<PackageReference Include="Aria2.NET" Version="1.0.5" />
<PackageReference Include="Downloader" Version="3.1.2" />
<PackageReference Include="Downloader.NET" Version="1.0.12" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.7" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.7.0" />
<PackageReference Include="MonoTorrent" Version="2.0.7" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.8" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.8.0" />
<PackageReference Include="MonoTorrent" Version="3.0.2" />
<PackageReference Include="Polly" Version="8.4.1" />
<PackageReference Include="Premiumize.NET" Version="1.0.4" />
<PackageReference Include="RD.NET" Version="2.1.4" />
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="RD.NET" Version="2.1.6" />
<PackageReference Include="Serilog" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="SharpCompress" Version="0.37.2" />
<PackageReference Include="SharpCompress" Version="0.38.0" />
<PackageReference Include="TorBox.NET" Version="1.0.0.40" />
</ItemGroup>

View file

@ -39,10 +39,13 @@ public class DownloadClient(Download download, Torrent torrent, String destinati
throw new("Invalid download path");
}
await FileHelper.Delete(filePath.Result!);
Type = torrent.DownloadClient;
if (Type != Data.Enums.DownloadClient.Symlink)
{
await FileHelper.Delete(filePath);
}
Downloader = Type switch
{
Data.Enums.DownloadClient.Internal => new InternalDownloader(download.Link, filePath.Result!),

View file

@ -73,6 +73,8 @@ public class SymlinkDownloader(String uri, String destinationPath, String path)
potentialFilePaths.Add(fileName);
potentialFilePaths.Add(fileNameWithoutExtension);
// add an empty path so we can check for the new file in the base directory
potentialFilePaths.Add("");
potentialFilePaths = potentialFilePaths.Distinct().ToList();

View file

@ -194,7 +194,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
var prio = 0;
Decimal downloadProgress = 0;
Double downloadProgress = 0;
foreach (var torrent in allTorrents)
{
@ -214,12 +214,12 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
Int64 bytesDone = 0;
Int64 bytesTotal = 0;
Int64 speed = 0;
Int64 rdProgress = 0;
Double rdProgress = 0;
try
{
rdProgress = (Int64) ((torrent.RdProgress ?? 0) / 100.0m);
rdProgress = (torrent.RdProgress ?? 0.0) / 100.0;
bytesTotal = torrent.RdSize ?? 1;
bytesDone = bytesTotal * rdProgress;
bytesDone = (Int64) (bytesTotal * rdProgress);
speed = torrent.RdSpeed ?? 0;
}
catch (Exception ex)
@ -237,10 +237,10 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
bytesDone = torrent.Downloads.Sum(m => m.BytesDone);
bytesTotal = torrent.Downloads.Sum(m => m.BytesTotal);
speed = (Int32) torrent.Downloads.Average(m => m.Speed);
downloadProgress = bytesTotal > 0 ? (Decimal) bytesDone / bytesTotal : 0;
downloadProgress = bytesTotal > 0 ? (Double) bytesDone / bytesTotal : 0;
}
var progress = (Int64) ((rdProgress + downloadProgress) / 2m);
var progress = (rdProgress + downloadProgress) / 2.0;
var result = new TorrentInfo
{

View file

@ -287,7 +287,7 @@ public class RealDebridTorrentClient(ILogger<RealDebridTorrentClient> logger, IH
return torrent;
}
if (torrentClientTorrent == null || torrentClientTorrent.Ended == null)
if (torrentClientTorrent == null || torrentClientTorrent.Ended == null || String.IsNullOrEmpty(torrentClientTorrent.Filename))
{
torrentClientTorrent = await GetInfo(torrent.RdId) ?? throw new($"Resource not found");
}

View file

@ -117,7 +117,7 @@ public class Torrents(
var id = await TorrentClient.AddMagnet(magnetLink);
var hash = magnet.InfoHash.ToHex();
var hash = magnet.InfoHashes.V1OrV2.ToHex();
var newTorrent = await Add(id, hash, magnetLink, false, torrent);
@ -132,7 +132,7 @@ public class Torrents(
Directory.CreateDirectory(Settings.Get.General.CopyAddedTorrents);
}
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, $"{FileHelper.RemoveInvalidFileNameChars(magnet.Name)}.magnet");
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, $"{FileHelper.RemoveInvalidFileNameChars(magnet.Name!)}.magnet");
if (File.Exists(copyFileName))
{
@ -168,7 +168,7 @@ public class Torrents(
var id = await TorrentClient.AddFile(bytes);
var hash = monoTorrent.InfoHash.ToHex();
var hash = monoTorrent.InfoHashes.V1OrV2.ToHex();
var newTorrent = await Add(id, hash, fileAsBase64, true, torrent);

View file

@ -316,6 +316,7 @@ public class QBittorrentController(ILogger<QBittorrentController> logger, QBitto
foreach (var url in urls)
{
try{
if (url.StartsWith("magnet"))
{
await qBittorrent.TorrentsAddMagnet(url.Trim(), request.Category, null);
@ -330,6 +331,15 @@ public class QBittorrentController(ILogger<QBittorrentController> logger, QBitto
{
return BadRequest($"Invalid torrent link format {url}");
}
}
catch (RDNET.RealDebridException ex)
{
// Infringing file.
if (ex.ErrorCode == 35)
{
return Ok("Fails.");
}
}
}
return Ok();

View file

@ -134,7 +134,7 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
var torrent = await MonoTorrent.Torrent.LoadAsync(bytes);
var result = await torrents.GetAvailableFiles(torrent.InfoHash.ToHex());
var result = await torrents.GetAvailableFiles(torrent.InfoHashes.V1OrV2.ToHex());
return Ok(result);
}
@ -148,9 +148,14 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
return BadRequest();
}
if (String.IsNullOrEmpty(request.MagnetLink))
{
return BadRequest("MagnetLink cannot be null or empty");
}
var magnet = MagnetLink.Parse(request.MagnetLink);
var result = await torrents.GetAvailableFiles(magnet.InfoHash.ToHex());
var result = await torrents.GetAvailableFiles(magnet.InfoHashes.V1OrV2.ToHex());
return Ok(result);
}
@ -226,7 +231,7 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
{
var magnet = MagnetLink.Parse(request.MagnetLink);
availableFiles = await torrents.GetAvailableFiles(magnet.InfoHash.ToHex());
availableFiles = await torrents.GetAvailableFiles(magnet.InfoHashes.V1OrV2.ToHex());
}
else if (file != null)
{
@ -240,7 +245,7 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
var torrent = await MonoTorrent.Torrent.LoadAsync(bytes);
availableFiles = await torrents.GetAvailableFiles(torrent.InfoHash.ToHex());
availableFiles = await torrents.GetAvailableFiles(torrent.InfoHashes.V1OrV2.ToHex());
}
else
{

View file

@ -168,6 +168,7 @@ try
if (basePath != null)
{
app.UseMiddleware<BaseHrefMiddleware>(basePath);
app.UsePathBase($"/{basePath.TrimStart('/').TrimEnd('/')}/");
}
app.UseMiddleware<RequestLoggingMiddleware>();

View file

@ -11,7 +11,8 @@
"RdtClient.Web": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Development",
"BASE_PATH": "test"
},
"applicationUrl": "http://localhost:6500"
},

View file

@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
<Version>2.0.80</Version>
<Version>2.0.86</Version>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
@ -29,17 +29,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.7" />
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
<PackageReference Include="Serilog" Version="4.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
</ItemGroup>