Switched out RDNET Dll with Nuget package, update Angular. Rewrote Download handler and removed references to Hangfire.

This commit is contained in:
Roger Far 2020-04-10 16:48:33 -06:00
parent 76b8513d6b
commit bfba5c99fb
39 changed files with 1183 additions and 856 deletions

10
.gitignore vendored
View file

@ -33,11 +33,7 @@ client/e2e/*.map
# .NET Core build folders # .NET Core build folders
server/**/bin server/**/bin
server/**/obj server/**/obj
server/*.user server/**/*.user
server/**/.vs
# Common node modules locations
server/wwwroot/
server/.vs
server/RdtClient.Web/wwwroot/ server/RdtClient.Web/wwwroot/
server/RdtClient.Web/Properties/PublishProfiles/FolderProfile.pubxml.user
*.user

1183
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,33 +11,34 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "~9.1.0", "@angular/animations": "~9.1.1",
"@angular/common": "~9.1.0", "@angular/common": "~9.1.1",
"@angular/compiler": "~9.1.0", "@angular/compiler": "~9.1.1",
"@angular/core": "~9.1.0", "@angular/core": "~9.1.1",
"@angular/forms": "~9.1.0", "@angular/forms": "~9.1.1",
"@angular/platform-browser": "~9.1.0", "@angular/platform-browser": "~9.1.1",
"@angular/platform-browser-dynamic": "~9.1.0", "@angular/platform-browser-dynamic": "~9.1.1",
"@angular/router": "~9.1.0", "@angular/router": "~9.1.1",
"@fortawesome/fontawesome-free": "^5.13.0", "@fortawesome/fontawesome-free": "^5.13.0",
"bulma": "^0.8.1", "bulma": "^0.8.1",
"curray": "^1.0.7",
"ngx-filesize": "^2.0.13", "ngx-filesize": "^2.0.13",
"rxjs": "~6.5.5", "rxjs": "~6.5.5",
"tslib": "^1.11.1", "tslib": "^1.11.1",
"zone.js": "~0.10.3" "zone.js": "~0.10.3"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.901.0", "@angular-devkit/build-angular": "~0.901.1",
"@angular/cli": "~9.1.0", "@angular/cli": "~9.1.1",
"@angular/compiler-cli": "~9.1.0", "@angular/compiler-cli": "~9.1.1",
"@angular/language-service": "~9.1.0", "@angular/language-service": "~9.1.1",
"@types/node": "^13.11.0", "@types/node": "^13.11.1",
"@types/jasmine": "~3.5.10", "@types/jasmine": "~3.5.10",
"@types/jasminewd2": "~2.0.8", "@types/jasminewd2": "~2.0.8",
"codelyzer": "^5.2.2", "codelyzer": "^5.2.2",
"jasmine-core": "~3.5.0", "jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.1", "jasmine-spec-reporter": "~5.0.1",
"karma": "~4.4.1", "karma": "~5.0.1",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.1.1", "karma-coverage-istanbul-reporter": "~2.1.1",
"karma-jasmine": "~3.1.1", "karma-jasmine": "~3.1.1",

View file

