Switched out RDNET Dll with Nuget package, update Angular. Rewrote Download handler and removed references to Hangfire.
This commit is contained in:
parent
76b8513d6b
commit
bfba5c99fb
39 changed files with 1183 additions and 856 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -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
1183
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
@ -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),
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")]
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
if (!ActiveDownloads.TryAdd(download.DownloadId, download))
|
_bytesLastUpdate = 0;
|
||||||
{
|
_nextUpdate = DateTime.UtcNow.AddSeconds(1);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
download.Progress = 0;
|
var fileUrl = Download.Link;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
180
server/RdtClient.Service/Services/TaskRunner.cs
Normal file
180
server/RdtClient.Service/Services/TaskRunner.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -119,8 +108,6 @@ namespace RdtClient.Web
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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.
Loading…
Reference in a new issue