Rename folder to path everywhere.

Added a remote path setting for path mapping for Sonarr/Radarr.
This commit is contained in:
Roger Far 2021-01-12 21:24:46 -07:00
parent 2300b51ede
commit 7f9d6e6cba
11 changed files with 160 additions and 101 deletions

View file

@ -18,11 +18,21 @@
</p>
</div>
<div class="field">
<label class="label">Download folder</label>
<label class="label">Download path</label>
<div class="control">
<input class="input" type="text" maxlength="1000" [(ngModel)]="settingDownloadFolder" />
<input class="input" type="text" maxlength="1000" [(ngModel)]="settingDownloadPath" />
</div>
<p class="help">Path on the host where RealDebrid Client is hosted.</p>
<p class="help">Path in the docker container to download files to (i.e. /data/downloads).</p>
</div>
<div class="field">
<label class="label">Mapped path</label>
<div class="control">
<input class="input" type="text" maxlength="1000" [(ngModel)]="settingMappedPath" />
</div>
<p class="help">
Path where files are downloaded to on your host (i.e. D:\Downloads). This path is used for Radarr and Sonarr
to find your downloads.
</p>
</div>
<div class="field">
<label class="label">Maximum parallel downloads</label>
@ -38,16 +48,30 @@
</div>
<p class="help">Maximum amount of downloads that get unpacked on your host at the same time.</p>
</div>
<div class="field">
<label class="label">Minimum file size to download</label>
<div class="control">
<div class="field has-addons" style="margin-bottom: 0">
<div class="control is-expanded">
<input class="input" type="number" max="100" min="1" [(ngModel)]="settingMinFileSize" />
</div>
<div class="control">
<a class="button is-static">MB</a>
</div>
</div>
<div class="help">When selecting files in the torrent, skip files smaller than this setting.</div>
</div>
</div>
<div class="notification is-danger is-light" *ngIf="error?.length > 0">Error saving settings: {{ error }}</div>
<div class="notification is-danger is-light" *ngIf="testFolderError?.length > 0">
Could not test your download folder<br />
{{ testFolderError }}
<div class="notification is-danger is-light" *ngIf="testPathError?.length > 0">
Could not test your download path<br />
{{ testPathError }}
</div>
<div class="notification is-success is-light" *ngIf="testFolderSuccess">
Successfully tested your download folder
</div>
<div class="notification is-success is-light" *ngIf="testPathSuccess">Successfully tested your download path</div>
</section>
<footer class="modal-card-foot">
<button class="button is-success" (click)="ok()" [disabled]="saving" [ngClass]="{ 'is-loading': saving }">

View file