@ -17,6 +17,9 @@ import { TorrentStatusPipe } from './torrent-status.pipe';
import { FileStatusPipe } from './file-status.pipe'; import { FileStatusPipe } from './file-status.pipe';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { AuthInterceptor } from './auth.interceptor'; import { AuthInterceptor } from './auth.interceptor';
import { curray } from 'curray';
curray();
@NgModule({ @NgModule({
declarations: [ declarations: [

View file

@ -15,7 +15,11 @@ export class FileStatusPipe implements PipeTransform {
} }
if (value.download.status === DownloadStatus.Downloading) { if (value.download.status === DownloadStatus.Downloading) {
return `${value.download.progress}%`; const progress = (
(value.download.bytesDownloaded / value.download.bytesSize) *
100
).toFixed(2);
return `${progress || 0}%`;
} }
if (value.download.status === DownloadStatus.Finished) { if (value.download.status === DownloadStatus.Finished) {

View file

@ -9,13 +9,16 @@ export class Download {
public status: DownloadStatus; public status: DownloadStatus;
public progress: number; public bytesDownloaded: number;
public bytesSize: number;
public speed: number; public speed: number;
} }
export enum DownloadStatus { export enum DownloadStatus {
PendingDownload = 0, PendingDownload = 0,
Downloading, Downloading = 1,
Finished, Unpacking = 2,
Finished = 3,
} }

View file

@ -19,7 +19,6 @@ export class Torrent {
files: TorrentFile[]; files: TorrentFile[];
downloads: Download[]; downloads: Download[];
activeDownload: Download;
} }
export class TorrentFile { export class TorrentFile {
@ -33,9 +32,10 @@ export class TorrentFile {
export enum TorrentStatus { export enum TorrentStatus {
RealDebrid = 0, RealDebrid = 0,
WaitingForDownload, WaitingForDownload = 1,
Downloading, DownloadQueued = 2,
Finished, Downloading = 3,
Finished = 4,
Error = 99, Error = 99,
} }

View file

@ -24,4 +24,7 @@
> >
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</span> </span>
<span class="icon loading-icon" *ngIf="loading">
<i class="fas fa-spinner fa-pulse"></i>
</span>
</td> </td>

View file

@ -1,6 +1,7 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { Torrent, TorrentStatus } from './models/torrent.model'; import { Torrent, TorrentStatus } from './models/torrent.model';
import { FileSizePipe } from 'ngx-filesize'; import { FileSizePipe } from 'ngx-filesize';
import { DownloadStatus } from './models/download.model';
@Pipe({ @Pipe({
name: 'status', name: 'status',
@ -9,23 +10,59 @@ export class TorrentStatusPipe implements PipeTransform {
constructor(private pipe: FileSizePipe) {} constructor(private pipe: FileSizePipe) {}
transform(torrent: Torrent): string { transform(torrent: Torrent): string {
switch (torrent.status) { if (torrent.downloads && torrent.downloads.length > 0) {
case TorrentStatus.RealDebrid: { const allFinished = torrent.downloads.all(
const speed = this.pipe.transform(torrent.rdSpeed, 'filesize'); (m) => m.status === DownloadStatus.Finished
return `Downloading from RD (${torrent.rdProgress}% - ${speed}/s)`; );
if (allFinished) {
return 'Finished';
} }
const downloading = torrent.downloads.where(
(m) => m.status === DownloadStatus.Downloading
);
const unpacking = torrent.downloads.where(
(m) => m.status === DownloadStatus.Unpacking
);
if (downloading.length > 0) {
const allBytesDownloaded = torrent.downloads.sum(
(m) => m.bytesDownloaded
);
const allBytesSize = torrent.downloads.sum((m) => m.bytesSize);
if (allBytesSize > 0) {
const progress = ((allBytesDownloaded / allBytesSize) * 100).toFixed(
2
);
const allSpeeds =
downloading.sum((m) => m.speed) / downloading.length;
const speed = this.pipe.transform(allSpeeds, 'filesize');
return `Downloading (${progress || 0}% - ${speed}/s)`;
}
return `Preparing download`;
}
if (unpacking.length > 0) {
return `Unpacking`;
}
return 'Pending download';
}
switch (torrent.status) {
case TorrentStatus.RealDebrid:
const speed = this.pipe.transform(torrent.rdSpeed, 'filesize');
return `Torrent downloading (${torrent.rdProgress}% - ${speed}/s)`;
case TorrentStatus.WaitingForDownload: case TorrentStatus.WaitingForDownload:
return `Waiting to download`; return `Waiting to download`;
case TorrentStatus.Downloading: { case TorrentStatus.DownloadQueued:
if (torrent.activeDownload != null) { return `Download queued`;
const speed = this.pipe.transform( case TorrentStatus.Downloading:
torrent.activeDownload.speed,
'filesize'
);
return `Downloading (${torrent.activeDownload.progress}% - ${speed}/s)`;
}
return `Downloading`; return `Downloading`;
}
case TorrentStatus.Finished: case TorrentStatus.Finished:
return `Finished`; return `Finished`;
case TorrentStatus.Error: case TorrentStatus.Error:

View file

@ -1,3 +1,7 @@
<div class="notification is-danger is-light" *ngIf="error && error.length > 0">
An error has occured: {{ error }}<br />
Please refresh the screen after fixing this error.
</div>
<div class="table-container"> <div class="table-container">
<table class="table is-fullwidth is-hoverable"> <table class="table is-fullwidth is-hoverable">
<colgroup> <colgroup>

View file

@ -16,7 +16,7 @@ import { DownloadStatus } from '../models/download.model';
}) })
export class TorrentTableComponent implements OnInit, OnDestroy { export class TorrentTableComponent implements OnInit, OnDestroy {
public torrents: Torrent[] = []; public torrents: Torrent[] = [];
public error: string;
public showFiles: { [key: string]: boolean } = {}; public showFiles: { [key: string]: boolean } = {};
private timer: any; private timer: any;
@ -25,18 +25,15 @@ export class TorrentTableComponent implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.torrentService.getList().subscribe((result) => { this.torrentService.getList().subscribe(
this.torrents = result; (result) => {
this.torrents = result;
this.torrents.forEach((torrent) => { },
const activeDownloads = torrent.downloads.filter( (err) => {
(m) => m.status === DownloadStatus.Downloading this.error = err.error;
); clearInterval(this.timer);
if (activeDownloads.length > 0) { }
torrent.activeDownload = activeDownloads[0]; );
}
});
});
}, 1000); }, 1000);
} }

View file

@ -2,10 +2,7 @@
"extends": "tslint:recommended", "extends": "tslint:recommended",
"rules": { "rules": {
"align": { "align": {
"options": [ "options": ["parameters", "statements"]
"parameters",
"statements"
]
}, },
"array-type": false, "array-type": false,
"arrow-return-shorthand": true, "arrow-return-shorthand": true,
@ -16,34 +13,16 @@
"component-class-suffix": true, "component-class-suffix": true,
"contextual-lifecycle": true, "contextual-lifecycle": true,
"directive-class-suffix": true, "directive-class-suffix": true,
"directive-selector": [ "directive-selector": [true, "attribute", "app", "camelCase"],
true, "component-selector": [true, "element", "app", "kebab-case"],
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"eofline": true, "eofline": true,
"import-blacklist": [ "import-blacklist": [true, "rxjs/Rx"],
true,
"rxjs/Rx"
],
"import-spacing": true, "import-spacing": true,
"indent": { "indent": {
"options": [ "options": ["spaces"]
"spaces"
]
}, },
"max-classes-per-file": false, "max-classes-per-file": false,
"max-line-length": [ "max-line-length": [true, 140],
true,
140
],
"member-ordering": [ "member-ordering": [
true, true,
{ {
@ -55,35 +34,17 @@
] ]
} }
], ],
"no-console": [ "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false, "no-empty": false,
"no-inferrable-types": [ "no-inferrable-types": [true, "ignore-params"],
true,
"ignore-params"
],
"no-non-null-assertion": true, "no-non-null-assertion": true,
"no-redundant-jsdoc": true, "no-redundant-jsdoc": true,
"no-switch-case-fall-through": true, "no-switch-case-fall-through": true,
"no-var-requires": false, "no-var-requires": false,
"object-literal-key-quotes": [ "object-literal-key-quotes": [true, "as-needed"],
true, "quotemark": [true, "single"],
"as-needed"
],
"quotemark": [
true,
"single"
],
"semicolon": { "semicolon": {
"options": [ "options": ["always"]
"always"
]
}, },
"space-before-function-paren": { "space-before-function-paren": {
"options": { "options": {
@ -113,11 +74,7 @@
] ]
}, },
"variable-name": { "variable-name": {
"options": [ "options": ["ban-keywords", "check-format", "allow-pascal-case"]
"ban-keywords",
"check-format",
"allow-pascal-case"
]
}, },
"whitespace": { "whitespace": {
"options": [ "options": [
@ -142,7 +99,5 @@
"use-lifecycle-interface": true, "use-lifecycle-interface": true,
"use-pipe-transform-interface": true "use-pipe-transform-interface": true
}, },
"rulesDirectory": [ "rulesDirectory": ["codelyzer"]
"codelyzer" }
]
}

View file

@ -11,6 +11,7 @@ namespace RdtClient.Data.Data
public interface IDownloadData public interface IDownloadData
{ {
Task<IList<Download>> Get(); Task<IList<Download>> Get();
Task<IList<Download>> GetForTorrent(Guid torrentId);
Task<Download> Add(Guid torrentId, String link); Task<Download> Add(Guid torrentId, String link);
Task UpdateStatus(Guid downloadId, DownloadStatus status); Task UpdateStatus(Guid downloadId, DownloadStatus status);
Task DeleteForTorrent(Guid torrentId); Task DeleteForTorrent(Guid torrentId);
@ -33,6 +34,14 @@ namespace RdtClient.Data.Data
.ToListAsync(); .ToListAsync();
} }
public async Task<IList<Download>> GetForTorrent(Guid torrentId)
{
return await _dataContext.Downloads
.AsNoTracking()
.Where(m => m.TorrentId == torrentId)
.ToListAsync();
}
public async Task<Download> Add(Guid torrentId, String link) public async Task<Download> Add(Guid torrentId, String link)
{ {
var download = new Download var download = new Download

View file

@ -101,8 +101,6 @@ namespace RdtClient.Data.Data
{ {
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrent.TorrentId); var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrent.TorrentId);
dbTorrent.Status = torrent.Status;
dbTorrent.RdName = torrent.RdName; dbTorrent.RdName = torrent.RdName;
dbTorrent.RdSize = torrent.RdSize; dbTorrent.RdSize = torrent.RdSize;
dbTorrent.RdHost = torrent.RdHost; dbTorrent.RdHost = torrent.RdHost;
@ -114,6 +112,11 @@ namespace RdtClient.Data.Data
dbTorrent.RdSpeed = torrent.RdSpeed; dbTorrent.RdSpeed = torrent.RdSpeed;
dbTorrent.RdSeeders = torrent.RdSeeders; dbTorrent.RdSeeders = torrent.RdSeeders;
if (torrent.Files != null)
{
dbTorrent.RdFiles = torrent.RdFiles;
}
await _dataContext.SaveChangesAsync(); await _dataContext.SaveChangesAsync();
} }

View file

@ -3,9 +3,10 @@
public enum TorrentStatus public enum TorrentStatus
{ {
RealDebrid = 0, RealDebrid = 0,
WaitingForDownload, WaitingForDownload = 1,
Downloading, DownloadQueued = 2,
Finished, Downloading = 3,
Finished = 4,
Error = 99 Error = 99
} }

View file

@ -9,7 +9,7 @@ using RdtClient.Data.Data;
namespace RdtClient.Data.Migrations namespace RdtClient.Data.Migrations
{ {
[DbContext(typeof(DataContext))] [DbContext(typeof(DataContext))]
[Migration("20200407174750_Initial")] [Migration("20200408224831_Initial")]
partial class Initial partial class Initial
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -277,6 +277,12 @@ namespace RdtClient.Data.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<bool>("AutoDelete")
.HasColumnType("INTEGER");
b.Property<bool>("AutoDownload")
.HasColumnType("INTEGER");
b.Property<string>("Category") b.Property<string>("Category")
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -66,6 +66,8 @@ namespace RdtClient.Data.Migrations
TorrentId = table.Column<Guid>(nullable: false), TorrentId = table.Column<Guid>(nullable: false),
Hash = table.Column<string>(nullable: true), Hash = table.Column<string>(nullable: true),
Category = table.Column<string>(nullable: true), Category = table.Column<string>(nullable: true),
AutoDownload = table.Column<bool>(nullable: false),
AutoDelete = table.Column<bool>(nullable: false),
Status = table.Column<int>(nullable: false), Status = table.Column<int>(nullable: false),
RdId = table.Column<string>(nullable: true), RdId = table.Column<string>(nullable: true),
RdName = table.Column<string>(nullable: true), RdName = table.Column<string>(nullable: true),

View file

@ -275,6 +275,12 @@ namespace RdtClient.Data.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<bool>("AutoDelete")
.HasColumnType("INTEGER");
b.Property<bool>("AutoDownload")
.HasColumnType("INTEGER");
b.Property<string>("Category") b.Property<string>("Category")
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -22,15 +22,12 @@ namespace RdtClient.Data.Models.Data
public Torrent Torrent { get; set; } public Torrent Torrent { get; set; }
[NotMapped] [NotMapped]
public Int32 Progress { get; set; } public Int64 BytesSize { get; set; }
[NotMapped]
public Int64 BytesDownloaded { get; set; }
[NotMapped] [NotMapped]
public Int64 Speed { get; set; } public Int64 Speed { get; set; }
[NotMapped]
public DateTime NextUpdate { get; set; }
[NotMapped]
public Int64 BytesLastUpdate { get; set; }
} }
} }

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
using RDNET.Models; using RDNET;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
namespace RdtClient.Data.Models.Data namespace RdtClient.Data.Models.Data
@ -17,6 +17,10 @@ namespace RdtClient.Data.Models.Data
public String Category { get; set; } public String Category { get; set; }
public Boolean AutoDownload { get; set; }
public Boolean AutoDelete { get; set; }
public TorrentStatus Status { get; set; } public TorrentStatus Status { get; set; }
[InverseProperty("Torrent")] [InverseProperty("Torrent")]

View file

@ -4,31 +4,6 @@
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Migrations\20200402172935_AspNetIdentity.cs" />
<Compile Remove="Migrations\20200402172935_AspNetIdentity.Designer.cs" />
<Compile Remove="Migrations\20200402173119_Torrents.cs" />
<Compile Remove="Migrations\20200402173119_Torrents.Designer.cs" />
<Compile Remove="Migrations\20200402190746_Torrents.cs" />
<Compile Remove="Migrations\20200402190746_Torrents.Designer.cs" />
<Compile Remove="Migrations\20200402194059_Torrents.cs" />
<Compile Remove="Migrations\20200402194059_Torrents.Designer.cs" />
<Compile Remove="Migrations\20200402212417_Torrents.cs" />
<Compile Remove="Migrations\20200402212417_Torrents.Designer.cs" />
<Compile Remove="Migrations\20200403143200_Torrent.cs" />
<Compile Remove="Migrations\20200403143200_Torrent.Designer.cs" />
<Compile Remove="Migrations\20200403143240_Settings.cs" />
<Compile Remove="Migrations\20200403143240_Settings.Designer.cs" />
<Compile Remove="Migrations\20200403145651_Settings.cs" />
<Compile Remove="Migrations\20200403145651_Settings.Designer.cs" />
<Compile Remove="Migrations\20200403164143_Downloads.cs" />
<Compile Remove="Migrations\20200403164143_Downloads.Designer.cs" />
<Compile Remove="Migrations\20200403174830_Initia.cs" />
<Compile Remove="Migrations\20200403174830_Initia.Designer.cs" />
<Compile Remove="Migrations\20200403174846_Initial.cs" />
<Compile Remove="Migrations\20200403174846_Initial.Designer.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.3" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="3.1.3" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="3.1.3" />
@ -39,6 +14,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="RD.NET" Version="1.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -10,9 +10,10 @@ namespace RdtClient.Service
services.AddScoped<IAuthentication, Authentication>(); services.AddScoped<IAuthentication, Authentication>();
services.AddScoped<IDownloads, Downloads>(); services.AddScoped<IDownloads, Downloads>();
services.AddScoped<IQBittorrent, QBittorrent>(); services.AddScoped<IQBittorrent, QBittorrent>();
services.AddScoped<IScheduler, Scheduler>();
services.AddScoped<ISettings, Settings>(); services.AddScoped<ISettings, Settings>();
services.AddScoped<ITorrents, Torrents>(); services.AddScoped<ITorrents, Torrents>();
services.AddHostedService<TaskRunner>();
} }
} }
} }

View file

@ -6,9 +6,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Hangfire.Core" Version="1.7.10" />
<PackageReference Include="MonoTorrent" Version="1.0.19" /> <PackageReference Include="MonoTorrent" Version="1.0.19" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="RD.NET" Version="1.0.0" />
<PackageReference Include="SharpCompress" Version="0.25.0" /> <PackageReference Include="SharpCompress" Version="0.25.0" />
</ItemGroup> </ItemGroup>
@ -16,10 +16,4 @@
<ProjectReference Include="..\RdtClient.Data\RdtClient.Data.csproj" /> <ProjectReference Include="..\RdtClient.Data\RdtClient.Data.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="RDNET">
<HintPath>..\libs\RDNET.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

View file

@ -1,12 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Data;
using SharpCompress.Common; using SharpCompress.Common;
@ -14,32 +10,37 @@ using SharpCompress.Readers;
namespace RdtClient.Service.Services namespace RdtClient.Service.Services
{ {
public static class DownloadManager public class DownloadManager
{ {
public static readonly Dictionary<Guid, Download> ActiveDownloads = new Dictionary<Guid, Download>(); public DownloadStatus? NewStatus { get; set; }
public Download Download { get; set; }
public Int64 Speed { get; private set; }
public Int64 BytesDownloaded { get; private set; }
public Int64 BytesSize { get; private set; }
static DownloadManager() private DateTime _nextUpdate;
private Int64 _bytesLastUpdate;
public DownloadManager()
{ {
ServicePointManager.Expect100Continue = false; ServicePointManager.Expect100Continue = false;
ServicePointManager.DefaultConnectionLimit = 100; ServicePointManager.DefaultConnectionLimit = 100;
ServicePointManager.MaxServicePointIdleTime = 1000; ServicePointManager.MaxServicePointIdleTime = 1000;
} }
public static async Task Download(Download download, String destinationFolderPath) private DownloadManager ActiveDownload => TaskRunner.ActiveDownloads[Download.DownloadId];
public async Task Start(String destinationFolderPath)
{ {
await UpdateStatus(download.DownloadId, DownloadStatus.Downloading, TorrentStatus.Downloading); ActiveDownload.NewStatus = DownloadStatus.Downloading;
ActiveDownload.BytesDownloaded = 0;
ActiveDownload.BytesSize = 0;
ActiveDownload.Speed = 0;
_bytesLastUpdate = 0;
_nextUpdate = DateTime.UtcNow.AddSeconds(1);
if (!ActiveDownloads.TryAdd(download.DownloadId, download)) var fileUrl = Download.Link;
{
return;
}
download.Progress = 0;
download.BytesLastUpdate = 0;
download.NextUpdate = DateTime.UtcNow.AddSeconds(1);
download.Speed = 0;
var fileUrl = download.Link;
var uri = new Uri(fileUrl); var uri = new Uri(fileUrl);
var filePath = Path.Combine(destinationFolderPath, uri.Segments.Last()); var filePath = Path.Combine(destinationFolderPath, uri.Segments.Last());
@ -77,13 +78,15 @@ namespace RdtClient.Service.Services
{ {
fileStream.Write(buffer, 0, read); fileStream.Write(buffer, 0, read);
ActiveDownloads[download.DownloadId].Progress = (Int32) (fileStream.Length * 100 / responseLength); ActiveDownload.BytesDownloaded = fileStream.Length;
ActiveDownload.BytesSize = responseLength;
if (DateTime.UtcNow > ActiveDownloads[download.DownloadId].NextUpdate) if (DateTime.UtcNow > _nextUpdate)
{ {
ActiveDownloads[download.DownloadId].Speed = fileStream.Length - ActiveDownloads[download.DownloadId].BytesLastUpdate; ActiveDownload.Speed = fileStream.Length - _bytesLastUpdate;
ActiveDownloads[download.DownloadId].NextUpdate = DateTime.UtcNow.AddSeconds(1);
ActiveDownloads[download.DownloadId].BytesLastUpdate = fileStream.Length; _nextUpdate = DateTime.UtcNow.AddSeconds(1);
_bytesLastUpdate = fileStream.Length;
} }
} }
else else
@ -93,13 +96,14 @@ namespace RdtClient.Service.Services
} }
} }
ActiveDownloads[download.DownloadId].Speed = 0; ActiveDownload.Speed = 0;
ActiveDownload.BytesDownloaded = ActiveDownload.BytesSize;
try try
{ {
if (filePath.EndsWith(".rar")) if (filePath.EndsWith(".rar"))
{ {
await UpdateStatus(download.DownloadId, DownloadStatus.Unpacking, TorrentStatus.Downloading); ActiveDownload.NewStatus = DownloadStatus.Unpacking;
await using (Stream stream = File.OpenRead(filePath)) await using (Stream stream = File.OpenRead(filePath))
{ {
@ -141,43 +145,7 @@ namespace RdtClient.Service.Services
// ignored // ignored
} }
await UpdateStatus(download.DownloadId, DownloadStatus.Finished, TorrentStatus.Finished); ActiveDownload.NewStatus = DownloadStatus.Finished;
ActiveDownloads.Remove(download.DownloadId);
}
private static async Task UpdateStatus(Guid downloadId, DownloadStatus downloadStatus, TorrentStatus torrentStatus)
{
await using var context = new DataContext();
var download = await context.Downloads.FirstOrDefaultAsync(m => m.DownloadId == downloadId);
download.Status = downloadStatus;
await context.SaveChangesAsync();
var torrent = await context.Torrents.FirstOrDefaultAsync(m => m.TorrentId == download.TorrentId);
if (torrentStatus == TorrentStatus.Finished)
{
var allDownloads = await context.Downloads.Where(m => m.TorrentId == download.TorrentId)
.ToListAsync();
if (allDownloads.All(m => m.Status == DownloadStatus.Finished))
{
torrent.Status = TorrentStatus.Finished;
}
else
{
torrent.Status = TorrentStatus.Downloading;
}
}
else
{
torrent.Status = torrentStatus;
}
await context.SaveChangesAsync();
} }
} }
} }

View file

@ -10,6 +10,7 @@ namespace RdtClient.Service.Services
public interface IDownloads public interface IDownloads
{ {
Task<IList<Download>> Get(); Task<IList<Download>> Get();
Task<IList<Download>> GetForTorrent(Guid torrentId);
Task<Download> Add(Guid torrentId, String link); Task<Download> Add(Guid torrentId, String link);
Task UpdateStatus(Guid downloadId, DownloadStatus status); Task UpdateStatus(Guid downloadId, DownloadStatus status);
Task DeleteForTorrent(Guid torrentId); Task DeleteForTorrent(Guid torrentId);
@ -18,12 +19,10 @@ namespace RdtClient.Service.Services
public class Downloads : IDownloads public class Downloads : IDownloads
{ {
private readonly IDownloadData _downloadData; private readonly IDownloadData _downloadData;
private readonly ISettings _settings;
public Downloads(IDownloadData downloadData, ISettings settings) public Downloads(IDownloadData downloadData)
{ {
_downloadData = downloadData; _downloadData = downloadData;
_settings = settings;
} }
public async Task<IList<Download>> Get() public async Task<IList<Download>> Get()
@ -31,6 +30,11 @@ namespace RdtClient.Service.Services
return await _downloadData.Get(); return await _downloadData.Get();
} }
public async Task<IList<Download>> GetForTorrent(Guid torrentId)
{
return await _downloadData.GetForTorrent(torrentId);
}
public async Task<Download> Add(Guid torrentId, String link) public async Task<Download> Add(Guid torrentId, String link)
{ {
return await _downloadData.Add(torrentId, link); return await _downloadData.Add(torrentId, link);

View file

@ -18,7 +18,7 @@ namespace RdtClient.Service.Services
Task<IList<TorrentInfo>> TorrentInfo(); Task<IList<TorrentInfo>> TorrentInfo();
Task<TorrentProperties> TorrentProperties(String hash); Task<TorrentProperties> TorrentProperties(String hash);
Task TorrentsDelete(String hash, Boolean deleteFiles); Task TorrentsDelete(String hash, Boolean deleteFiles);
Task TorrentsAdd(String url); Task TorrentsAdd(String magnetLink, Boolean autoDownload, Boolean autoDelete);
Task TorrentsSetCategory(String hash, String category); Task TorrentsSetCategory(String hash, String category);
Task<IDictionary<String, TorrentCategory>> TorrentsCategories(); Task<IDictionary<String, TorrentCategory>> TorrentsCategories();
} }
@ -363,9 +363,9 @@ namespace RdtClient.Service.Services
} }
} }
public async Task TorrentsAdd(String url) public async Task TorrentsAdd(String magnetLink, Boolean autoDownload, Boolean autoDelete)
{ {
await _torrents.UploadMagnet(url); await _torrents.UploadMagnet(magnetLink, autoDownload, autoDelete);
} }
public async Task TorrentsSetCategory(String hash, String category) public async Task TorrentsSetCategory(String hash, String category)

View file

@ -1,62 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using Hangfire;
using RdtClient.Data.Enums;
namespace RdtClient.Service.Services
{
public interface IScheduler
{
void Start();
Task Process();
}
public class Scheduler : IScheduler
{
private readonly IDownloads _downloads;
private readonly ISettings _settings;
private readonly ITorrents _torrents;
public Scheduler(ITorrents torrents, IDownloads downloads, ISettings settings)
{
_torrents = torrents;
_downloads = downloads;
_settings = settings;
}
public void Start()
{
RecurringJob.AddOrUpdate(() => Process(), "* * * * *");
BackgroundJob.Enqueue(() => Process());
}
[DisableConcurrentExecution(5)]
public async Task Process()
{
await _torrents.Update();
var downloads = await _downloads.Get();
downloads = downloads.Where(m => m.Status != DownloadStatus.Finished)
.OrderByDescending(m => m.Status)
.ThenByDescending(m => m.Added)
.ToList();
var maxDownloads = await _settings.GetNumber("DownloadLimit");
var destinationFolderPath = await _settings.GetString("DownloadFolder");
foreach (var download in downloads)
{
if (DownloadManager.ActiveDownloads.Count >= maxDownloads)
{
return;
}
download.Torrent = null;
BackgroundJob.Enqueue(() => DownloadManager.Download(download, destinationFolderPath));
await Task.Delay(1000);
}
}
}
}

View file

@ -0,0 +1,180 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RdtClient.Data.Enums;
namespace RdtClient.Service.Services
{
public class TaskRunner : IHostedService, IDisposable
{
public static readonly ConcurrentDictionary<Guid, DownloadManager> ActiveDownloads = new ConcurrentDictionary<Guid, DownloadManager>();
private readonly ILogger<TaskRunner> _logger;
private readonly IServiceProvider _services;
private Timer _timer;
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public TaskRunner(ILogger<TaskRunner> logger, IServiceProvider services)
{
_logger = logger;
_services = services;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Hosted Service running.");
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
private async void DoWork(Object state)
{
// Make sure only 1 process enters the lock
var obtainLock = await _semaphoreSlim.WaitAsync(100);
if (!obtainLock)
{
return;
}
try
{
using (var scope = _services.CreateScope())
{
var downloads = scope.ServiceProvider.GetRequiredService<IDownloads>();
var settings = scope.ServiceProvider.GetRequiredService<ISettings>();
var torrents = scope.ServiceProvider.GetRequiredService<ITorrents>();
var rdKey = await settings.GetString("RealDebridApiKey");
if (String.IsNullOrWhiteSpace(rdKey))
{
return;
}
await ProcessAutoDownloads(downloads, settings, torrents);
await ProcessDownloads(downloads, settings, torrents);
await ProcessStatus(downloads, settings, torrents);
}
}
finally
{
_semaphoreSlim.Release(1);
}
}
private async Task ProcessAutoDownloads(IDownloads downloads, ISettings settings, ITorrents torrents)
{
await torrents.Update();
var allTorrents = await torrents.Get();
allTorrents = allTorrents.Where(m => m.Status == TorrentStatus.WaitingForDownload && m.AutoDownload && m.Downloads.Count == 0)
.ToList();
foreach (var torrent in allTorrents)
{
await torrents.Download(torrent.TorrentId);
}
}
private async Task ProcessDownloads(IDownloads downloads, ISettings settings, ITorrents torrents)
{
await torrents.Update();
var allDownloads = await downloads.Get();
allDownloads = allDownloads.Where(m => m.Status != DownloadStatus.Finished)
.OrderByDescending(m => m.Status)
.ThenByDescending(m => m.Added)
.ToList();
var maxDownloads = await settings.GetNumber("DownloadLimit");
var destinationFolderPath = await settings.GetString("DownloadFolder");
foreach (var download in allDownloads)
{
if (ActiveDownloads.ContainsKey(download.DownloadId))
{
continue;
}
if (ActiveDownloads.Count >= maxDownloads)
{
return;
}
// Prevent circular references
download.Torrent.Downloads = null;
await Task.Factory.StartNew(async delegate
{
var downloadManager = new DownloadManager();
if (ActiveDownloads.TryAdd(download.DownloadId, downloadManager))
{
downloadManager.Download = download;
await downloadManager.Start(destinationFolderPath);
await torrents.UpdateStatus(download.TorrentId, TorrentStatus.Downloading);
}
});
}
}
private async Task ProcessStatus(IDownloads downloads, ISettings settings, ITorrents torrents)
{
foreach (var (downloadId, download) in ActiveDownloads)
{
if (download.NewStatus.HasValue)
{
download.Download.Status = download.NewStatus.Value;
download.NewStatus = null;
await downloads.UpdateStatus(downloadId, download.Download.Status);
if (download.Download.Status == DownloadStatus.Finished)
{
ActiveDownloads.TryRemove(downloadId, out _);
// Check if all downloads are completed and update the torrent
var allDownloads = await downloads.GetForTorrent(download.Download.TorrentId);
if (allDownloads.All(m => m.Status == DownloadStatus.Finished))
{
await torrents.UpdateStatus(download.Download.TorrentId, TorrentStatus.Finished);
if (download.Download.Torrent.AutoDelete)
{
await torrents.Delete(download.Download.TorrentId);
}
}
}
}
}
}
}
}

View file

@ -19,9 +19,10 @@ namespace RdtClient.Service.Services
Task<Torrent> GetById(Guid id); Task<Torrent> GetById(Guid id);
Task<Torrent> GetByHash(String hash); Task<Torrent> GetByHash(String hash);
Task<IList<Torrent>> Update(); Task<IList<Torrent>> Update();
Task UpdateStatus(Guid torrentId, TorrentStatus status);
Task UpdateCategory(String hash, String category); Task UpdateCategory(String hash, String category);
Task UploadMagnet(String magnetLink); Task UploadMagnet(String magnetLink, Boolean autoDownload, Boolean autoDelete);
Task UploadFile(Byte[] bytes); Task UploadFile(Byte[] bytes, Boolean autoDownload, Boolean autoDelete);
Task Delete(Guid id); Task Delete(Guid id);
Task Download(Guid id); Task Download(Guid id);
void Reset(); void Reset();
@ -60,7 +61,7 @@ namespace RdtClient.Service.Services
throw new Exception("RealDebrid API Key not set in the settings"); throw new Exception("RealDebrid API Key not set in the settings");
} }
_rdtClient = new RdNetClient("X245A4XAIBGVM", null, null, null, null, apiKey); _rdtClient = new RdNetClient("X245A4XAIBGVM", null, null, null, apiKey);
} }
return _rdtClient; return _rdtClient;
@ -82,10 +83,11 @@ namespace RdtClient.Service.Services
{ {
foreach (var download in torrent.Downloads) foreach (var download in torrent.Downloads)
{ {
if (DownloadManager.ActiveDownloads.TryGetValue(download.DownloadId, out var activeDownload)) if (TaskRunner.ActiveDownloads.TryGetValue(download.DownloadId, out var activeDownload))
{ {
download.Speed = activeDownload.Speed; download.Speed = activeDownload.Speed;
download.Progress = activeDownload.Progress; download.BytesSize = activeDownload.BytesSize;
download.BytesDownloaded = activeDownload.BytesDownloaded;
} }
} }
} }
@ -99,7 +101,7 @@ namespace RdtClient.Service.Services
if (torrent != null) if (torrent != null)
{ {
var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId);
await Update(torrent, rdTorrent); await Update(torrent, rdTorrent);
} }
@ -113,7 +115,7 @@ namespace RdtClient.Service.Services
if (torrent != null) if (torrent != null)
{ {
var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId);
await Update(torrent, rdTorrent); await Update(torrent, rdTorrent);
} }
@ -133,7 +135,7 @@ namespace RdtClient.Service.Services
try try
{ {
var rdTorrents = await RdNetClient.TorrentsAsync(0, 100); var rdTorrents = await RdNetClient.GetTorrentsAsync(0, 100);
foreach (var rdTorrent in rdTorrents) foreach (var rdTorrent in rdTorrents)
{ {
@ -169,6 +171,11 @@ namespace RdtClient.Service.Services
} }
} }
public async Task UpdateStatus(Guid torrentId, TorrentStatus status)
{
await _torrentData.UpdateStatus(torrentId, status);
}
public async Task UpdateCategory(String hash, String category) public async Task UpdateCategory(String hash, String category)
{ {
var torrent = await _torrentData.GetByHash(hash); var torrent = await _torrentData.GetByHash(hash);
@ -181,22 +188,22 @@ namespace RdtClient.Service.Services
await _torrentData.UpdateCategory(torrent.TorrentId, category); await _torrentData.UpdateCategory(torrent.TorrentId, category);
} }
public async Task UploadMagnet(String magnetLink) public async Task UploadMagnet(String magnetLink, Boolean autoDownload, Boolean autoDelete)
{ {
var magnet = MagnetLink.Parse(magnetLink); var magnet = MagnetLink.Parse(magnetLink);
var rdTorrent = await RdNetClient.TorrentAddMagnet(magnetLink); var rdTorrent = await RdNetClient.AddTorrentMagnetAsync(magnetLink);
await Add(rdTorrent.Id, magnet.InfoHash.ToHex()); await Add(rdTorrent.Id, magnet.InfoHash.ToHex(), autoDownload, autoDelete);
} }
public async Task UploadFile(Byte[] bytes) public async Task UploadFile(Byte[] bytes, Boolean autoDownload, Boolean autoDelete)
{ {
var torrent = MonoTorrent.Torrent.Load(bytes); var torrent = MonoTorrent.Torrent.Load(bytes);
var rdTorrent = await RdNetClient.TorrentAddFile(bytes); var rdTorrent = await RdNetClient.AddTorrentFileAsync(bytes);
await Add(rdTorrent.Id, torrent.InfoHash.ToHex()); await Add(rdTorrent.Id, torrent.InfoHash.ToHex(), autoDownload, autoDelete);
} }
public async Task Delete(Guid id) public async Task Delete(Guid id)
@ -207,7 +214,7 @@ namespace RdtClient.Service.Services
{ {
await _downloads.DeleteForTorrent(torrent.TorrentId); await _downloads.DeleteForTorrent(torrent.TorrentId);
await _torrentData.Delete(id); await _torrentData.Delete(id);
await RdNetClient.TorrentDelete(torrent.RdId); await RdNetClient.DeleteTorrentAsync(torrent.RdId);
} }
} }
@ -217,7 +224,9 @@ namespace RdtClient.Service.Services
await _downloads.DeleteForTorrent(id); await _downloads.DeleteForTorrent(id);
var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); await _torrentData.UpdateStatus(id, TorrentStatus.DownloadQueued);
var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId);
foreach (var link in rdTorrent.Links) foreach (var link in rdTorrent.Links)
{ {
@ -235,7 +244,12 @@ namespace RdtClient.Service.Services
public async Task<Profile> GetProfile() public async Task<Profile> GetProfile()
{ {
var user = await _rdtClient.UserAsync(); if (_rdtClient == null)
{
return new Profile();
}
var user = await _rdtClient.GetUserAsync();
var profile = new Profile var profile = new Profile
{ {
@ -246,11 +260,11 @@ namespace RdtClient.Service.Services
return profile; return profile;
} }
private async Task Add(String rdTorrentId, String infoHash) private async Task Add(String rdTorrentId, String infoHash, Boolean autoDownload, Boolean autoDelete)
{ {
var newTorrent = await _torrentData.Add(rdTorrentId, infoHash); var newTorrent = await _torrentData.Add(rdTorrentId, infoHash);
var rdTorrent = await RdNetClient.TorrentInfoAsync(rdTorrentId); var rdTorrent = await RdNetClient.GetTorrentInfoAsync(rdTorrentId);
if (rdTorrent.Files != null && rdTorrent.Files.Count > 0) if (rdTorrent.Files != null && rdTorrent.Files.Count > 0)
{ {
@ -259,14 +273,14 @@ namespace RdtClient.Service.Services
var fileIds = rdTorrent.Files.Select(m => m.Id.ToString()) var fileIds = rdTorrent.Files.Select(m => m.Id.ToString())
.ToArray(); .ToArray();
await RdNetClient.TorrentSelectFiles(rdTorrentId, fileIds); await RdNetClient.SelectTorrentFilesAsync(rdTorrentId, fileIds);
} }
} }
await Update(newTorrent, rdTorrent); await Update(newTorrent, rdTorrent);
} }
private async Task Update(Torrent torrent, RDNET.Models.Torrent rdTorrent) private async Task Update(Torrent torrent, RDNET.Torrent rdTorrent)
{ {
if (!String.IsNullOrWhiteSpace(rdTorrent.Filename)) if (!String.IsNullOrWhiteSpace(rdTorrent.Filename))
{ {
@ -300,11 +314,13 @@ namespace RdtClient.Service.Services
torrent.RdSpeed = rdTorrent.Speed; torrent.RdSpeed = rdTorrent.Speed;
torrent.RdSeeders = rdTorrent.Seeders; torrent.RdSeeders = rdTorrent.Seeders;
await _torrentData.UpdateRdData(torrent);
if (torrent.Status == TorrentStatus.RealDebrid) if (torrent.Status == TorrentStatus.RealDebrid)
{ {
if (torrent.Status == TorrentStatus.RealDebrid && torrent.RdProgress == 100) if (torrent.Status == TorrentStatus.RealDebrid && torrent.RdProgress == 100)
{ {
torrent.Status = TorrentStatus.WaitingForDownload; await _torrentData.UpdateStatus(torrent.TorrentId, TorrentStatus.WaitingForDownload);
} }
else else
{ {
@ -317,10 +333,10 @@ namespace RdtClient.Service.Services
"dead" => TorrentStatus.Error, "dead" => TorrentStatus.Error,
_ => TorrentStatus.RealDebrid _ => TorrentStatus.RealDebrid
}; };
await _torrentData.UpdateStatus(torrent.TorrentId, torrent.Status);
} }
} }
await _torrentData.UpdateRdData(torrent);
} }
} }
} }

