Fixed settings parsing when entering an invalid full Int32.
Add Uploading status to the interface.
This commit is contained in:
parent
075f494ec6
commit
a0d000138c
13 changed files with 210 additions and 14 deletions
|
|
@ -4,6 +4,15 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.9.5] - 2021-10-28
|
||||||
|
### Changed
|
||||||
|
- Fixed issues with the simple downloader.
|
||||||
|
- Fixed issue with retrying downloads.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added torrent uploading status from Real Debrid.
|
||||||
|
- Restored removing of torrents when deleted from Real Debrid.
|
||||||
|
|
||||||
## [1.9.4] - 2021-10-28
|
## [1.9.4] - 2021-10-28
|
||||||
### Changed
|
### Changed
|
||||||
- Fixed issues retrying torrents after multiple failed downloads in large torrents.
|
- Fixed issues retrying torrents after multiple failed downloads in large torrents.
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="field has-addons" style="margin-bottom: 0">
|
<div class="field has-addons" style="margin-bottom: 0">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<input class="input" type="number" max="1000" min="0" [(ngModel)]="downloadMinSize" />
|
<input class="input" type="number" max="1000" min="0" step="1" [(ngModel)]="downloadMinSize" />
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a class="button is-static">MB</a>
|
<a class="button is-static">MB</a>
|
||||||
|
|
@ -84,7 +84,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Priority</label>
|
<label class="label">Priority</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" [(ngModel)]="priority" />
|
<input class="input" type="number" step="1" [(ngModel)]="priority" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ export enum RealDebridStatus {
|
||||||
WaitingForFileSelection = 1,
|
WaitingForFileSelection = 1,
|
||||||
Downloading = 2,
|
Downloading = 2,
|
||||||
Finished = 3,
|
Finished = 3,
|
||||||
|
Uploading = 4,
|
||||||
|
|
||||||
Error = 99,
|
Error = 99,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
<a class="navbar-item"> Profile </a>
|
<a class="navbar-item"> Profile </a>
|
||||||
<a class="navbar-item" (click)="logout()"> Logout </a>
|
<a class="navbar-item" (click)="logout()"> Logout </a>
|
||||||
<hr class="navbar-divider" />
|
<hr class="navbar-divider" />
|
||||||
<div class="navbar-item">Version 1.9.4</div>
|
<div class="navbar-item">Version 1.9.5</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Maximum unpack processes</label>
|
<label class="label">Maximum unpack processes</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" max="100" min="1" [(ngModel)]="settingUnpackLimit" />
|
<input class="input" type="number" max="100" min="1" step="1" [(ngModel)]="settingUnpackLimit" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">Maximum amount of downloads that get unpacked on your host at the same time.</p>
|
<p class="help">Maximum amount of downloads that get unpacked on your host at the same time.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Maximum parallel downloads</label>
|
<label class="label">Maximum parallel downloads</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" max="100" min="1" [(ngModel)]="settingDownloadLimit" />
|
<input class="input" type="number" max="100" min="1" step="1" [(ngModel)]="settingDownloadLimit" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">Maximum amount of torrents that get downloaded to your host at the same time.</p>
|
<p class="help">Maximum amount of torrents that get downloaded to your host at the same time.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -106,7 +106,7 @@
|
||||||
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
||||||
<label class="label">Parallel connections per download</label>
|
<label class="label">Parallel connections per download</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" max="100" min="0" [(ngModel)]="settingDownloadChunkCount" />
|
<input class="input" type="number" max="100" min="0" step="1" [(ngModel)]="settingDownloadChunkCount" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Maximum amount of parallel threads that are used to download a single torrent to your host. If set to 1 no
|
Maximum amount of parallel threads that are used to download a single torrent to your host. If set to 1 no
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
||||||
<label class="label">Download speed (in MB/s)</label>
|
<label class="label">Download speed (in MB/s)</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" max="1000" min="0" [(ngModel)]="settingDownloadMaxSpeed" />
|
<input class="input" type="number" max="1000" min="0" step="1" [(ngModel)]="settingDownloadMaxSpeed" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">Maximum download speed in Megabytes per second. When set to 0 unlimited speed is used.</p>
|
<p class="help">Maximum download speed in Megabytes per second. When set to 0 unlimited speed is used.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -178,7 +178,7 @@
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="field has-addons" style="margin-bottom: 0">
|
<div class="field has-addons" style="margin-bottom: 0">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<input class="input" type="number" max="1000" min="0" [(ngModel)]="settingMinFileSize" />
|
<input class="input" type="number" max="1000" min="0" step="1" [(ngModel)]="settingMinFileSize" />
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a class="button is-static">MB</a>
|
<a class="button is-static">MB</a>
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,8 @@ export class TorrentStatusPipe implements PipeTransform {
|
||||||
return `Torrent error: ${torrent.rdStatusRaw}`;
|
return `Torrent error: ${torrent.rdStatusRaw}`;
|
||||||
case RealDebridStatus.Finished:
|
case RealDebridStatus.Finished:
|
||||||
return `Torrent finished, waiting to download`;
|
return `Torrent finished, waiting to download`;
|
||||||
|
case RealDebridStatus.Uploading:
|
||||||
|
return `Torrent uploading`;
|
||||||
default:
|
default:
|
||||||
return 'Unknown status';
|
return 'Unknown status';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Priority</label>
|
<label class="label">Priority</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="number" [(ngModel)]="updateSettingsPriority" />
|
<input class="input" type="number" step="1" [(ngModel)]="updateSettingsPriority" />
|
||||||
</div>
|
</div>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rdt-client",
|
"name": "rdt-client",
|
||||||
"version": "1.9.4",
|
"version": "1.9.5",
|
||||||
"description": "This is a web interface to manage your torrents on Real-Debrid.",
|
"description": "This is a web interface to manage your torrents on Real-Debrid.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using RdtClient.Data.Models.Data;
|
using RdtClient.Data.Models.Data;
|
||||||
using RdtClient.Data.Models.Internal;
|
using RdtClient.Data.Models.Internal;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace RdtClient.Data.Data
|
namespace RdtClient.Data.Data
|
||||||
{
|
{
|
||||||
|
|
@ -26,8 +27,24 @@ namespace RdtClient.Data.Data
|
||||||
{
|
{
|
||||||
var allSettings = await _dataContext.Settings.AsNoTracking().ToListAsync();
|
var allSettings = await _dataContext.Settings.AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
String GetString(String name) => allSettings.FirstOrDefault(m => m.SettingId == name)?.Value;
|
String GetString(String name)
|
||||||
Int32 GetInt32(String name) => Int32.Parse(allSettings.FirstOrDefault(m => m.SettingId == name)?.Value ?? "0");
|
{
|
||||||
|
return allSettings.FirstOrDefault(m => m.SettingId == name)?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 GetInt32(String name)
|
||||||
|
{
|
||||||
|
var strVal = GetString(name);
|
||||||
|
|
||||||
|
if (!Int32.TryParse(strVal, out var intVal))
|
||||||
|
{
|
||||||
|
Log.Error("Unable to parse setting {name} to Int32", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Get = new DbSettings
|
Get = new DbSettings
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
WaitingForFileSelection = 1,
|
WaitingForFileSelection = 1,
|
||||||
Downloading = 2,
|
Downloading = 2,
|
||||||
Finished = 3,
|
Finished = 3,
|
||||||
|
Uploading = 4,
|
||||||
|
|
||||||
Error = 99
|
Error = 99
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using RDNET;
|
||||||
|
using RdtClient.Service.Models.TorrentClient;
|
||||||
|
|
||||||
|
namespace RdtClient.Service.Services.TorrentClients
|
||||||
|
{
|
||||||
|
public class AllDebridTorrentClient : ITorrentClient
|
||||||
|
{
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public AllDebridTorrentClient(IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RdNetClient GetRdNetClient()
|
||||||
|
{
|
||||||
|
var apiKey = Settings.Get.RealDebridApiKey;
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(apiKey))
|
||||||
|
{
|
||||||
|
throw new Exception("Real-Debrid API Key not set in the settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
|
var rdtNetClient = new RdNetClient(null, httpClient, 5);
|
||||||
|
rdtNetClient.UseApiAuthentication(apiKey);
|
||||||
|
|
||||||
|
return rdtNetClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TorrentClientTorrent Map(Torrent torrent)
|
||||||
|
{
|
||||||
|
return new TorrentClientTorrent
|
||||||
|
{
|
||||||
|
Id = torrent.Id,
|
||||||
|
Filename = torrent.Filename,
|
||||||
|
OriginalFilename = torrent.OriginalFilename,
|
||||||
|
Hash = torrent.Hash,
|
||||||
|
Bytes = torrent.Bytes,
|
||||||
|
OriginalBytes = torrent.OriginalBytes,
|
||||||
|
Host = torrent.Host,
|
||||||
|
Split = torrent.Split,
|
||||||
|
Progress = torrent.Progress,
|
||||||
|
Status = torrent.Status,
|
||||||
|
Added = torrent.Added,
|
||||||
|
Files = (torrent.Files ?? new List<TorrentFile>()).Select(m => new TorrentClientTorrentFile
|
||||||
|
{
|
||||||
|
Path = m.Path,
|
||||||
|
Bytes = m.Bytes,
|
||||||
|
Id = m.Id,
|
||||||
|
Selected = m.Selected
|
||||||
|
}).ToList(),
|
||||||
|
Links = torrent.Links,
|
||||||
|
Ended = torrent.Ended,
|
||||||
|
Speed = torrent.Speed,
|
||||||
|
Seeders = torrent.Seeders,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IList<TorrentClientTorrent>> GetTorrents()
|
||||||
|
{
|
||||||
|
var page = 0;
|
||||||
|
var results = new List<Torrent>();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var pagedResults = await GetRdNetClient().Torrents.GetAsync(page, 100);
|
||||||
|
|
||||||
|
results.AddRange(pagedResults);
|
||||||
|
|
||||||
|
if (pagedResults.Count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
page += 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.Select(Map).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TorrentClientUser> GetUser()
|
||||||
|
{
|
||||||
|
var user = await GetRdNetClient().User.GetAsync();
|
||||||
|
|
||||||
|
return new TorrentClientUser
|
||||||
|
{
|
||||||
|
Username = user.Username,
|
||||||
|
Expiration = user.Expiration
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<String> AddMagnet(String magnetLink)
|
||||||
|
{
|
||||||
|
var result = await GetRdNetClient().Torrents.AddMagnetAsync(magnetLink);
|
||||||
|
|
||||||
|
return result.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<String> AddFile(Byte[] bytes)
|
||||||
|
{
|
||||||
|
var result = await GetRdNetClient().Torrents.AddFileAsync(bytes);
|
||||||
|
|
||||||
|
return result.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||||
|
{
|
||||||
|
var result = await GetRdNetClient().Torrents.GetAvailableFiles(hash);
|
||||||
|
|
||||||
|
var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values);
|
||||||
|
|
||||||
|
var groups = files.GroupBy(m => $"{m.Filename}-{m.Filesize}");
|
||||||
|
|
||||||
|
var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile
|
||||||
|
{
|
||||||
|
Filename = m.First().Filename,
|
||||||
|
Filesize = m.First().Filesize
|
||||||
|
} ).ToList();
|
||||||
|
|
||||||
|
return torrentClientAvailableFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SelectFiles(String torrentId, IList<String> fileIds)
|
||||||
|
{
|
||||||
|
await GetRdNetClient().Torrents.SelectFilesAsync(torrentId, fileIds.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||||
|
{
|
||||||
|
var result = await GetRdNetClient().Torrents.GetInfoAsync(torrentId);
|
||||||
|
|
||||||
|
return Map(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Delete(String torrentId)
|
||||||
|
{
|
||||||
|
await GetRdNetClient().Torrents.DeleteAsync(torrentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<String> Unrestrict(String link)
|
||||||
|
{
|
||||||
|
var result = await GetRdNetClient().Unrestrict.LinkAsync(link);
|
||||||
|
|
||||||
|
return result.Download;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -354,6 +354,17 @@ namespace RdtClient.Service.Services
|
||||||
|
|
||||||
await UpdateRdData(torrent);
|
await UpdateRdData(torrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var torrent in torrents)
|
||||||
|
{
|
||||||
|
var rdTorrent = rdTorrents.FirstOrDefault(m => m.Id == torrent.RdId);
|
||||||
|
|
||||||
|
if (rdTorrent == null)
|
||||||
|
{
|
||||||
|
await _downloads.DeleteForTorrent(torrent.TorrentId);
|
||||||
|
await _torrentData.Delete(torrent.TorrentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -649,7 +660,7 @@ namespace RdtClient.Service.Services
|
||||||
"error" => RealDebridStatus.Error,
|
"error" => RealDebridStatus.Error,
|
||||||
"virus" => RealDebridStatus.Error,
|
"virus" => RealDebridStatus.Error,
|
||||||
"compressing" => RealDebridStatus.Downloading,
|
"compressing" => RealDebridStatus.Downloading,
|
||||||
"uploading" => RealDebridStatus.Downloading,
|
"uploading" => RealDebridStatus.Uploading,
|
||||||
"dead" => RealDebridStatus.Error,
|
"dead" => RealDebridStatus.Error,
|
||||||
_ => RealDebridStatus.Error
|
_ => RealDebridStatus.Error
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
|
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
|
||||||
<Version>1.9.4</Version>
|
<Version>1.9.5</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue