Add retry count as a setting per torrent and global.
Add error status on the torrent itself too. Improved torrent retrying.
This commit is contained in:
parent
a0d000138c
commit
b3dd856410
44 changed files with 2143 additions and 627 deletions
|
|
@ -84,12 +84,43 @@
|
|||
<div class="field">
|
||||
<label class="label">Priority</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number" step="1" [(ngModel)]="priority" />
|
||||
<input class="input" type="number" step="1" [(ngModel)]="priority" />
|
||||
</div>
|
||||
<p class="help">
|
||||
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry downloads</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="number"
|
||||
max="1000"
|
||||
min="0"
|
||||
step="1"
|
||||
[(ngModel)]="downloadRetryAttempts"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">When a single download fails it will retry it this many times before marking it as failed.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry torrent</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="number"
|
||||
max="1000"
|
||||
min="0"
|
||||
step="1"
|
||||
[(ngModel)]="torrentRetryAttempts"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
When a single download has failed multiple times (see setting above) or when the torrent itself received an
|
||||
error it will retry the full torrent this many times before marking it failed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex>
|
||||
<div class="field">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { TorrentService } from 'src/app/torrent.service';
|
||||
import { TorrentFileAvailability } from '../models/torrent.model';
|
||||
import { Torrent, TorrentFileAvailability } from '../models/torrent.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-new-torrent',
|
||||
|
|
@ -21,6 +21,9 @@ export class AddNewTorrentComponent implements OnInit {
|
|||
|
||||
public downloadMinSize: number = 0;
|
||||
|
||||
public downloadRetryAttempts: number = 3;
|
||||
public torrentRetryAttempts: number = 1;
|
||||
|
||||
public availableFiles: TorrentFileAvailability[] = [];
|
||||
public downloadFiles: { [key: string]: boolean } = {};
|
||||
public allSelected: boolean;
|
||||
|
|
@ -91,46 +94,36 @@ export class AddNewTorrentComponent implements OnInit {
|
|||
downloadManualFiles = selectedFiles.join(',');
|
||||
}
|
||||
|
||||
const torrent = new Torrent();
|
||||
torrent.category = this.category;
|
||||
torrent.downloadAction = this.downloadAction;
|
||||
torrent.finishedAction = this.finishedAction;
|
||||
torrent.downloadMinSize = this.downloadMinSize;
|
||||
torrent.downloadManualFiles = downloadManualFiles;
|
||||
torrent.priority = this.priority;
|
||||
torrent.torrentRetryAttempts = this.torrentRetryAttempts;
|
||||
torrent.downloadRetryAttempts = this.downloadRetryAttempts;
|
||||
|
||||
if (this.magnetLink) {
|
||||
this.torrentService
|
||||
.uploadMagnet(
|
||||
this.magnetLink,
|
||||
this.category,
|
||||
this.downloadAction,
|
||||
this.finishedAction,
|
||||
this.downloadMinSize,
|
||||
downloadManualFiles,
|
||||
this.priority
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
this.torrentService.uploadMagnet(this.magnetLink, torrent).subscribe(
|
||||
() => {
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
} else if (this.selectedFile) {
|
||||
this.torrentService
|
||||
.uploadFile(
|
||||
this.selectedFile,
|
||||
this.category,
|
||||
this.downloadAction,
|
||||
this.finishedAction,
|
||||
this.downloadMinSize,
|
||||
downloadManualFiles,
|
||||
this.priority
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
this.torrentService.uploadFile(this.selectedFile, torrent).subscribe(
|
||||
() => {
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.error = 'No magnet or file uploaded';
|
||||
this.saving = false;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ export class Torrent {
|
|||
public isFile: boolean;
|
||||
|
||||
public retryCount: number;
|
||||
public downloadRetryAttempts: number;
|
||||
public torrentRetryAttempts: number;
|
||||
|
||||
public priority: number;
|
||||
public error: string;
|
||||
|
||||
public rdId: string;
|
||||
public rdName: string;
|
||||
|
|
|
|||
|
|
@ -204,6 +204,25 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry downloads</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number" max="1000" min="0" step="1" [(ngModel)]="downloadRetryAttempts" />
|
||||
</div>
|
||||
<p class="help">When a single download fails it will retry it this many times before marking it as failed.</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry torrent</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number" max="1000" min="0" step="1" [(ngModel)]="torrentRetryAttempts" />
|
||||
</div>
|
||||
<p class="help">
|
||||
When a single download has failed multiple times (see setting above) or when the torrent itself received an error
|
||||
it will retry the full torrent this many times before marking it failed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="activeTab === 3">
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ export class SettingsComponent implements OnInit {
|
|||
public aria2cUrl: string;
|
||||
public aria2cSecret: string;
|
||||
|
||||
public downloadRetryAttempts: number;
|
||||
public torrentRetryAttempts: number;
|
||||
|
||||
constructor(private settingsService: SettingsService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
|
@ -69,6 +72,8 @@ export class SettingsComponent implements OnInit {
|
|||
this.settingProxyServer = this.getSetting(results, 'ProxyServer');
|
||||
this.aria2cUrl = this.getSetting(results, 'Aria2cUrl');
|
||||
this.aria2cSecret = this.getSetting(results, 'Aria2cSecret');
|
||||
this.downloadRetryAttempts = parseInt(this.getSetting(results, 'DownloadRetryAttempts'), 10);
|
||||
this.torrentRetryAttempts = parseInt(this.getSetting(results, 'TorrentRetryAttempts'), 10);
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
|
|
@ -141,6 +146,14 @@ export class SettingsComponent implements OnInit {
|
|||
settingId: 'Aria2cSecret',
|
||||
value: this.aria2cSecret,
|
||||
},
|
||||
{
|
||||
settingId: 'DownloadRetryAttempts',
|
||||
value: (this.downloadRetryAttempts ?? 0).toString(),
|
||||
},
|
||||
{
|
||||
settingId: 'TorrentRetryAttempts',
|
||||
value: (this.torrentRetryAttempts ?? 0).toString(),
|
||||
},
|
||||
];
|
||||
|
||||
this.settingsService.update(settings).subscribe(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ export class TorrentStatusPipe implements PipeTransform {
|
|||
constructor(private pipe: FileSizePipe) {}
|
||||
|
||||
transform(torrent: Torrent): string {
|
||||
|
||||
if (torrent.error) {
|
||||
return torrent.error;
|
||||
}
|
||||
|
||||
if (torrent.downloads.length > 0) {
|
||||
const errors = torrent.downloads.where((m) => m.error != null);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,41 +37,17 @@ export class TorrentService {
|
|||
return this.http.get<Torrent>(`/Api/Torrents/Get/${torrentId}`);
|
||||
}
|
||||
|
||||
public uploadMagnet(
|
||||
magnetLink: string,
|
||||
category: string,
|
||||
downloadAction: number,
|
||||
finishedAction: number,
|
||||
downloadMinSize: number,
|
||||
downloadManualFiles: string,
|
||||
priority: number
|
||||
): Observable<void> {
|
||||
public uploadMagnet(magnetLink: string, torrent: Torrent): Observable<void> {
|
||||
return this.http.post<void>(`/Api/Torrents/UploadMagnet`, {
|
||||
magnetLink,
|
||||
category,
|
||||
downloadAction,
|
||||
finishedAction,
|
||||
downloadMinSize,
|
||||
downloadManualFiles,
|
||||
priority,
|
||||
torrent,
|
||||
});
|
||||
}
|
||||
|
||||
public uploadFile(
|
||||
file: File,
|
||||
category: string,
|
||||
downloadAction: number,
|
||||
finishedAction: number,
|
||||
downloadMinSize: number,
|
||||
downloadManualFiles: string,
|
||||
priority: number
|
||||
): Observable<void> {
|
||||
public uploadFile(file: File, torrent: Torrent): Observable<void> {
|
||||
const formData: FormData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append(
|
||||
'formData',
|
||||
JSON.stringify({ category, downloadAction, finishedAction, downloadMinSize, downloadManualFiles, priority })
|
||||
);
|
||||
formData.append('formData', JSON.stringify(torrent));
|
||||
return this.http.post<void>(`/Api/Torrents/UploadFile`, formData);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<button class="button is-primary" (click)="showRetryModal()">Retry Torrent</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-light" (click)="showUpdateSettingsModal()">Change priority</button>
|
||||
<button class="button is-light" (click)="showUpdateSettingsModal()">Change Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Retry count</label>
|
||||
{{ torrent.retryCount }} / 2
|
||||
{{ torrent.retryCount }} / {{ torrent.torrentRetryAttempts}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Hash</label>
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Retry Count</label>
|
||||
{{ download.retryCount }} / 3
|
||||
{{ download.retryCount }} / {{ torrent.downloadRetryAttempts }}
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex>
|
||||
|
|
@ -470,6 +470,37 @@
|
|||
Set the priority for this torrent where 1 is the highest. When empty it will be assigned the lowest priority.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry downloads</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="number"
|
||||
max="1000"
|
||||
min="0"
|
||||
step="1"
|
||||
[(ngModel)]="updateSettingsDownloadRetryAttempts"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">When a single download fails it will retry it this many times before marking it as failed.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Automatic retry torrent</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="number"
|
||||
max="1000"
|
||||
min="0"
|
||||
step="1"
|
||||
[(ngModel)]="updateSettingsTorrentRetryAttempts"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
When a single download has failed multiple times (see setting above) or when the torrent itself received an
|
||||
error it will retry the full torrent this many times before marking it failed.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="modal-card-foot">
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ export class TorrentComponent implements OnInit {
|
|||
|
||||
public isUpdateSettingsModalActive: boolean;
|
||||
public updateSettingsPriority: number;
|
||||
public updateSettingsDownloadRetryAttempts: number;
|
||||
public updateSettingsTorrentRetryAttempts: number;
|
||||
public updating: boolean;
|
||||
|
||||
constructor(private activatedRoute: ActivatedRoute, private router: Router, private torrentService: TorrentService) {}
|
||||
|
|
@ -170,6 +172,8 @@ export class TorrentComponent implements OnInit {
|
|||
|
||||
public showUpdateSettingsModal(): void {
|
||||
this.updateSettingsPriority = this.torrent.priority;
|
||||
this.updateSettingsDownloadRetryAttempts = this.torrent.downloadRetryAttempts;
|
||||
this.updateSettingsTorrentRetryAttempts = this.torrent.torrentRetryAttempts;
|
||||
|
||||
this.isUpdateSettingsModalActive = true;
|
||||
}
|
||||
|
|
@ -182,6 +186,8 @@ export class TorrentComponent implements OnInit {
|
|||
this.updating = true;
|
||||
|
||||
this.torrent.priority = this.updateSettingsPriority;
|
||||
this.torrent.downloadRetryAttempts = this.updateSettingsDownloadRetryAttempts;
|
||||
this.torrent.torrentRetryAttempts = this.updateSettingsTorrentRetryAttempts;
|
||||
|
||||
this.torrentService.update(this.torrent).subscribe(
|
||||
() => {
|
||||
|
|
|
|||
|
|
@ -147,6 +147,18 @@ namespace RdtClient.Data.Data
|
|||
SettingId = "Aria2cSecret",
|
||||
Type = "String",
|
||||
Value = ""
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "DownloadRetryAttempts",
|
||||
Type = "Int32",
|
||||
Value = "3"
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "TorrentRetryAttempts",
|
||||
Type = "Int32",
|
||||
Value = "1"
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ namespace RdtClient.Data.Data
|
|||
Categories = GetString("Categories"),
|
||||
Aria2cUrl = GetString("Aria2cUrl"),
|
||||
Aria2cSecret = GetString("Aria2cSecret"),
|
||||
DownloadRetryAttempts = GetInt32("DownloadRetryAttempts"),
|
||||
TorrentRetryAttempts = GetInt32("TorrentRetryAttempts")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RdtClient.Data.Enums;
|
||||
using RdtClient.Data.Models.Data;
|
||||
|
||||
namespace RdtClient.Data.Data
|
||||
|
|
@ -12,7 +11,7 @@ namespace RdtClient.Data.Data
|
|||
public class TorrentData
|
||||
{
|
||||
private static IList<Torrent> _torrentCache;
|
||||
private static readonly SemaphoreSlim _torrentCacheLock = new(1);
|
||||
private static readonly SemaphoreSlim TorrentCacheLock = new(1, 1);
|
||||
|
||||
private readonly DataContext _dataContext;
|
||||
|
||||
|
|
@ -23,7 +22,7 @@ namespace RdtClient.Data.Data
|
|||
|
||||
public async Task<IList<Torrent>> Get()
|
||||
{
|
||||
await _torrentCacheLock.WaitAsync();
|
||||
await TorrentCacheLock.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -36,7 +35,7 @@ namespace RdtClient.Data.Data
|
|||
}
|
||||
finally
|
||||
{
|
||||
_torrentCacheLock.Release();
|
||||
TorrentCacheLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,38 +81,35 @@ namespace RdtClient.Data.Data
|
|||
|
||||
public async Task<Torrent> Add(String realDebridId,
|
||||
String hash,
|
||||
String category,
|
||||
TorrentDownloadAction downloadAction,
|
||||
TorrentFinishedAction finishedAction,
|
||||
Int32 downloadMinSize,
|
||||
String downloadManualFiles,
|
||||
String fileOrMagnetContents,
|
||||
Boolean isFile,
|
||||
Int32? priority)
|
||||
Torrent torrent)
|
||||
{
|
||||
var torrent = new Torrent
|
||||
var newTorrent = new Torrent
|
||||
{
|
||||
TorrentId = Guid.NewGuid(),
|
||||
Added = DateTimeOffset.UtcNow,
|
||||
RdId = realDebridId,
|
||||
Hash = hash.ToLower(),
|
||||
Category = category,
|
||||
DownloadAction = downloadAction,
|
||||
FinishedAction = finishedAction,
|
||||
DownloadMinSize = downloadMinSize,
|
||||
DownloadManualFiles = downloadManualFiles,
|
||||
Category = torrent.Category,
|
||||
DownloadAction = torrent.DownloadAction,
|
||||
FinishedAction = torrent.FinishedAction,
|
||||
DownloadMinSize = torrent.DownloadMinSize,
|
||||
DownloadManualFiles = torrent.DownloadManualFiles,
|
||||
FileOrMagnet = fileOrMagnetContents,
|
||||
IsFile = isFile,
|
||||
Priority = priority
|
||||
Priority = torrent.Priority,
|
||||
TorrentRetryAttempts = torrent.TorrentRetryAttempts,
|
||||
DownloadRetryAttempts = torrent.DownloadRetryAttempts
|
||||
};
|
||||
|
||||
await _dataContext.Torrents.AddAsync(torrent);
|
||||
await _dataContext.Torrents.AddAsync(newTorrent);
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
await VoidCache();
|
||||
|
||||
return torrent;
|
||||
return newTorrent;
|
||||
}
|
||||
|
||||
public async Task UpdateRdData(Torrent torrent)
|
||||
|
|
@ -157,6 +153,8 @@ namespace RdtClient.Data.Data
|
|||
}
|
||||
|
||||
dbTorrent.Priority = torrent.Priority;
|
||||
dbTorrent.DownloadRetryAttempts = torrent.DownloadRetryAttempts;
|
||||
dbTorrent.TorrentRetryAttempts = torrent.TorrentRetryAttempts;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
|
|
@ -179,7 +177,7 @@ namespace RdtClient.Data.Data
|
|||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdateComplete(Guid torrentId, DateTimeOffset? datetime)
|
||||
public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset? datetime)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
||||
|
|
@ -188,7 +186,28 @@ namespace RdtClient.Data.Data
|
|||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
var downloads = await _dataContext.Downloads.AsNoTracking().Where(m => m.TorrentId == torrentId).ToListAsync();
|
||||
var downloadWithErrors = downloads.Where(m => !String.IsNullOrWhiteSpace(m.Error)).ToList();
|
||||
|
||||
if (downloads.Any())
|
||||
{
|
||||
error = $"{downloadWithErrors.Count}/{downloads.Count} downloads failed with errors";
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
if (dbTorrent.RetryCount < dbTorrent.TorrentRetryAttempts)
|
||||
{
|
||||
dbTorrent.RetryCount += 1;
|
||||
dbTorrent.Retry = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
dbTorrent.Completed = datetime;
|
||||
dbTorrent.Error = error;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
|
|
@ -211,22 +230,6 @@ namespace RdtClient.Data.Data
|
|||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdateRetryCount(Guid torrentId, Int32 retryCount)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
||||
if (dbTorrent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dbTorrent.RetryCount = retryCount;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdatePriority(Guid torrentId, Int32? priority)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
|
@ -243,6 +246,39 @@ namespace RdtClient.Data.Data
|
|||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdateRetry(Guid torrentId, DateTimeOffset? dateTime, Int32 retryCount)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
||||
if (dbTorrent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dbTorrent.RetryCount = retryCount;
|
||||
dbTorrent.Retry = dateTime;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdateError(Guid torrentId, String error)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
||||
if (dbTorrent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dbTorrent.Error = error;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
|
||||
await VoidCache();
|
||||
}
|
||||
|
||||
public async Task Delete(Guid torrentId)
|
||||
{
|
||||
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
|
||||
|
|
@ -261,7 +297,7 @@ namespace RdtClient.Data.Data
|
|||
|
||||
public static async Task VoidCache()
|
||||
{
|
||||
await _torrentCacheLock.WaitAsync();
|
||||
await TorrentCacheLock.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -269,7 +305,7 @@ namespace RdtClient.Data.Data
|
|||
}
|
||||
finally
|
||||
{
|
||||
_torrentCacheLock.Release();
|
||||
TorrentCacheLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
445
server/RdtClient.Data/Migrations/20211029131846_Torrents_Add_Retry.Designer.cs
generated
Normal file
445
server/RdtClient.Data/Migrations/20211029131846_Torrents_Add_Retry.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using RdtClient.Data.Data;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20211029131846_Torrents_Add_Retry")]
|
||||
partial class Torrents_Add_Retry
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.Property<Guid>("DownloadId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Link")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RemoteId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("TorrentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("DownloadId");
|
||||
|
||||
b.HasIndex("TorrentId");
|
||||
|
||||
b.ToTable("Downloads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Setting", b =>
|
||||
{
|
||||
b.Property<string>("SettingId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SettingId");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Property<Guid>("TorrentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DownloadManualFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadMinSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FileOrMagnet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("FilesSelected")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("FinishedAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsFile")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Priority")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("RdAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("RdEnded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdHost")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("RdProgress")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSeeders")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSpeed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSplit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RdStatus")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("RdStatusRaw")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Retry")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("TorrentId");
|
||||
|
||||
b.ToTable("Torrents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.HasOne("RdtClient.Data.Models.Data.Torrent", "Torrent")
|
||||
.WithMany("Downloads")
|
||||
.HasForeignKey("TorrentId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Torrent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Navigation("Downloads");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
public partial class Torrents_Add_Retry : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "Retry",
|
||||
table: "Torrents",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Retry",
|
||||
table: "Torrents");
|
||||
}
|
||||
}
|
||||
}
|
||||
448
server/RdtClient.Data/Migrations/20211029133429_Torrents_Error.Designer.cs
generated
Normal file
448
server/RdtClient.Data/Migrations/20211029133429_Torrents_Error.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using RdtClient.Data.Data;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20211029133429_Torrents_Error")]
|
||||
partial class Torrents_Error
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.Property<Guid>("DownloadId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Link")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RemoteId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("TorrentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("DownloadId");
|
||||
|
||||
b.HasIndex("TorrentId");
|
||||
|
||||
b.ToTable("Downloads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Setting", b =>
|
||||
{
|
||||
b.Property<string>("SettingId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SettingId");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Property<Guid>("TorrentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DownloadManualFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadMinSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FileOrMagnet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("FilesSelected")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("FinishedAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsFile")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Priority")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("RdAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("RdEnded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdHost")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("RdProgress")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSeeders")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSpeed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSplit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RdStatus")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("RdStatusRaw")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Retry")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("TorrentId");
|
||||
|
||||
b.ToTable("Torrents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.HasOne("RdtClient.Data.Models.Data.Torrent", "Torrent")
|
||||
.WithMany("Downloads")
|
||||
.HasForeignKey("TorrentId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Torrent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Navigation("Downloads");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
public partial class Torrents_Error : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Error",
|
||||
table: "Torrents",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Error",
|
||||
table: "Torrents");
|
||||
}
|
||||
}
|
||||
}
|
||||
454
server/RdtClient.Data/Migrations/20211029142739_Torrents_Add_RetryAttempts.Designer.cs
generated
Normal file
454
server/RdtClient.Data/Migrations/20211029142739_Torrents_Add_RetryAttempts.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using RdtClient.Data.Data;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20211029142739_Torrents_Add_RetryAttempts")]
|
||||
partial class Torrents_Add_RetryAttempts
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.Property<Guid>("DownloadId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("DownloadStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Link")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RemoteId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("TorrentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingFinished")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingQueued")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnpackingStarted")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("DownloadId");
|
||||
|
||||
b.HasIndex("TorrentId");
|
||||
|
||||
b.ToTable("Downloads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Setting", b =>
|
||||
{
|
||||
b.Property<string>("SettingId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SettingId");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Property<Guid>("TorrentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("Added")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DownloadManualFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadMinSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DownloadRetryAttempts")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FileOrMagnet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("FilesSelected")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("FinishedAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsFile")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Priority")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("RdAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("RdEnded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdHost")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RdName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("RdProgress")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSeeders")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("RdSpeed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("RdSplit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RdStatus")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("RdStatusRaw")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Retry")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("TorrentRetryAttempts")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("TorrentId");
|
||||
|
||||
b.ToTable("Torrents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
|
||||
{
|
||||
b.HasOne("RdtClient.Data.Models.Data.Torrent", "Torrent")
|
||||
.WithMany("Downloads")
|
||||
.HasForeignKey("TorrentId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Torrent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
|
||||
{
|
||||
b.Navigation("Downloads");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
public partial class Torrents_Add_RetryAttempts : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "DownloadRetryAttempts",
|
||||
table: "Torrents",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "TorrentRetryAttempts",
|
||||
table: "Torrents",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DownloadRetryAttempts",
|
||||
table: "Torrents");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TorrentRetryAttempts",
|
||||
table: "Torrents");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ namespace RdtClient.Data.Migrations
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.10");
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
|
|
@ -303,6 +303,12 @@ namespace RdtClient.Data.Migrations
|
|||
b.Property<int>("DownloadMinSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DownloadRetryAttempts")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Error")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FileOrMagnet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
|
|
@ -360,9 +366,15 @@ namespace RdtClient.Data.Migrations
|
|||
b.Property<string>("RdStatusRaw")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Retry")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("TorrentRetryAttempts")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("TorrentId");
|
||||
|
||||
b.ToTable("Torrents");
|
||||
|
|
|
|||
|
|
@ -11,24 +11,19 @@ namespace RdtClient.Data.Models.Data
|
|||
|
||||
public Guid TorrentId { get; set; }
|
||||
|
||||
public String Path { get; set; }
|
||||
[ForeignKey("TorrentId")]
|
||||
public Torrent Torrent { get; set; }
|
||||
|
||||
public String Path { get; set; }
|
||||
public String Link { get; set; }
|
||||
|
||||
public DateTimeOffset Added { get; set; }
|
||||
|
||||
public DateTimeOffset? DownloadQueued { get; set; }
|
||||
|
||||
public DateTimeOffset? DownloadStarted { get; set; }
|
||||
|
||||
public DateTimeOffset? DownloadFinished { get; set; }
|
||||
|
||||
public DateTimeOffset? UnpackingQueued { get; set; }
|
||||
|
||||
public DateTimeOffset? UnpackingStarted { get; set; }
|
||||
|
||||
public DateTimeOffset? UnpackingFinished { get; set; }
|
||||
|
||||
public DateTimeOffset? Completed { get; set; }
|
||||
|
||||
public Int32 RetryCount { get; set; }
|
||||
|
|
@ -37,9 +32,6 @@ namespace RdtClient.Data.Models.Data
|
|||
|
||||
public String RemoteId { get; set; }
|
||||
|
||||
[ForeignKey("TorrentId")]
|
||||
public Torrent Torrent { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public Int64 BytesTotal { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Newtonsoft.Json;
|
||||
using RDNET;
|
||||
using RdtClient.Data.Enums;
|
||||
using RdtClient.Data.Models.TorrentClient;
|
||||
|
||||
namespace RdtClient.Data.Models.Data
|
||||
{
|
||||
|
|
@ -25,12 +25,17 @@ namespace RdtClient.Data.Models.Data
|
|||
public DateTimeOffset Added { get; set; }
|
||||
public DateTimeOffset? FilesSelected { get; set; }
|
||||
public DateTimeOffset? Completed { get; set; }
|
||||
public DateTimeOffset? Retry { get; set; }
|
||||
|
||||
public String FileOrMagnet { get; set; }
|
||||
public Boolean IsFile { get; set; }
|
||||
|
||||
public Int32? Priority { get; set; }
|
||||
public Int32 RetryCount { get; set; }
|
||||
public Int32 DownloadRetryAttempts { get; set; }
|
||||
public Int32 TorrentRetryAttempts { get; set; }
|
||||
|
||||
public String Error { get; set; }
|
||||
|
||||
[InverseProperty("Torrent")]
|
||||
public IList<Download> Downloads { get; set; }
|
||||
|
|
@ -50,22 +55,22 @@ namespace RdtClient.Data.Models.Data
|
|||
public String RdFiles { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public IList<TorrentFile> Files
|
||||
public IList<TorrentClientFile> Files
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(RdFiles))
|
||||
{
|
||||
return new List<TorrentFile>();
|
||||
return new List<TorrentClientFile>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<List<TorrentFile>>(RdFiles);
|
||||
return JsonConvert.DeserializeObject<List<TorrentClientFile>>(RdFiles);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<TorrentFile>();
|
||||
return new List<TorrentClientFile>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,5 +20,7 @@ namespace RdtClient.Data.Models.Internal
|
|||
public String Categories { get; set; }
|
||||
public String Aria2cUrl { get; set; }
|
||||
public String Aria2cSecret { get; set; }
|
||||
public Int32 DownloadRetryAttempts { get; set; }
|
||||
public Int32 TorrentRetryAttempts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace RdtClient.Service.Models
|
||||
namespace RdtClient.Data.Models.Internal
|
||||
{
|
||||
public class Profile
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
public class AppBuildInfo
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
namespace QuickType
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
public class TorrentCategory
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
public class TorrentFileItem
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
namespace QuickType
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RdtClient.Service.Models.QBittorrent
|
||||
namespace RdtClient.Data.Models.QBittorrent
|
||||
{
|
||||
public class TorrentProperties
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace RdtClient.Service.Models.TorrentClient
|
||||
namespace RdtClient.Data.Models.TorrentClient
|
||||
{
|
||||
public class TorrentClientAvailableFile
|
||||
{
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace RdtClient.Data.Models.TorrentClient
|
||||
{
|
||||
public class TorrentClientFile
|
||||
{
|
||||
public Int64 Id { get; set; }
|
||||
public String Path { get; set; }
|
||||
public Int64 Bytes { get; set; }
|
||||
public Boolean Selected { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RdtClient.Service.Models.TorrentClient
|
||||
namespace RdtClient.Data.Models.TorrentClient
|
||||
{
|
||||
public class TorrentClientTorrent
|
||||
{
|
||||
|
|
@ -16,18 +16,10 @@ namespace RdtClient.Service.Models.TorrentClient
|
|||
public Int64 Progress { get; set; }
|
||||
public String Status { get; set; }
|
||||
public DateTimeOffset Added { get; set; }
|
||||
public List<TorrentClientTorrentFile> Files { get; set; }
|
||||
public List<TorrentClientFile> Files { get; set; }
|
||||
public List<String> Links { get; set; }
|
||||
public DateTimeOffset? Ended { get; set; }
|
||||
public Int64? Speed { get; set; }
|
||||
public Int64? Seeders { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentClientTorrentFile
|
||||
{
|
||||
public Int64 Id { get; set; }
|
||||
public String Path { get; set; }
|
||||
public Int64 Bytes { get; set; }
|
||||
public Boolean Selected { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace RdtClient.Service.Models.TorrentClient
|
||||
namespace RdtClient.Data.Models.TorrentClient
|
||||
{
|
||||
public class TorrentClientUser
|
||||
{
|
||||
|
|
@ -14,14 +14,7 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="RD.NET" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="RDNET">
|
||||
<HintPath>..\libs\RDNET.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AllDebrid.NET" Version="1.0.1" />
|
||||
<PackageReference Include="Aria2.NET" Version="1.0.4" />
|
||||
<PackageReference Include="Downloader" Version="2.2.9" />
|
||||
<PackageReference Include="MonoTorrent" Version="2.0.0" />
|
||||
<PackageReference Include="MonoTorrent" Version="2.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="RD.NET" Version="2.1.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using RdtClient.Data.Enums;
|
||||
using RdtClient.Service.Models.QBittorrent;
|
||||
using RdtClient.Service.Models.QBittorrent.QuickType;
|
||||
using RdtClient.Data.Models.Data;
|
||||
using RdtClient.Data.Models.QBittorrent;
|
||||
using RdtClient.Data.Models.QBittorrent.QuickType;
|
||||
|
||||
namespace RdtClient.Service.Services
|
||||
{
|
||||
|
|
@ -293,7 +294,15 @@ namespace RdtClient.Service.Services
|
|||
Upspeed = speed
|
||||
};
|
||||
|
||||
if (torrent.Completed.HasValue)
|
||||
if (torrent.Retry != null)
|
||||
{
|
||||
result.State = "downloading";
|
||||
}
|
||||
else if (!String.IsNullOrWhiteSpace(torrent.Error))
|
||||
{
|
||||
result.State = torrent.Error;
|
||||
}
|
||||
else if (torrent.Completed.HasValue)
|
||||
{
|
||||
var allDownloadsComplete = torrent.Downloads.All(m => m.Completed.HasValue);
|
||||
var hasDownloadsWithErrors = torrent.Downloads.Any(m => m.Error != null);
|
||||
|
|
@ -419,16 +428,34 @@ namespace RdtClient.Service.Services
|
|||
|
||||
public async Task TorrentsAddMagnet(String magnetLink, String category, Int32? priority)
|
||||
{
|
||||
var downloadAction = Settings.Get.OnlyDownloadAvailableFiles == 1 ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll;
|
||||
var torrent = new Torrent
|
||||
{
|
||||
Category = category,
|
||||
DownloadAction = Settings.Get.OnlyDownloadAvailableFiles == 1 ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
|
||||
FinishedAction = TorrentFinishedAction.None,
|
||||
DownloadMinSize = Settings.Get.MinFileSize,
|
||||
TorrentRetryAttempts = Settings.Get.TorrentRetryAttempts,
|
||||
DownloadRetryAttempts = Settings.Get.DownloadRetryAttempts,
|
||||
Priority = priority
|
||||
};
|
||||
|
||||
await _torrents.UploadMagnet(magnetLink, category, downloadAction, TorrentFinishedAction.None, Settings.Get.MinFileSize, null, priority);
|
||||
await _torrents.UploadMagnet(magnetLink, torrent);
|
||||
}
|
||||
|
||||
public async Task TorrentsAddFile(Byte[] fileBytes, String category, Int32? priority)
|
||||
{
|
||||
var downloadAction = Settings.Get.OnlyDownloadAvailableFiles == 1 ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll;
|
||||
var torrent = new Torrent
|
||||
{
|
||||
Category = category,
|
||||
DownloadAction = Settings.Get.OnlyDownloadAvailableFiles == 1 ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
|
||||
FinishedAction = TorrentFinishedAction.None,
|
||||
DownloadMinSize = Settings.Get.MinFileSize,
|
||||
TorrentRetryAttempts = Settings.Get.TorrentRetryAttempts,
|
||||
DownloadRetryAttempts = Settings.Get.DownloadRetryAttempts,
|
||||
Priority = priority
|
||||
};
|
||||
|
||||
await _torrents.UploadFile(fileBytes, category, downloadAction, TorrentFinishedAction.None, Settings.Get.MinFileSize, null, priority);
|
||||
await _torrents.UploadFile(fileBytes, torrent);
|
||||
}
|
||||
|
||||
public async Task TorrentsSetCategory(String hash, String category)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using RDNET;
|
||||
using RdtClient.Service.Models.TorrentClient;
|
||||
using AllDebridNET;
|
||||
using RdtClient.Data.Models.TorrentClient;
|
||||
|
||||
namespace RdtClient.Service.Services.TorrentClients
|
||||
{
|
||||
|
|
@ -17,139 +17,110 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
private RdNetClient GetRdNetClient()
|
||||
private AllDebridNETClient GetClient()
|
||||
{
|
||||
var apiKey = Settings.Get.RealDebridApiKey;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(apiKey))
|
||||
{
|
||||
throw new Exception("Real-Debrid API Key not set in the settings");
|
||||
throw new Exception("All-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);
|
||||
var allDebridNetClient = new AllDebridNETClient("RealDebridClient", apiKey);
|
||||
|
||||
return rdtNetClient;
|
||||
return allDebridNetClient;
|
||||
}
|
||||
|
||||
private static TorrentClientTorrent Map(Torrent torrent)
|
||||
private static TorrentClientTorrent Map(Magnet torrent)
|
||||
{
|
||||
return new TorrentClientTorrent
|
||||
{
|
||||
Id = torrent.Id,
|
||||
Id = torrent.Id.ToString(),
|
||||
Filename = torrent.Filename,
|
||||
OriginalFilename = torrent.OriginalFilename,
|
||||
OriginalFilename = torrent.Filename,
|
||||
Hash = torrent.Hash,
|
||||
Bytes = torrent.Bytes,
|
||||
OriginalBytes = torrent.OriginalBytes,
|
||||
Host = torrent.Host,
|
||||
Split = torrent.Split,
|
||||
Progress = torrent.Progress,
|
||||
Bytes = torrent.Size,
|
||||
OriginalBytes = torrent.Size,
|
||||
Host = null,
|
||||
Split = 0,
|
||||
Progress = torrent.ProcessingPerc,
|
||||
Status = torrent.Status,
|
||||
Added = torrent.Added,
|
||||
Files = (torrent.Files ?? new List<TorrentFile>()).Select(m => new TorrentClientTorrentFile
|
||||
Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate),
|
||||
Files = (torrent.Links ?? new List<Link>()).Select(m => new TorrentClientFile
|
||||
{
|
||||
Path = m.Path,
|
||||
Bytes = m.Bytes,
|
||||
Id = m.Id,
|
||||
Selected = m.Selected
|
||||
Path = m.Filename,
|
||||
Bytes = m.Size,
|
||||
Id = 0,
|
||||
Selected = true
|
||||
}).ToList(),
|
||||
Links = torrent.Links,
|
||||
Ended = torrent.Ended,
|
||||
Speed = torrent.Speed,
|
||||
Seeders = torrent.Seeders,
|
||||
Links = (torrent.Links ?? new List<Link>()).Select(m => m.LinkUrl.ToString()).ToList(),
|
||||
Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate),
|
||||
Speed = torrent.DownloadSpeed,
|
||||
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;
|
||||
}
|
||||
|
||||
var results = await GetClient().Magnet.StatusAllAsync();
|
||||
return results.Select(Map).ToList();
|
||||
}
|
||||
|
||||
public async Task<TorrentClientUser> GetUser()
|
||||
{
|
||||
var user = await GetRdNetClient().User.GetAsync();
|
||||
var user = await GetClient().User.GetAsync();
|
||||
|
||||
return new TorrentClientUser
|
||||
{
|
||||
Username = user.Username,
|
||||
Expiration = user.Expiration
|
||||
Expiration = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(user.PremiumUntil)
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<String> AddMagnet(String magnetLink)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.AddMagnetAsync(magnetLink);
|
||||
var result = await GetClient().Magnet.UploadMagnetAsync(magnetLink);
|
||||
|
||||
return result.Id;
|
||||
return result.Id.ToString();
|
||||
}
|
||||
|
||||
public async Task<String> AddFile(Byte[] bytes)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.AddFileAsync(bytes);
|
||||
var result = await GetClient().Magnet.UploadFileAsync(bytes);
|
||||
|
||||
return result.Id;
|
||||
return result.Id.ToString();
|
||||
}
|
||||
|
||||
public async Task<List<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||
public 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;
|
||||
return Task.FromResult(new List<TorrentClientAvailableFile>());
|
||||
}
|
||||
|
||||
public async Task SelectFiles(String torrentId, IList<String> fileIds)
|
||||
public Task SelectFiles(String torrentId, IList<String> fileIds)
|
||||
{
|
||||
await GetRdNetClient().Torrents.SelectFilesAsync(torrentId, fileIds.ToArray());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.GetInfoAsync(torrentId);
|
||||
var result = await GetClient().Magnet.StatusAsync(torrentId);
|
||||
|
||||
return Map(result);
|
||||
}
|
||||
|
||||
public async Task Delete(String torrentId)
|
||||
{
|
||||
await GetRdNetClient().Torrents.DeleteAsync(torrentId);
|
||||
await GetClient().Magnet.DeleteAsync(torrentId);
|
||||
}
|
||||
|
||||
public async Task<String> Unrestrict(String link)
|
||||
{
|
||||
var result = await GetRdNetClient().Unrestrict.LinkAsync(link);
|
||||
var result = await GetClient().Links.DownloadLinkAsync(link);
|
||||
|
||||
return result.Download;
|
||||
return result.Link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using RdtClient.Service.Models.TorrentClient;
|
||||
using RdtClient.Data.Models.TorrentClient;
|
||||
|
||||
namespace RdtClient.Service.Services.TorrentClients
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using RDNET;
|
||||
using RdtClient.Service.Models.TorrentClient;
|
||||
using RdtClient.Data.Models.TorrentClient;
|
||||
|
||||
namespace RdtClient.Service.Services.TorrentClients
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
private RdNetClient GetRdNetClient()
|
||||
private RdNetClient GetClient()
|
||||
{
|
||||
var apiKey = Settings.Get.RealDebridApiKey;
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
Progress = torrent.Progress,
|
||||
Status = torrent.Status,
|
||||
Added = torrent.Added,
|
||||
Files = (torrent.Files ?? new List<TorrentFile>()).Select(m => new TorrentClientTorrentFile
|
||||
Files = (torrent.Files ?? new List<TorrentFile>()).Select(m => new TorrentClientFile
|
||||
{
|
||||
Path = m.Path,
|
||||
Bytes = m.Bytes,
|
||||
|
|
@ -71,7 +71,7 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
|
||||
while (true)
|
||||
{
|
||||
var pagedResults = await GetRdNetClient().Torrents.GetAsync(page, 100);
|
||||
var pagedResults = await GetClient().Torrents.GetAsync(page, 100);
|
||||
|
||||
results.AddRange(pagedResults);
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
|
||||
public async Task<TorrentClientUser> GetUser()
|
||||
{
|
||||
var user = await GetRdNetClient().User.GetAsync();
|
||||
var user = await GetClient().User.GetAsync();
|
||||
|
||||
return new TorrentClientUser
|
||||
{
|
||||
|
|
@ -99,21 +99,21 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
|
||||
public async Task<String> AddMagnet(String magnetLink)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.AddMagnetAsync(magnetLink);
|
||||
var result = await GetClient().Torrents.AddMagnetAsync(magnetLink);
|
||||
|
||||
return result.Id;
|
||||
}
|
||||
|
||||
public async Task<String> AddFile(Byte[] bytes)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.AddFileAsync(bytes);
|
||||
var result = await GetClient().Torrents.AddFileAsync(bytes);
|
||||
|
||||
return result.Id;
|
||||
}
|
||||
|
||||
public async Task<List<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.GetAvailableFiles(hash);
|
||||
var result = await GetClient().Torrents.GetAvailableFiles(hash);
|
||||
|
||||
var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values);
|
||||
|
||||
|
|
@ -130,24 +130,24 @@ namespace RdtClient.Service.Services.TorrentClients
|
|||
|
||||
public async Task SelectFiles(String torrentId, IList<String> fileIds)
|
||||
{
|
||||
await GetRdNetClient().Torrents.SelectFilesAsync(torrentId, fileIds.ToArray());
|
||||
await GetClient().Torrents.SelectFilesAsync(torrentId, fileIds.ToArray());
|
||||
}
|
||||
|
||||
public async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||
{
|
||||
var result = await GetRdNetClient().Torrents.GetInfoAsync(torrentId);
|
||||
var result = await GetClient().Torrents.GetInfoAsync(torrentId);
|
||||
|
||||
return Map(result);
|
||||
}
|
||||
|
||||
public async Task Delete(String torrentId)
|
||||
{
|
||||
await GetRdNetClient().Torrents.DeleteAsync(torrentId);
|
||||
await GetClient().Torrents.DeleteAsync(torrentId);
|
||||
}
|
||||
|
||||
public async Task<String> Unrestrict(String link)
|
||||
{
|
||||
var result = await GetRdNetClient().Unrestrict.LinkAsync(link);
|
||||
var result = await GetClient().Unrestrict.LinkAsync(link);
|
||||
|
||||
return result.Download;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,9 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Aria2NET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using RdtClient.Data.Enums;
|
||||
|
|
@ -21,27 +19,20 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
public class TorrentRunner
|
||||
{
|
||||
private const Int32 DownloadRetryCount = 3;
|
||||
private const Int32 TorrentRetryCount = 2;
|
||||
|
||||
private static DateTime _nextUpdate = DateTime.UtcNow;
|
||||
|
||||
public static readonly ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients = new();
|
||||
public static readonly ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients = new();
|
||||
|
||||
public static readonly SemaphoreSlim TorrentResetLock = new(1, 1);
|
||||
|
||||
private readonly ILogger<TorrentRunner> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly Torrents _torrents;
|
||||
private readonly Downloads _downloads;
|
||||
private readonly RemoteService _remoteService;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public TorrentRunner(ILogger<TorrentRunner> logger, IServiceProvider serviceProvider, Torrents torrents, Downloads downloads, RemoteService remoteService)
|
||||
public TorrentRunner(ILogger<TorrentRunner> logger, Torrents torrents, Downloads downloads, RemoteService remoteService)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_torrents = torrents;
|
||||
_downloads = downloads;
|
||||
_remoteService = remoteService;
|
||||
|
|
@ -174,38 +165,22 @@ namespace RdtClient.Service.Services
|
|||
|
||||
Log("Processing download", download, download.Torrent);
|
||||
|
||||
if (downloadClient.Error != null)
|
||||
if (!String.IsNullOrWhiteSpace(downloadClient.Error))
|
||||
{
|
||||
// Retry the download if an error is encountered.
|
||||
Log($"Download reported an error: {downloadClient.Error}", download, download.Torrent);
|
||||
Log($"Download retry count {download.RetryCount}/{DownloadRetryCount}, torrent retry count {download.Torrent.RetryCount}/{TorrentRetryCount}", download, download.Torrent);
|
||||
Log($"Download retry count {download.RetryCount}/{download.Torrent.DownloadRetryAttempts}, torrent retry count {download.Torrent.RetryCount}/{download.Torrent.TorrentRetryAttempts}", download, download.Torrent);
|
||||
|
||||
if (download.RetryCount < DownloadRetryCount)
|
||||
if (download.RetryCount < download.Torrent.DownloadRetryAttempts)
|
||||
{
|
||||
Log($"Retrying download", download, download.Torrent);
|
||||
|
||||
await _downloads.Reset(downloadId);
|
||||
await _downloads.UpdateRetryCount(downloadId, download.RetryCount + 1);
|
||||
}
|
||||
else if (download.Torrent.RetryCount < TorrentRetryCount)
|
||||
{
|
||||
Log($"Retrying torrent", download, download.Torrent);
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
using var blockScope = _serviceProvider.CreateScope();
|
||||
var torrentsService = (Torrents) blockScope.ServiceProvider.GetService(typeof(Torrents));
|
||||
await torrentsService.RetryTorrent(download.TorrentId, download.Torrent.RetryCount + 1);
|
||||
});
|
||||
|
||||
// Force a delay and return the main loop to prevent concurrency issues.
|
||||
await Task.Delay(10000);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Not retrying", download, download.Torrent);
|
||||
Log($"Not retrying download", download, download.Torrent);
|
||||
|
||||
await _downloads.UpdateError(downloadId, downloadClient.Error);
|
||||
await _downloads.UpdateCompleted(downloadId, DateTimeOffset.UtcNow);
|
||||
|
|
@ -268,6 +243,29 @@ namespace RdtClient.Service.Services
|
|||
|
||||
var torrents = await _torrents.Get();
|
||||
|
||||
// Process torrent retries
|
||||
foreach (var torrent in torrents.Where(m => m.Retry != null))
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogDebug($"Retrying torrent {torrent.RetryCount}/{torrent.TorrentRetryAttempts}", torrent);
|
||||
|
||||
if (torrent.RetryCount > torrent.TorrentRetryAttempts)
|
||||
{
|
||||
await _torrents.UpdateRetry(torrent.TorrentId, null, torrent.RetryCount);
|
||||
_logger.LogDebug($"Torrent reach max retry count", torrent);
|
||||
continue;
|
||||
}
|
||||
|
||||
await _torrents.RetryTorrent(torrent.TorrentId, torrent.RetryCount);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _torrents.UpdateRetry(torrent.TorrentId, null, torrent.RetryCount);
|
||||
await _torrents.UpdateError(torrent.TorrentId, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
torrents = torrents.Where(m => m.Completed == null).ToList();
|
||||
|
||||
// Only poll Real-Debrid every second when a hub is connected, otherwise every 30 seconds
|
||||
|
|
@ -308,305 +306,301 @@ namespace RdtClient.Service.Services
|
|||
|
||||
foreach (var torrent in torrents)
|
||||
{
|
||||
// Check if there are any downloads that are queued and can be started.
|
||||
var queuedDownloads = torrent.Downloads
|
||||
.Where(m => m.Completed == null && m.DownloadQueued != null && m.DownloadStarted == null && m.Error == null)
|
||||
.OrderBy(m => m.DownloadQueued)
|
||||
.ToList();
|
||||
|
||||
foreach (var download in queuedDownloads)
|
||||
try
|
||||
{
|
||||
Log($"Processing to download", download, torrent);
|
||||
// Check if there are any downloads that are queued and can be started.
|
||||
var queuedDownloads = torrent.Downloads
|
||||
.Where(m => m.Completed == null && m.DownloadQueued != null && m.DownloadStarted == null && m.Error == null)
|
||||
.OrderBy(m => m.DownloadQueued)
|
||||
.ToList();
|
||||
|
||||
if (ActiveDownloadClients.Count >= settingDownloadLimit)
|
||||
foreach (var download in queuedDownloads)
|
||||
{
|
||||
Log($"Not starting download because there are already the max number of downloads active", download, torrent);
|
||||
Log($"Processing to download", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ActiveDownloadClients.ContainsKey(download.DownloadId))
|
||||
{
|
||||
Log($"Not starting download because this download is already active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Log($"Unrestricting links", download, torrent);
|
||||
|
||||
var downloadLink = await _torrents.UnrestrictLink(download.DownloadId);
|
||||
download.Link = downloadLink;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Cannot unrestrict link: {ex.Message}");
|
||||
|
||||
await _downloads.UpdateError(download.DownloadId, ex.Message);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.UtcNow);
|
||||
download.Error = ex.Message;
|
||||
download.Completed = DateTimeOffset.UtcNow;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Log($"Marking download as started", download, torrent);
|
||||
|
||||
download.DownloadStarted = DateTime.UtcNow;
|
||||
await _downloads.UpdateDownloadStarted(download.DownloadId, download.DownloadStarted);
|
||||
|
||||
var downloadPath = settingDownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
downloadPath = Path.Combine(downloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
Log($"Setting download path to {downloadPath}", download, torrent);
|
||||
|
||||
// Start the download process
|
||||
var downloadClient = new DownloadClient(download, torrent, downloadPath);
|
||||
|
||||
if (ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient))
|
||||
{
|
||||
Log($"Starting download", download, torrent);
|
||||
|
||||
var remoteId = await downloadClient.Start(Settings.Get);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(remoteId) && download.RemoteId != remoteId)
|
||||
if (ActiveDownloadClients.Count >= settingDownloadLimit)
|
||||
{
|
||||
Log($"Received ID {remoteId}", download, torrent);
|
||||
Log($"Not starting download because there are already the max number of downloads active", download, torrent);
|
||||
|
||||
await _downloads.UpdateRemoteId(download.DownloadId, remoteId);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (ActiveDownloadClients.ContainsKey(download.DownloadId))
|
||||
{
|
||||
Log($"No ID received", download, torrent);
|
||||
Log($"Not starting download because this download is already active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Log($"Unrestricting links", download, torrent);
|
||||
|
||||
var downloadLink = await _torrents.UnrestrictLink(download.DownloadId);
|
||||
download.Link = downloadLink;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Cannot unrestrict link: {ex.Message}");
|
||||
|
||||
await _downloads.UpdateError(download.DownloadId, ex.Message);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.UtcNow);
|
||||
download.Error = ex.Message;
|
||||
download.Completed = DateTimeOffset.UtcNow;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Log($"Marking download as started", download, torrent);
|
||||
|
||||
download.DownloadStarted = DateTime.UtcNow;
|
||||
await _downloads.UpdateDownloadStarted(download.DownloadId, download.DownloadStarted);
|
||||
|
||||
var downloadPath = settingDownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
downloadPath = Path.Combine(downloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
Log($"Setting download path to {downloadPath}", download, torrent);
|
||||
|
||||
// Start the download process
|
||||
var downloadClient = new DownloadClient(download, torrent, downloadPath);
|
||||
|
||||
if (ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient))
|
||||
{
|
||||
Log($"Starting download", download, torrent);
|
||||
|
||||
var remoteId = await downloadClient.Start(Settings.Get);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(remoteId) && download.RemoteId != remoteId)
|
||||
{
|
||||
Log($"Received ID {remoteId}", download, torrent);
|
||||
|
||||
await _downloads.UpdateRemoteId(download.DownloadId, remoteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"No ID received", download, torrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are any unpacks that are queued and can be started.
|
||||
var queuedUnpacks = torrent.Downloads
|
||||
.Where(m => m.Completed == null && m.UnpackingQueued != null && m.UnpackingStarted == null && m.Error == null)
|
||||
.OrderBy(m => m.DownloadQueued)
|
||||
.ToList();
|
||||
// Check if there are any unpacks that are queued and can be started.
|
||||
var queuedUnpacks = torrent.Downloads
|
||||
.Where(m => m.Completed == null && m.UnpackingQueued != null && m.UnpackingStarted == null && m.Error == null)
|
||||
.OrderBy(m => m.DownloadQueued)
|
||||
.ToList();
|
||||
|
||||
foreach (var download in queuedUnpacks)
|
||||
{
|
||||
Log($"Starting unpack", download, torrent);
|
||||
|
||||
if (download.Link == null)
|
||||
{
|
||||
Log($"No download link found", download, torrent);
|
||||
|
||||
await _downloads.UpdateError(download.DownloadId, "Download Link cannot be null");
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.UtcNow);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the unpacking process is even needed
|
||||
var uri = new Uri(download.Link);
|
||||
var fileName = uri.Segments.Last();
|
||||
|
||||
fileName = HttpUtility.UrlDecode(fileName);
|
||||
|
||||
Log($"Found file name {fileName}", download, torrent);
|
||||
|
||||
var extension = Path.GetExtension(fileName);
|
||||
|
||||
if (extension != ".rar")
|
||||
{
|
||||
Log($"No need to unpack, setting it as unpacked", download, torrent);
|
||||
|
||||
download.UnpackingStarted = DateTimeOffset.UtcNow;
|
||||
download.UnpackingFinished = DateTimeOffset.UtcNow;
|
||||
download.Completed = DateTimeOffset.UtcNow;
|
||||
|
||||
await _downloads.UpdateUnpackingStarted(download.DownloadId, download.UnpackingStarted);
|
||||
await _downloads.UpdateUnpackingFinished(download.DownloadId, download.UnpackingFinished);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, download.Completed);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we have reached the download limit, if so queue the download, but don't start it.
|
||||
if (TorrentRunner.ActiveUnpackClients.Count >= settingUnpackLimit)
|
||||
{
|
||||
Log($"Not starting unpack because there are already the max number of unpacks active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.ContainsKey(download.DownloadId))
|
||||
{
|
||||
Log($"Not starting unpack because this download is already active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
download.UnpackingStarted = DateTimeOffset.UtcNow;
|
||||
await _downloads.UpdateUnpackingStarted(download.DownloadId, download.UnpackingStarted);
|
||||
|
||||
var downloadPath = settingDownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
downloadPath = Path.Combine(downloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
Log($"Setting unpack path to {downloadPath}", download, torrent);
|
||||
|
||||
// Start the unpacking process
|
||||
var unpackClient = new UnpackClient(download, downloadPath);
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.TryAdd(download.DownloadId, unpackClient))
|
||||
foreach (var download in queuedUnpacks)
|
||||
{
|
||||
Log($"Starting unpack", download, torrent);
|
||||
|
||||
unpackClient.Start();
|
||||
}
|
||||
}
|
||||
|
||||
Log("Processing", torrent);
|
||||
|
||||
// If torrent is erroring out on the Real-Debrid side.
|
||||
if (torrent.RdStatus == RealDebridStatus.Error)
|
||||
{
|
||||
Log($"Torrent reported an error: {torrent.RdStatusRaw}", torrent);
|
||||
Log($"Torrent retry count {torrent.RetryCount}/{TorrentRetryCount}", torrent);
|
||||
|
||||
if (torrent.RetryCount < TorrentRetryCount)
|
||||
{
|
||||
Log($"Retrying torrent", torrent);
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
if (download.Link == null)
|
||||
{
|
||||
using var blockScope = _serviceProvider.CreateScope();
|
||||
var torrentsService = (Torrents) blockScope.ServiceProvider.GetService(typeof(Torrents));
|
||||
await torrentsService.RetryTorrent(torrent.TorrentId, torrent.RetryCount + 1);
|
||||
});
|
||||
Log($"No download link found", download, torrent);
|
||||
|
||||
// Force a delay and return the main loop to prevent concurrency issues.
|
||||
await Task.Delay(10000);
|
||||
await _downloads.UpdateError(download.DownloadId, "Download Link cannot be null");
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.UtcNow);
|
||||
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Log($"Received RealDebrid error: {torrent.RdStatusRaw}, not processing further", torrent);
|
||||
await _torrents.UpdateComplete(torrent.TorrentId, DateTimeOffset.Now);
|
||||
// Check if the unpacking process is even needed
|
||||
var uri = new Uri(download.Link);
|
||||
var fileName = uri.Segments.Last();
|
||||
|
||||
continue;
|
||||
}
|
||||
fileName = HttpUtility.UrlDecode(fileName);
|
||||
|
||||
// Real-Debrid is waiting for file selection, select which files to download.
|
||||
if ((torrent.RdStatus == RealDebridStatus.WaitingForFileSelection || torrent.RdStatus == RealDebridStatus.Finished) &&
|
||||
torrent.FilesSelected == null &&
|
||||
torrent.Downloads.Count == 0 &&
|
||||
torrent.FilesSelected == null)
|
||||
{
|
||||
Log($"Selecting files", torrent);
|
||||
Log($"Found file name {fileName}", download, torrent);
|
||||
|
||||
var files = torrent.Files;
|
||||
var extension = Path.GetExtension(fileName);
|
||||
|
||||
if (torrent.DownloadAction == TorrentDownloadAction.DownloadAvailableFiles)
|
||||
{
|
||||
Log($"Determining which files are already available on RealDebrid", torrent);
|
||||
|
||||
var availableFiles = await _torrents.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.ToList();
|
||||
}
|
||||
else 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();
|
||||
}
|
||||
|
||||
Log($"Selecting {files.Count}/{torrent.Files.Count} files", torrent);
|
||||
|
||||
if (torrent.DownloadAction != TorrentDownloadAction.DownloadManual && torrent.DownloadMinSize > 0)
|
||||
{
|
||||
var minFileSize = torrent.DownloadMinSize * 1024 * 1024;
|
||||
|
||||
Log($"Determining which files are over {minFileSize} bytes", torrent);
|
||||
|
||||
files = files.Where(m => m.Bytes > minFileSize)
|
||||
.ToList();
|
||||
|
||||
Log($"Found {files.Count} files that match the minimum file size criterea", torrent);
|
||||
}
|
||||
|
||||
if (files.Count == 0)
|
||||
{
|
||||
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
|
||||
|
||||
files = torrent.Files;
|
||||
}
|
||||
|
||||
var fileIds = files.Select(m => m.Id.ToString()).ToArray();
|
||||
|
||||
Log($"Selecting files:{Environment.NewLine}{String.Join(Environment.NewLine, files.Select(m => m.Path))}", torrent);
|
||||
|
||||
await _torrents.SelectFiles(torrent.TorrentId, fileIds);
|
||||
|
||||
await _torrents.UpdateFilesSelected(torrent.TorrentId, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
// Real-Debrid finished downloading the torrent, process the file to host.
|
||||
if (torrent.RdStatus == RealDebridStatus.Finished)
|
||||
{
|
||||
// The files are selected but there are no downloads yet, check if Real-Debrid has generated links yet.
|
||||
if (torrent.Downloads.Count == 0 && torrent.FilesSelected != null)
|
||||
{
|
||||
Log($"Checking for links", torrent);
|
||||
|
||||
await _torrents.CheckForLinks(torrent.TorrentId);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if torrent is complete
|
||||
if (torrent.Downloads.Count > 0)
|
||||
{
|
||||
var allComplete = torrent.Downloads.Count(m => m.Completed != null);
|
||||
|
||||
if (allComplete == torrent.Downloads.Count)
|
||||
{
|
||||
Log($"All downloads complete, marking torrent as complete", torrent);
|
||||
|
||||
await _torrents.UpdateComplete(torrent.TorrentId, DateTimeOffset.UtcNow);
|
||||
|
||||
switch (torrent.FinishedAction)
|
||||
if (extension != ".rar")
|
||||
{
|
||||
case TorrentFinishedAction.RemoveAllTorrents:
|
||||
Log($"Removing torrents from Real-Debrid and Real-Debrid Client, no files", torrent);
|
||||
await _torrents.Delete(torrent.TorrentId, true, true, false);
|
||||
break;
|
||||
case TorrentFinishedAction.RemoveRealDebrid:
|
||||
Log($"Removing torrents from Real-Debrid, no files", torrent);
|
||||
await _torrents.Delete(torrent.TorrentId, false, true, false);
|
||||
break;
|
||||
case TorrentFinishedAction.None:
|
||||
Log($"Not removing torrents or files", torrent);
|
||||
break;
|
||||
default:
|
||||
Log($"Invalid torrent FinishedAction {torrent.FinishedAction}", torrent);
|
||||
break;
|
||||
Log($"No need to unpack, setting it as unpacked", download, torrent);
|
||||
|
||||
download.UnpackingStarted = DateTimeOffset.UtcNow;
|
||||
download.UnpackingFinished = DateTimeOffset.UtcNow;
|
||||
download.Completed = DateTimeOffset.UtcNow;
|
||||
|
||||
await _downloads.UpdateUnpackingStarted(download.DownloadId, download.UnpackingStarted);
|
||||
await _downloads.UpdateUnpackingFinished(download.DownloadId, download.UnpackingFinished);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, download.Completed);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we have reached the download limit, if so queue the download, but don't start it.
|
||||
if (TorrentRunner.ActiveUnpackClients.Count >= settingUnpackLimit)
|
||||
{
|
||||
Log($"Not starting unpack because there are already the max number of unpacks active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.ContainsKey(download.DownloadId))
|
||||
{
|
||||
Log($"Not starting unpack because this download is already active", download, torrent);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
download.UnpackingStarted = DateTimeOffset.UtcNow;
|
||||
await _downloads.UpdateUnpackingStarted(download.DownloadId, download.UnpackingStarted);
|
||||
|
||||
var downloadPath = settingDownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
downloadPath = Path.Combine(downloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
Log($"Setting unpack path to {downloadPath}", download, torrent);
|
||||
|
||||
// Start the unpacking process
|
||||
var unpackClient = new UnpackClient(download, downloadPath);
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.TryAdd(download.DownloadId, unpackClient))
|
||||
{
|
||||
Log($"Starting unpack", download, torrent);
|
||||
|
||||
unpackClient.Start();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Log("Processing", torrent);
|
||||
|
||||
// If torrent is erroring out on the Real-Debrid side.
|
||||
if (torrent.RdStatus == RealDebridStatus.Error)
|
||||
{
|
||||
Log($"Waiting for downloads to complete. {allComplete}/{torrent.Downloads.Count} complete", torrent);
|
||||
Log($"Torrent reported an error: {torrent.RdStatusRaw}", torrent);
|
||||
Log($"Torrent retry count {torrent.RetryCount}/{torrent.TorrentRetryAttempts}", torrent);
|
||||
|
||||
Log($"Received RealDebrid error: {torrent.RdStatusRaw}, not processing further", torrent);
|
||||
|
||||
await _torrents.UpdateComplete(torrent.TorrentId, $"Received RealDebrid error: {torrent.RdStatusRaw}.", DateTimeOffset.UtcNow);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Real-Debrid is waiting for file selection, select which files to download.
|
||||
if ((torrent.RdStatus == RealDebridStatus.WaitingForFileSelection || torrent.RdStatus == RealDebridStatus.Finished) &&
|
||||
torrent.FilesSelected == null &&
|
||||
torrent.Downloads.Count == 0 &&
|
||||
torrent.FilesSelected == null)
|
||||
{
|
||||
Log($"Selecting files", torrent);
|
||||
|
||||
var files = torrent.Files;
|
||||
|
||||
if (torrent.DownloadAction == TorrentDownloadAction.DownloadAvailableFiles)
|
||||
{
|
||||
Log($"Determining which files are already available on RealDebrid", torrent);
|
||||
|
||||
var availableFiles = await _torrents.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.ToList();
|
||||
}
|
||||
else 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();
|
||||
}
|
||||
|
||||
Log($"Selecting {files.Count}/{torrent.Files.Count} files", torrent);
|
||||
|
||||
if (torrent.DownloadAction != TorrentDownloadAction.DownloadManual && torrent.DownloadMinSize > 0)
|
||||
{
|
||||
var minFileSize = torrent.DownloadMinSize * 1024 * 1024;
|
||||
|
||||
Log($"Determining which files are over {minFileSize} bytes", torrent);
|
||||
|
||||
files = files.Where(m => m.Bytes > minFileSize)
|
||||
.ToList();
|
||||
|
||||
Log($"Found {files.Count} files that match the minimum file size criterea", torrent);
|
||||
}
|
||||
|
||||
if (files.Count == 0)
|
||||
{
|
||||
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
|
||||
|
||||
files = torrent.Files;
|
||||
}
|
||||
|
||||
var fileIds = files.Select(m => m.Id.ToString()).ToArray();
|
||||
|
||||
Log($"Selecting files:{Environment.NewLine}{String.Join(Environment.NewLine, files.Select(m => m.Path))}", torrent);
|
||||
|
||||
await _torrents.SelectFiles(torrent.TorrentId, fileIds);
|
||||
|
||||
await _torrents.UpdateFilesSelected(torrent.TorrentId, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
// Real-Debrid finished downloading the torrent, process the file to host.
|
||||
if (torrent.RdStatus == RealDebridStatus.Finished)
|
||||
{
|
||||
// The files are selected but there are no downloads yet, check if Real-Debrid has generated links yet.
|
||||
if (torrent.Downloads.Count == 0 && torrent.FilesSelected != null)
|
||||
{
|
||||
Log($"Checking for links", torrent);
|
||||
|
||||
await _torrents.CheckForLinks(torrent.TorrentId);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if torrent is complete
|
||||
if (torrent.Downloads.Count > 0)
|
||||
{
|
||||
var allComplete = torrent.Downloads.Count(m => m.Completed != null);
|
||||
|
||||
if (allComplete == torrent.Downloads.Count)
|
||||
{
|
||||
Log($"All downloads complete, marking torrent as complete", torrent);
|
||||
|
||||
await _torrents.UpdateComplete(torrent.TorrentId, null, DateTimeOffset.UtcNow);
|
||||
|
||||
switch (torrent.FinishedAction)
|
||||
{
|
||||
case TorrentFinishedAction.RemoveAllTorrents:
|
||||
Log($"Removing torrents from Real-Debrid and Real-Debrid Client, no files", torrent);
|
||||
await _torrents.Delete(torrent.TorrentId, true, true, false);
|
||||
|
||||
break;
|
||||
case TorrentFinishedAction.RemoveRealDebrid:
|
||||
Log($"Removing torrents from Real-Debrid, no files", torrent);
|
||||
await _torrents.Delete(torrent.TorrentId, false, true, false);
|
||||
|
||||
break;
|
||||
case TorrentFinishedAction.None:
|
||||
Log($"Not removing torrents or files", torrent);
|
||||
|
||||
break;
|
||||
default:
|
||||
Log($"Invalid torrent FinishedAction {torrent.FinishedAction}", torrent);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Waiting for downloads to complete. {allComplete}/{torrent.Downloads.Count} complete", torrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message, $"Torrent processing result in an unexpected exception: {ex.Message}");
|
||||
await _torrents.UpdateComplete(torrent.TorrentId, ex.Message, DateTimeOffset.UtcNow);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ using MonoTorrent;
|
|||
using Newtonsoft.Json;
|
||||
using RdtClient.Data.Data;
|
||||
using RdtClient.Data.Enums;
|
||||
using RdtClient.Data.Models.Internal;
|
||||
using RdtClient.Data.Models.TorrentClient;
|
||||
using RdtClient.Service.Helpers;
|
||||
using RdtClient.Service.Models;
|
||||
using RdtClient.Service.Models.TorrentClient;
|
||||
using RdtClient.Service.Services.TorrentClients;
|
||||
using Torrent = RdtClient.Data.Models.Data.Torrent;
|
||||
|
||||
|
|
@ -93,13 +93,7 @@ namespace RdtClient.Service.Services
|
|||
await _torrentData.UpdateCategory(torrent.TorrentId, category);
|
||||
}
|
||||
|
||||
public async Task<Torrent> UploadMagnet(String magnetLink,
|
||||
String category,
|
||||
TorrentDownloadAction downloadAction,
|
||||
TorrentFinishedAction finishedAction,
|
||||
Int32 downloadMinSize,
|
||||
String downloadManualFiles,
|
||||
Int32? priority)
|
||||
public async Task<Torrent> UploadMagnet(String magnetLink, Torrent torrent)
|
||||
{
|
||||
MagnetLink magnet;
|
||||
|
||||
|
|
@ -117,20 +111,14 @@ namespace RdtClient.Service.Services
|
|||
|
||||
var hash = magnet.InfoHash.ToHex();
|
||||
|
||||
var newTorrent = await Add(id, hash, category, downloadAction, finishedAction, downloadMinSize, downloadManualFiles, magnetLink, false, priority);
|
||||
var newTorrent = await Add(id, hash, magnetLink, false, torrent);
|
||||
|
||||
Log($"Adding {hash} magnet link {magnetLink}", newTorrent);
|
||||
|
||||
return newTorrent;
|
||||
}
|
||||
|
||||
public async Task<Torrent> UploadFile(Byte[] bytes,
|
||||
String category,
|
||||
TorrentDownloadAction downloadAction,
|
||||
TorrentFinishedAction finishedAction,
|
||||
Int32 downloadMinSize,
|
||||
String downloadManualFiles,
|
||||
Int32? priority)
|
||||
public async Task<Torrent> UploadFile(Byte[] bytes, Torrent torrent)
|
||||
{
|
||||
MonoTorrent.Torrent monoTorrent;
|
||||
|
||||
|
|
@ -149,7 +137,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
var hash = monoTorrent.InfoHash.ToHex();
|
||||
|
||||
var newTorrent = await Add(id, hash, category, downloadAction, finishedAction, downloadMinSize, downloadManualFiles, fileAsBase64, true, priority);
|
||||
var newTorrent = await Add(id, hash, fileAsBase64, true, torrent);
|
||||
|
||||
Log($"Adding {hash} torrent file {fileAsBase64}", newTorrent);
|
||||
|
||||
|
|
@ -221,7 +209,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
Log($"Deleting", torrent);
|
||||
|
||||
await UpdateComplete(torrentId, DateTimeOffset.UtcNow);
|
||||
await UpdateComplete(torrentId, "Torrent deleted", DateTimeOffset.UtcNow);
|
||||
|
||||
foreach (var download in torrent.Downloads)
|
||||
{
|
||||
|
|
@ -248,7 +236,6 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
Log($"Deleting RdtClient data", torrent);
|
||||
|
||||
await _torrentData.UpdateComplete(torrent.TorrentId, DateTimeOffset.UtcNow);
|
||||
await _downloads.DeleteForTorrent(torrent.TorrentId);
|
||||
await _torrentData.Delete(torrentId);
|
||||
}
|
||||
|
|
@ -380,31 +367,31 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
var torrent = await _torrentData.GetById(torrentId);
|
||||
|
||||
if (torrent == null)
|
||||
if (torrent?.Retry == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log($"Retrying Torrent", torrent);
|
||||
|
||||
await UpdateComplete(torrent.TorrentId, DateTimeOffset.Now);
|
||||
await UpdateComplete(torrent.TorrentId, "Retrying Torrent", DateTimeOffset.UtcNow);
|
||||
|
||||
foreach (var download in torrent.Downloads)
|
||||
{
|
||||
await _downloads.UpdateError(download.DownloadId, null);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.Now);
|
||||
await _downloads.UpdateCompleted(download.DownloadId, DateTimeOffset.UtcNow);
|
||||
}
|
||||
|
||||
foreach (var download in torrent.Downloads)
|
||||
{
|
||||
while (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
|
||||
while (TorrentRunner.ActiveDownloadClients.TryRemove(download.DownloadId, out var downloadClient))
|
||||
{
|
||||
await downloadClient.Cancel();
|
||||
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
while (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient))
|
||||
while (TorrentRunner.ActiveUnpackClients.TryRemove(download.DownloadId, out var unpackClient))
|
||||
{
|
||||
unpackClient.Cancel();
|
||||
|
||||
|
|
@ -425,26 +412,14 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
var bytes = Convert.FromBase64String(torrent.FileOrMagnet);
|
||||
|
||||
newTorrent = await UploadFile(bytes,
|
||||
torrent.Category,
|
||||
torrent.DownloadAction,
|
||||
torrent.FinishedAction,
|
||||
torrent.DownloadMinSize,
|
||||
torrent.DownloadManualFiles,
|
||||
torrent.Priority);
|
||||
newTorrent = await UploadFile(bytes, torrent);
|
||||
}
|
||||
else
|
||||
{
|
||||
newTorrent = await UploadMagnet(torrent.FileOrMagnet,
|
||||
torrent.Category,
|
||||
torrent.DownloadAction,
|
||||
torrent.FinishedAction,
|
||||
torrent.DownloadMinSize,
|
||||
torrent.DownloadManualFiles,
|
||||
torrent.Priority);
|
||||
newTorrent = await UploadMagnet(torrent.FileOrMagnet, torrent);
|
||||
}
|
||||
|
||||
await _torrentData.UpdateRetryCount(newTorrent.TorrentId, retryCount);
|
||||
await _torrentData.UpdateRetry(newTorrent.TorrentId, null, retryCount);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -485,16 +460,16 @@ namespace RdtClient.Service.Services
|
|||
|
||||
await FileHelper.Delete(filePath);
|
||||
|
||||
await _torrentData.UpdateComplete(download.TorrentId, null);
|
||||
|
||||
Log($"Resetting", download, download.Torrent);
|
||||
|
||||
await _downloads.Reset(downloadId);
|
||||
|
||||
await _torrentData.UpdateComplete(download.TorrentId, null, null);
|
||||
}
|
||||
|
||||
public async Task UpdateComplete(Guid torrentId, DateTimeOffset datetime)
|
||||
public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset datetime)
|
||||
{
|
||||
await _torrentData.UpdateComplete(torrentId, datetime);
|
||||
await _torrentData.UpdateComplete(torrentId, error, datetime);
|
||||
}
|
||||
|
||||
public async Task UpdateFilesSelected(Guid torrentId, DateTimeOffset datetime)
|
||||
|
|
@ -514,6 +489,16 @@ namespace RdtClient.Service.Services
|
|||
await _torrentData.UpdatePriority(torrent.TorrentId, priority);
|
||||
}
|
||||
|
||||
public async Task UpdateRetry(Guid torrentId, DateTimeOffset? datetime, Int32 retry)
|
||||
{
|
||||
await _torrentData.UpdateRetry(torrentId, datetime, retry);
|
||||
}
|
||||
|
||||
public async Task UpdateError(Guid torrentId, String error)
|
||||
{
|
||||
await _torrentData.UpdateError(torrentId, error);
|
||||
}
|
||||
|
||||
public async Task<Torrent> GetById(Guid torrentId)
|
||||
{
|
||||
var torrent = await _torrentData.GetById(torrentId);
|
||||
|
|
@ -558,36 +543,26 @@ namespace RdtClient.Service.Services
|
|||
|
||||
private async Task<Torrent> Add(String rdTorrentId,
|
||||
String infoHash,
|
||||
String category,
|
||||
TorrentDownloadAction downloadAction,
|
||||
TorrentFinishedAction finishedAction,
|
||||
Int32 downloadMinSize,
|
||||
String downloadManualFiles,
|
||||
String fileOrMagnetContents,
|
||||
Boolean isFile,
|
||||
Int32? priority)
|
||||
Torrent torrent)
|
||||
{
|
||||
await RealDebridUpdateLock.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var torrent = await _torrentData.GetByHash(infoHash);
|
||||
var existingTorrent = await _torrentData.GetByHash(infoHash);
|
||||
|
||||
if (torrent != null)
|
||||
if (existingTorrent != null)
|
||||
{
|
||||
return torrent;
|
||||
return existingTorrent;
|
||||
}
|
||||
|
||||
var newTorrent = await _torrentData.Add(rdTorrentId,
|
||||
infoHash,
|
||||
category,
|
||||
downloadAction,
|
||||
finishedAction,
|
||||
downloadMinSize,
|
||||
downloadManualFiles,
|
||||
fileOrMagnetContents,
|
||||
isFile,
|
||||
priority);
|
||||
torrent);
|
||||
|
||||
await UpdateRdData(newTorrent);
|
||||
|
||||
|
|
@ -598,7 +573,7 @@ namespace RdtClient.Service.Services
|
|||
RealDebridUpdateLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task Update(Torrent torrent)
|
||||
{
|
||||
await _torrentData.Update(torrent);
|
||||
|
|
@ -703,7 +678,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
_logger.LogDebug(message);
|
||||
}
|
||||
|
||||
|
||||
private void Log(String message, Torrent torrent = null)
|
||||
{
|
||||
if (torrent != null)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ using System.Net.Http;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RdtClient.Service.Models.QBittorrent;
|
||||
using RdtClient.Service.Models.QBittorrent.QuickType;
|
||||
using RdtClient.Data.Models.QBittorrent;
|
||||
using RdtClient.Data.Models.QBittorrent.QuickType;
|
||||
using RdtClient.Service.Services;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RdtClient.Data.Models.Data;
|
||||
using RdtClient.Service.Models;
|
||||
using RdtClient.Data.Models.Internal;
|
||||
using RdtClient.Service.Services;
|
||||
using Serilog.Events;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MonoTorrent;
|
||||
using RdtClient.Data.Enums;
|
||||
using RdtClient.Service.Helpers;
|
||||
using RdtClient.Service.Services;
|
||||
using Torrent = RdtClient.Data.Models.Data.Torrent;
|
||||
|
|
@ -91,7 +90,7 @@ namespace RdtClient.Web.Controllers
|
|||
|
||||
var bytes = memoryStream.ToArray();
|
||||
|
||||
await _torrents.UploadFile(bytes, formData.Category, formData.DownloadAction, formData.FinishedAction, formData.DownloadMinSize, formData.DownloadManualFiles, formData.Priority);
|
||||
await _torrents.UploadFile(bytes, formData.Torrent);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
|
@ -100,13 +99,7 @@ namespace RdtClient.Web.Controllers
|
|||
[Route("UploadMagnet")]
|
||||
public async Task<ActionResult> UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest request)
|
||||
{
|
||||
await _torrents.UploadMagnet(request.MagnetLink,
|
||||
request.Category,
|
||||
request.DownloadAction,
|
||||
request.FinishedAction,
|
||||
request.DownloadMinSize,
|
||||
request.DownloadManualFiles,
|
||||
request.Priority);
|
||||
await _torrents.UploadMagnet(request.MagnetLink, request.Torrent);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
|
@ -185,23 +178,13 @@ namespace RdtClient.Web.Controllers
|
|||
|
||||
public class TorrentControllerUploadFileRequest
|
||||
{
|
||||
public String Category { get; set; }
|
||||
public TorrentDownloadAction DownloadAction { get; set; }
|
||||
public TorrentFinishedAction FinishedAction { get; set; }
|
||||
public Int32 DownloadMinSize { get; set; }
|
||||
public String DownloadManualFiles { get; set; }
|
||||
public Int32? Priority { get; set; }
|
||||
public Torrent Torrent { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentControllerUploadMagnetRequest
|
||||
{
|
||||
public String MagnetLink { get; set; }
|
||||
public String Category { get; set; }
|
||||
public TorrentDownloadAction DownloadAction { get; set; }
|
||||
public TorrentFinishedAction FinishedAction { get; set; }
|
||||
public Int32 DownloadMinSize { get; set; }
|
||||
public String DownloadManualFiles { get; set; }
|
||||
public Int32? Priority { get; set; }
|
||||
public Torrent Torrent { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentControllerDeleteRequest
|
||||
|
|
|
|||
Loading…
Reference in a new issue