View file

@ -272,7 +272,7 @@ namespace RdtClient.Web.Controllers
foreach (var url in urls) foreach (var url in urls)
{ {
await _qBittorrent.TorrentsAdd(url.Trim()); await _qBittorrent.TorrentsAdd(url.Trim(), true, true);
} }
return Ok(); return Ok();

View file

@ -33,7 +33,7 @@ namespace RdtClient.Web.Controllers
} }
catch (Exception ex) catch (Exception ex)
{ {
return BadRequest(ex); return BadRequest(ex.Message);
} }
} }
@ -50,7 +50,7 @@ namespace RdtClient.Web.Controllers
} }
catch (Exception ex) catch (Exception ex)
{ {
return BadRequest(ex); return BadRequest(ex.Message);
} }
} }
@ -65,7 +65,7 @@ namespace RdtClient.Web.Controllers
} }
catch (Exception ex) catch (Exception ex)
{ {
return BadRequest(ex); return BadRequest(ex.Message);
} }
} }
} }

View file

@ -15,12 +15,10 @@ namespace RdtClient.Web.Controllers
public class TorrentsController : Controller public class TorrentsController : Controller
{ {
private readonly ITorrents _torrents; private readonly ITorrents _torrents;
private readonly IScheduler _scheduler;
public TorrentsController(ITorrents torrents, IScheduler scheduler) public TorrentsController(ITorrents torrents)
{ {
_torrents = torrents; _torrents = torrents;
_scheduler = scheduler;
} }
[HttpGet] [HttpGet]
@ -34,7 +32,7 @@ namespace RdtClient.Web.Controllers
} }
catch (Exception ex) catch (Exception ex)
{ {
return BadRequest(ex); return BadRequest(ex.Message);
} }
} }
@ -55,7 +53,7 @@ namespace RdtClient.Web.Controllers
} }
catch (Exception ex) catch (Exception ex)
{ {
return BadRequest(ex); return BadRequest(ex.Message);
} }
} }
@ -78,7 +76,7 @@ namespace RdtClient.Web.Controllers
var bytes = memoryStream.ToArray(); var bytes = memoryStream.ToArray();
await _torrents.UploadFile(bytes); await _torrents.UploadFile(bytes, false, false);
return Ok(); return Ok();
} }
@ -94,7 +92,7 @@ namespace RdtClient.Web.Controllers
{ {
try try
{ {
await _torrents.UploadMagnet(request.MagnetLink); await _torrents.UploadMagnet(request.MagnetLink, false, false);
return Ok(); return Ok();
} }
@ -127,7 +125,6 @@ namespace RdtClient.Web.Controllers
try try
{ {
await _torrents.Download(id); await _torrents.Download(id);
await _scheduler.Process();
return Ok(); return Ok();
} }

View file

@ -4,7 +4,6 @@ using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using RdtClient.Data.Models.Internal;
namespace RdtClient.Web namespace RdtClient.Web
{ {

View file

@ -5,9 +5,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.10" />
<PackageReference Include="Hangfire.Core" Version="1.7.10" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.3" />
@ -17,7 +14,6 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="3.1.3" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="3.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NReco.Logging.File" Version="1.0.5" /> <PackageReference Include="NReco.Logging.File" Version="1.0.5" />

View file

@ -1,6 +1,4 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire;
using Hangfire.MemoryStorage;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -14,7 +12,6 @@ using Microsoft.Extensions.Logging;
using RdtClient.Data; using RdtClient.Data;
using RdtClient.Data.Data; using RdtClient.Data.Data;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
using RdtClient.Service.Services;
namespace RdtClient.Web namespace RdtClient.Web
{ {
@ -83,19 +80,11 @@ namespace RdtClient.Web
options.Cookie.Name = "SID"; options.Cookie.Name = "SID";
}); });
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseMemoryStorage());
services.AddHangfireServer();
DiConfig.Config(services); DiConfig.Config(services);
Service.DiConfig.Config(services); Service.DiConfig.Config(services);
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger, DataContext dataContext, IScheduler scheduler) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger, DataContext dataContext)
{ {
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
@ -107,9 +96,9 @@ namespace RdtClient.Web
{ {
await next.Invoke(); await next.Invoke();
if (context.Response.StatusCode >= 404) if (context.Response.StatusCode != 200)
{ {
logger.LogWarning($"404: {context.Request.Path.Value}"); logger.LogWarning($"{context.Response.StatusCode}: {context.Request.Path.Value}");
} }
}); });
@ -118,9 +107,7 @@ namespace RdtClient.Web
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseHangfireServer();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder => app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
@ -134,8 +121,6 @@ namespace RdtClient.Web
}); });
dataContext.Migrate(); dataContext.Migrate();
scheduler.Start();
} }
} }
} }