@ -25,13 +25,15 @@ export class SettingsComponent implements OnInit {
public saving = false;
public error: string;
public testFolderError: string;
public testFolderSuccess: boolean;
public testPathError: string;
public testPathSuccess: boolean;
public settingRealDebridApiKey: string;
public settingDownloadFolder: string;
public settingDownloadPath: string;
public settingMappedPath: string;
public settingDownloadLimit: number;
public settingUnpackLimit: number;
public settingMinFileSize: number;
constructor(private settingsService: SettingsService) {}
@ -44,9 +46,11 @@ export class SettingsComponent implements OnInit {
this.settingsService.get().subscribe(
(results) => {
this.settingRealDebridApiKey = this.getSetting(results, 'RealDebridApiKey');
this.settingDownloadFolder = this.getSetting(results, 'DownloadFolder');
this.settingDownloadPath = this.getSetting(results, 'DownloadPath');
this.settingMappedPath = this.getSetting(results, 'MappedPath');
this.settingDownloadLimit = parseInt(this.getSetting(results, 'DownloadLimit'), 10);
this.settingUnpackLimit = parseInt(this.getSetting(results, 'UnpackLimit'), 10);
this.settingMinFileSize = parseInt(this.getSetting(results, 'MinFileSize'), 10);
},
(err) => {
this.error = err.error;
@ -64,8 +68,12 @@ export class SettingsComponent implements OnInit {
value: this.settingRealDebridApiKey,
},
{
settingId: 'DownloadFolder',
value: this.settingDownloadFolder,
settingId: 'DownloadPath',
value: this.settingDownloadPath,
},
{
settingId: 'MappedPath',
value: this.settingMappedPath,
},
{
settingId: 'DownloadLimit',
@ -75,6 +83,10 @@ export class SettingsComponent implements OnInit {
settingId: 'UnpackLimit',
value: (this.settingUnpackLimit ?? 1).toString(),
},
{
settingId: 'MinFileSize',
value: (this.settingMinFileSize ?? 0).toString(),
},
];
this.settingsService.update(settings).subscribe(
@ -90,17 +102,17 @@ export class SettingsComponent implements OnInit {
public test(): void {
this.saving = true;
this.testFolderError = null;
this.testFolderSuccess = false;
this.testPathError = null;
this.testPathSuccess = false;
this.settingsService.testFolder(this.settingDownloadFolder).subscribe(
this.settingsService.testPath(this.settingDownloadPath).subscribe(
() => {
this.saving = false;
this.testFolderSuccess = true;
this.testPathSuccess = true;
},
(err) => {
console.log(err);
this.testFolderError = err.error;
this.testPathError = err.error;
this.saving = false;
}
);

View file

@ -22,7 +22,7 @@ export class SettingsService {
return this.http.get<Profile>(`/Api/Settings/Profile`);
}
public testFolder(folder: string): Observable<void> {
return this.http.post<void>(`/Api/Settings/TestFolder`, { folder });
public testPath(path: string): Observable<void> {
return this.http.post<void>(`/Api/Settings/TestPath`, { path });
}
}

View file

@ -13,69 +13,71 @@ export class TorrentStatusPipe implements PipeTransform {
return 'Finished';
}
const allFinished = torrent.downloads.all((m) => m.completed != null);
if (torrent.downloads.length > 0) {
const allFinished = torrent.downloads.all((m) => m.completed != null);
if (allFinished) {
return 'Finished';
}
const errors = torrent.downloads.where((m) => m.error != null);
if (errors.length > 0) {
return 'Error';
}
const downloading = torrent.downloads.where((m) => m.downloadStarted && !m.downloadFinished);
if (downloading.length > 0) {
const bytesDone = downloading.sum((m) => m.bytesDone);
const bytesTotal = downloading.sum((m) => m.bytesTotal);
let progress = (bytesDone / bytesTotal) * 100;
let allSpeeds = downloading.sum((m) => m.speed) / downloading.length;
let speed: string | string[] = '0';
if (allSpeeds > 0) {
speed = this.pipe.transform(allSpeeds, 'filesize');
return `Downloading (${progress.toFixed(2)}% - ${speed}/s)`;
if (allFinished) {
return 'Finished';
}
}
const unpacking = torrent.downloads.where((m) => m.unpackingStarted && !m.unpackingFinished);
const errors = torrent.downloads.where((m) => m.error != null);
if (unpacking.length > 0) {
const bytesDone = unpacking.sum((m) => m.bytesDone);
const bytesTotal = unpacking.sum((m) => m.bytesTotal);
let progress = (bytesDone / bytesTotal) * 100;
let allSpeeds = unpacking.sum((m) => m.speed) / unpacking.length;
if (allSpeeds > 0) {
return `Extracting (${progress.toFixed(2)}%)`;
if (errors.length > 0) {
return 'Error';
}
}
const queuedForUnpacking = torrent.downloads.where((m) => m.unpackingQueued && !m.unpackingStarted);
const downloading = torrent.downloads.where((m) => m.downloadStarted && !m.downloadFinished);
if (queuedForUnpacking.length > 0) {
return `Queued for unpacking`;
}
if (downloading.length > 0) {
const bytesDone = downloading.sum((m) => m.bytesDone);
const bytesTotal = downloading.sum((m) => m.bytesTotal);
let progress = (bytesDone / bytesTotal) * 100;
let allSpeeds = downloading.sum((m) => m.speed) / downloading.length;
const queuedForDownload = torrent.downloads.where((m) => m.downloadQueued && !m.downloadStarted);
let speed: string | string[] = '0';
if (allSpeeds > 0) {
speed = this.pipe.transform(allSpeeds, 'filesize');
if (queuedForDownload.length > 0) {
return `Queued for downloading`;
}
return `Downloading (${progress.toFixed(2)}% - ${speed}/s)`;
}
}
const unpacked = torrent.downloads.where((m) => m.unpackingFinished != null);
const unpacking = torrent.downloads.where((m) => m.unpackingStarted && !m.unpackingFinished);
if (unpacked.length > 0) {
return `Files unpacked`;
}
if (unpacking.length > 0) {
const bytesDone = unpacking.sum((m) => m.bytesDone);
const bytesTotal = unpacking.sum((m) => m.bytesTotal);
let progress = (bytesDone / bytesTotal) * 100;
let allSpeeds = unpacking.sum((m) => m.speed) / unpacking.length;
const downloaded = torrent.downloads.where((m) => m.downloadFinished != null);
if (allSpeeds > 0) {
return `Extracting (${progress.toFixed(2)}%)`;
}
}
if (downloaded.length > 0) {
return `Files downloaded to host`;
const queuedForUnpacking = torrent.downloads.where((m) => m.unpackingQueued && !m.unpackingStarted);
if (queuedForUnpacking.length > 0) {
return `Queued for unpacking`;
}
const queuedForDownload = torrent.downloads.where((m) => m.downloadQueued && !m.downloadStarted);
if (queuedForDownload.length > 0) {
return `Queued for downloading`;
}
const unpacked = torrent.downloads.where((m) => m.unpackingFinished != null);
if (unpacked.length > 0) {
return `Files unpacked`;
}
const downloaded = torrent.downloads.where((m) => m.downloadFinished != null);
if (downloaded.length > 0) {
return `Files downloaded to host`;
}
}
switch (torrent.rdStatus) {
@ -89,7 +91,7 @@ export class TorrentStatusPipe implements PipeTransform {
case RealDebridStatus.Error:
return `Torrent error: ${torrent.rdStatusRaw}`;
case RealDebridStatus.Finished:
return `Torrent finished`;
return `Torrent finished, waiting to download`;
default:
return 'Unknown status';
}

View file

@ -48,7 +48,7 @@ namespace RdtClient.Data.Data
},
new Setting
{
SettingId = "DownloadFolder",
SettingId = "DownloadPath",
Type = "String",
#if DEBUG
Value = @"C:\Temp\rdtclient"
@ -57,6 +57,16 @@ namespace RdtClient.Data.Data
#endif
},
new Setting
{
SettingId = "MappedPath",
Type = "String",
#if DEBUG
Value = @"C:\Temp\rdtclient"
#else
Value = "D:\Downloads"
#endif
},
new Setting
{
SettingId = "DownloadLimit",
Type = "Int32",
@ -67,6 +77,12 @@ namespace RdtClient.Data.Data
SettingId = "UnpackLimit",
Type = "Int32",
Value = "1"
},
new Setting
{
SettingId = "MinFileSize",
Type = "Int32",
Value = "0"
}
};

View file

@ -213,7 +213,7 @@ namespace RdtClient.Service.Services
public async Task<String> AppDefaultSavePath()
{
var downloadPath = await _settings.GetString("DownloadFolder");
var downloadPath = await _settings.GetString("MappedPath");
downloadPath = downloadPath.TrimEnd('\\')
.TrimEnd('/');
downloadPath += Path.DirectorySeparatorChar;

View file

@ -13,7 +13,7 @@ namespace RdtClient.Service.Services
Task Update(IList<Setting> settings);
Task<String> GetString(String key);
Task<Int32> GetNumber(String key);
Task TestFolder(String folder);
Task TestPath(String path);
}
public class Settings : ISettings
@ -59,21 +59,21 @@ namespace RdtClient.Service.Services
return Int32.Parse(setting.Value);
}
public async Task TestFolder(String folder)
public async Task TestPath(String path)
{
if (String.IsNullOrWhiteSpace(folder))
if (String.IsNullOrWhiteSpace(path))
{
throw new Exception("Folder path is not set");
throw new Exception("Path is not set");
}
folder = folder.TrimEnd('/').TrimEnd('\\');
path = path.TrimEnd('/').TrimEnd('\\');
if (!Directory.Exists(folder))
if (!Directory.Exists(path))
{
throw new Exception($"Folder {folder} does not exist");
throw new Exception($"Path {path} does not exist");
}
var testFile = $"{folder}/test.txt";
var testFile = $"{path}/test.txt";
await File.WriteAllTextAsync(testFile, "RealDebridClient Test File, you can remove this file.");
File.Delete(testFile);

View file

@ -20,12 +20,8 @@ namespace RdtClient.Service.Services
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
#if DEBUG
await Task.Delay(TimeSpan.FromSeconds(3), stoppingToken);
#else
await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
#endif
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
using var scope = _serviceProvider.CreateScope();
var torrentRunner = scope.ServiceProvider.GetRequiredService<ITorrentRunner>();
@ -44,7 +40,7 @@ namespace RdtClient.Service.Services
_logger.LogError(ex, "Unexpected error occurred in TorrentDownloadManager.Tick");
}
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);
}
_logger.LogInformation("TaskRunner stopped.");

View file

@ -61,6 +61,7 @@ namespace RdtClient.Service.Services
public async Task Tick()
{
var settingApiKey = await _settings.GetString("RealDebridApiKey");
var minFileSizeSetting = await _settings.GetNumber("MinFileSize");
if (String.IsNullOrWhiteSpace(settingApiKey))
{
@ -164,6 +165,14 @@ namespace RdtClient.Service.Services
.Select(m => m.Id.ToString())
.ToArray();
if (minFileSizeSetting > 0)
{
fileIds = torrent.Files
.Where(m => m.Bytes * 1024 * 1024 > minFileSizeSetting)
.Select(m => m.Id.ToString())
.ToArray();
}
await _torrents.SelectFiles(torrent.RdId, fileIds);
}

View file

@ -165,9 +165,9 @@ namespace RdtClient.Service.Services
{
if (deleteLocalFiles)
{
var settingDownloadFolder = await _settings.GetString("DownloadFolder");
var settingDownloadPath = await _settings.GetString("DownloadPath");
var torrentPath = Path.Combine(settingDownloadFolder, torrent.RdName);
var torrentPath = Path.Combine(settingDownloadPath, torrent.RdName);
if (Directory.Exists(torrentPath))
{
@ -210,7 +210,7 @@ namespace RdtClient.Service.Services
public async Task Download(Guid downloadId)
{
var settingDownloadLimit = await _settings.GetNumber("DownloadLimit");
var settingDownloadFolder = await _settings.GetString("DownloadFolder");
var settingDownloadPath = await _settings.GetString("DownloadPath");
var download = await _downloads.GetById(downloadId);
@ -224,7 +224,7 @@ namespace RdtClient.Service.Services
await _downloads.UpdateDownloadStarted(download.DownloadId, download.DownloadStarted);
// Start the download process
var downloadClient = new DownloadClient(download, settingDownloadFolder);
var downloadClient = new DownloadClient(download, settingDownloadPath);
if (TorrentRunner.ActiveDownloadClients.TryAdd(downloadId, downloadClient))
{
@ -235,7 +235,7 @@ namespace RdtClient.Service.Services
public async Task Unpack(Guid downloadId)
{
var settingUnpackLimit = await _settings.GetNumber("UnpackLimit");
var settingDownloadFolder = await _settings.GetString("DownloadFolder");
var settingDownloadPath = await _settings.GetString("DownloadPath");
var download = await _downloads.GetById(downloadId);
@ -270,7 +270,7 @@ namespace RdtClient.Service.Services
await _downloads.UpdateUnpackingStarted(download.DownloadId, download.UnpackingStarted);
// Start the unpacking process
var unpackClient = new UnpackClient(download, settingDownloadFolder);
var unpackClient = new UnpackClient(download, settingDownloadPath);
if (TorrentRunner.ActiveUnpackClients.TryAdd(downloadId, unpackClient))
{

View file

@ -49,10 +49,10 @@ namespace RdtClient.Web.Controllers
}
[HttpPost]
[Route("TestFolder")]
public async Task<ActionResult<Profile>> TestFolder([FromBody] SettingsControllerTestFolderRequest request)
[Route("TestPath")]
public async Task<ActionResult<Profile>> TestPath([FromBody] SettingsControllerTestPathRequest request)
{
await _settings.TestFolder(request.Folder);
await _settings.TestPath(request.Path);
return Ok();
}
@ -63,8 +63,8 @@ namespace RdtClient.Web.Controllers
public IList<Setting> Settings { get; set; }
}
public class SettingsControllerTestFolderRequest
public class SettingsControllerTestPathRequest
{
public String Folder { get; set; }
public String Path { get; set; }
}
}