View file

@ -9,5 +9,5 @@
<link rel="stylesheet" href="styles.8d1160aad8efbde1424d.css"></head> <link rel="stylesheet" href="styles.8d1160aad8efbde1424d.css"></head>
<body> <body>
<app-root></app-root> <app-root></app-root>
<script src="runtime-es2015.c9afb3256f2870e161de.js" type="module"></script><script src="runtime-es5.c9afb3256f2870e161de.js" nomodule defer></script><script src="polyfills-es5.0e4e1968447fab48e788.js" nomodule defer></script><script src="polyfills-es2015.bbb42ff2e1c488ff52d5.js" type="module"></script><script src="main-es2015.949c41a1b6780ff9f3a9.js" type="module"></script><script src="main-es5.949c41a1b6780ff9f3a9.js" nomodule defer></script></body> <script src="runtime-es2015.1eba213af0b233498d9d.js" type="module"></script><script src="runtime-es5.1eba213af0b233498d9d.js" nomodule defer></script><script src="polyfills-es5.9e286f6d9247438cbb02.js" nomodule defer></script><script src="polyfills-es2015.690002c25ea8557bb4b0.js" type="module"></script><script src="main-es2015.86b880448cfc913cfe80.js" type="module"></script><script src="main-es5.86b880448cfc913cfe80.js" nomodule defer></script></body>
</html> </html>

View file

@ -1,63 +0,0 @@
{
"runtimeTarget": {
"name": ".NETStandard,Version=v2.0/",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETStandard,Version=v2.0": {},
".NETStandard,Version=v2.0/": {
"RDNET/1.0.0": {
"dependencies": {
"NETStandard.Library": "2.0.3",
"Newtonsoft.Json": "12.0.3"
},
"runtime": {
"RDNET.dll": {}
}
},
"Microsoft.NETCore.Platforms/1.1.0": {},
"NETStandard.Library/2.0.3": {
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0"
}
},
"Newtonsoft.Json/12.0.3": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
"assemblyVersion": "12.0.0.0",
"fileVersion": "12.0.3.23909"
}
}
}
}
},
"libraries": {
"RDNET/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Microsoft.NETCore.Platforms/1.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==",
"path": "microsoft.netcore.platforms/1.1.0",
"hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512"
},
"NETStandard.Library/2.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
"path": "netstandard.library/2.0.3",
"hashPath": "netstandard.library.2.0.3.nupkg.sha512"
},
"Newtonsoft.Json/12.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==",
"path": "newtonsoft.json/12.0.3",
"hashPath": "newtonsoft.json.12.0.3.nupkg.sha512"
}
}
}

Binary file not shown.

Binary file not shown.