Upgrade packages.

Migrate Angular to new injector constructors.
This commit is contained in:
Roger Far 2026-03-14 13:39:51 -06:00
parent 351e1eb7c8
commit 683ac44c12
34 changed files with 1094 additions and 1788 deletions

View file

@ -1,14 +1,14 @@
const minorOnly = ['eslint'];
const minorOnly = ["eslint"];
const patchOnly = [];
module.exports = {
target: (name) => {
if (minorOnly.indexOf(name) > -1) {
return 'minor';
return "minor";
}
if (patchOnly.indexOf(name) > -1) {
return 'patch';
return "patch";
}
return 'latest';
}
return "latest";
},
};

2548
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -8,19 +8,20 @@
"watch": "ng build --watch --configuration development",
"update": "ng update --force --allow-dirty @angular/cli @angular/core @angular/cdk",
"lint": "ng lint",
"prettier": "prettier --write \"./**/*.{ts,html,json}\""
"prettier": "prettier --write .",
"precommit": "npm run prettier && npm run lint"
},
"private": true,
"dependencies": {
"@angular/animations": "^21.1.4",
"@angular/cdk": "^21.1.4",
"@angular/common": "^21.1.4",
"@angular/compiler": "^21.1.4",
"@angular/core": "^21.1.4",
"@angular/forms": "^21.1.4",
"@angular/platform-browser": "^21.1.4",
"@angular/platform-browser-dynamic": "^21.1.4",
"@angular/router": "^21.1.4",
"@angular/animations": "^21.2.4",
"@angular/cdk": "^21.2.2",
"@angular/common": "^21.2.4",
"@angular/compiler": "^21.2.4",
"@angular/core": "^21.2.4",
"@angular/forms": "^21.2.4",
"@angular/platform-browser": "^21.2.4",
"@angular/platform-browser-dynamic": "^21.2.4",
"@angular/router": "^21.2.4",
"@fortawesome/fontawesome-free": "^7.2.0",
"@microsoft/signalr": "^10.0.0",
"bulma": "^1.0.4",
@ -29,24 +30,24 @@
"filesize": "^11.0.13",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "^0.16.0"
"zone.js": "^0.16.1"
},
"devDependencies": {
"@angular-eslint/builder": "21.2.0",
"@angular-eslint/eslint-plugin": "21.2.0",
"@angular-eslint/eslint-plugin-template": "21.2.0",
"@angular-eslint/schematics": "21.2.0",
"@angular-eslint/template-parser": "21.2.0",
"@angular/build": "^21.1.4",
"@angular/cli": "^21.1.4",
"@angular/compiler-cli": "^21.1.4",
"@angular/language-service": "^21.1.4",
"@angular-eslint/builder": "21.3.0",
"@angular-eslint/eslint-plugin": "21.3.0",
"@angular-eslint/eslint-plugin-template": "21.3.0",
"@angular-eslint/schematics": "21.3.0",
"@angular-eslint/template-parser": "21.3.0",
"@angular/build": "^21.2.2",
"@angular/cli": "^21.2.2",
"@angular/compiler-cli": "^21.2.4",
"@angular/language-service": "^21.2.4",
"@types/file-saver": "^2.0.7",
"@types/file-saver-es": "^2.0.3",
"@types/node": "^25.2.3",
"@typescript-eslint/eslint-plugin": "^8.55.0",
"@typescript-eslint/parser": "^8.55.0",
"eslint": "^9.39.2",
"@types/node": "^25.5.0",
"@typescript-eslint/eslint-plugin": "^8.57.0",
"@typescript-eslint/parser": "^8.57.0",
"eslint": "^9.39.4",
"prettier": "^3.8.1",
"typescript": "5.9.3"
}

View file

@ -87,7 +87,7 @@
<div class="field" style="margin-top: 10px">
<div class="control">
<button class="button is-success" [disabled]="saving" [ngClass]="{ 'is-loading': saving }" (click)="ok()">
@if (type === 'torrent') {
@if (type === "torrent") {
<span>Add Torrent</span>
} @else {
<span>Add NZB</span>
@ -109,9 +109,7 @@
<option [ngValue]="3">Synology DownloadStation</option>
</select>
</div>
<p class="help">
Select which downloader is used to download this from the debrid provider to your host.
</p>
<p class="help">Select which downloader is used to download this from the debrid provider to your host.</p>
</div>
<div class="field">
@ -123,8 +121,8 @@
</select>
</div>
<p class="help">
When a download is finished on the provider, perform this action. Use this setting if you only want
to add files to your debrid provider but not download them to the host.
When a download is finished on the provider, perform this action. Use this setting if you only want to add files
to your debrid provider but not download them to the host.
</p>
</div>
@ -213,8 +211,8 @@
<input class="input" type="number" [(ngModel)]="finishedActionDelay" />
</div>
<p class="help">
When a download is finished on the provider, perform this action. Use this setting if you only want
to add files to your debrid provider but not download them to the host.
When a download is finished on the provider, perform this action. Use this setting if you only want to add files
to your debrid provider but not download them to the host.
</p>
</div>
@ -247,9 +245,7 @@
<div class="control">
<input class="input" type="number" step="1" [(ngModel)]="priority" />
</div>
<p class="help">
Set the priority where 1 is the highest. When empty it will be assigned the lowest priority.
</p>
<p class="help">Set the priority where 1 is the highest. When empty it will be assigned the lowest priority.</p>
</div>
</div>
</div>
@ -289,8 +285,8 @@
<input class="input" type="number" max="100000" min="0" step="1" [(ngModel)]="torrentLifetime" />
</div>
<p class="help">
The maximum lifetime of a download in minutes. When this time has passed, mark it as error. If the
download is completed, the lifetime setting will not apply. 0 to disable.
The maximum lifetime of a download in minutes. When this time has passed, mark it as error. If the download is
completed, the lifetime setting will not apply. 0 to disable.
</p>
</div>
</div>
@ -303,4 +299,3 @@
}
</div>
</div>

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { Router } from '@angular/router';
import { TorrentService } from 'src/app/torrent.service';
import { DownloadType, Torrent, TorrentFileAvailability } from '../models/torrent.model';
@ -15,6 +15,11 @@ import { NgClass } from '@angular/common';
standalone: true,
})
export class AddNewTorrentComponent implements OnInit {
private router = inject(Router);
private torrentService = inject(TorrentService);
private settingsService = inject(SettingsService);
private activatedRoute = inject(ActivatedRoute);
public type: 'torrent' | 'nzb' = 'torrent';
public fileName: string;
public magnetLink: string;
@ -53,13 +58,6 @@ export class AddNewTorrentComponent implements OnInit {
private selectedFile: File;
constructor(
private router: Router,
private torrentService: TorrentService,
private settingsService: SettingsService,
private activatedRoute: ActivatedRoute,
) {}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe((params) => {
if (params['type'] === 'nzb') {
@ -89,9 +87,7 @@ export class AddNewTorrentComponent implements OnInit {
.map((c) => c.trim())
.filter((c) => c.length > 0)
.filter((c, i, arr) => arr.findIndex((a) => a.toLowerCase() === c.toLowerCase()) === i);
const matchedCategory = this.categories.find(
(c) => c.toLowerCase() === (this.category ?? '').toLowerCase(),
);
const matchedCategory = this.categories.find((c) => c.toLowerCase() === (this.category ?? '').toLowerCase());
if (matchedCategory) {
this.category = matchedCategory;
}

View file

@ -2,9 +2,9 @@ import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>',
styles: [],
imports: [RouterOutlet],
selector: 'app-root',
template: '<router-outlet></router-outlet>',
styles: [],
imports: [RouterOutlet],
})
export class AppComponent {}

View file

@ -1,12 +1,12 @@
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router) {}
private router = inject(Router);
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(

View file

@ -1,16 +1,14 @@
import { APP_BASE_HREF } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
@Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(
private http: HttpClient,
@Inject(APP_BASE_HREF) private baseHref: string,
) {}
private http = inject(HttpClient);
private baseHref = inject(APP_BASE_HREF);
public isLoggedIn(): Observable<boolean> {
return this.http.get<boolean>(`${this.baseHref}Api/Authentication/IsLoggedIn`);

View file

@ -1,6 +1,6 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'decodeURI', })
@Pipe({ name: 'decodeURI' })
export class DecodeURIPipe implements PipeTransform {
transform(input: any) {
return decodeURI(input);

View file

@ -1,10 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Pipe, PipeTransform, inject } from '@angular/core';
import { Download } from './models/download.model';
import { FileSizePipe } from './filesize.pipe';
@Pipe({ name: 'downloadStatus' })
export class DownloadStatusPipe implements PipeTransform {
constructor(private pipe: FileSizePipe) {}
private pipe = inject(FileSizePipe);
transform(value: Download): string {
if (!value) {

View file

@ -1,7 +1,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { filesize } from 'filesize';
@Pipe({ name: 'filesize', })
@Pipe({ name: 'filesize' })
export class FileSizePipe implements PipeTransform {
private static transformOne(value: number, options?: any): string {
return filesize(value, options).toString();

View file

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';
import { FormsModule } from '@angular/forms';
@ -12,16 +12,14 @@ import { NgClass } from '@angular/common';
standalone: true,
})
export class LoginComponent {
private authService = inject(AuthService);
private router = inject(Router);
public userName: string;
public password: string;
public error: string;
public loggingIn: boolean;
constructor(
private authService: AuthService,
private router: Router,
) {}
public setUserName(event: Event): void {
this.userName = (event.target as any).value;
}

View file

@ -4,4 +4,4 @@
.notification {
margin-top: 52px;
}
}

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { NavigationEnd, Router, RouterLink } from '@angular/router';
import { AuthService } from '../auth.service';
import { Profile } from '../models/profile.model';
@ -13,17 +13,17 @@ import { NgClass, DatePipe } from '@angular/common';
standalone: true,
})
export class NavbarComponent implements OnInit {
private settingsService = inject(SettingsService);
private authService = inject(AuthService);
private router = inject(Router);
public showMobileMenu = false;
public profile: Profile;
public providerLink: string;
public version: string;
constructor(
private settingsService: SettingsService,
private authService: AuthService,
private router: Router,
) {
constructor() {
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.showMobileMenu = false;

View file

@ -1,9 +1,9 @@
import { Pipe, PipeTransform, SecurityContext, VERSION } from '@angular/core';
import { Pipe, PipeTransform, SecurityContext, VERSION, inject } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'nl2br', })
@Pipe({ name: 'nl2br' })
export class Nl2BrPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
private sanitizer = inject(DomSanitizer);
transform(value: string, sanitizeBeforehand?: boolean): string {
if (typeof value !== 'string') {

View file

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { AuthService } from '../auth.service';
import { FormsModule } from '@angular/forms';
import { NgClass } from '@angular/common';
@ -11,7 +11,7 @@ import { NgClass } from '@angular/common';
standalone: true,
})
export class ProfileComponent {
constructor(private authService: AuthService) {}
private authService = inject(AuthService);
public username: string;
public password: string;

View file

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { Profile } from './models/profile.model';
import { Setting } from './models/setting.model';
@ -10,10 +10,8 @@ import { Version } from './models/version.model';
providedIn: 'root',
})
export class SettingsService {
constructor(
private http: HttpClient,
@Inject(APP_BASE_HREF) private baseHref: string,
) {}
private http = inject(HttpClient);
private baseHref = inject(APP_BASE_HREF);
public get(): Observable<Setting[]> {
return this.http.get<Setting[]>(`${this.baseHref}Api/Settings`);

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { SettingsService } from 'src/app/settings.service';
import { Setting } from '../models/setting.model';
import { NgClass, KeyValuePipe } from '@angular/common';
@ -14,6 +14,8 @@ import { FileSizePipe } from '../filesize.pipe';
standalone: true,
})
export class SettingsComponent implements OnInit {
private settingsService = inject(SettingsService);
public activeTab = 0;
public tabs: Setting[] = [];
@ -35,8 +37,6 @@ export class SettingsComponent implements OnInit {
public canRegisterMagnetHandler = false;
constructor(private settingsService: SettingsService) {}
ngOnInit(): void {
this.reset();
this.canRegisterMagnetHandler = !!(window.isSecureContext && 'registerProtocolHandler' in navigator);

View file

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';
import { NgClass } from '@angular/common';
@ -12,6 +12,9 @@ import { FormsModule } from '@angular/forms';
standalone: true,
})
export class SetupComponent {
private authService = inject(AuthService);
private router = inject(Router);
public userName: string;
public password: string;
public provider = 0;
@ -22,11 +25,6 @@ export class SetupComponent {
public step: number = 1;
constructor(
private authService: AuthService,
private router: Router,
) {}
public setup(): void {
this.error = null;
this.working = true;

View file

@ -1,6 +1,6 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'sort', })
@Pipe({ name: 'sort' })
export class SortPipe implements PipeTransform {
transform(array: any[], field: string, order: 'asc' | 'desc' = 'asc'): any[] {
if (!Array.isArray(array)) {

View file

@ -1,10 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Pipe, PipeTransform, inject } from '@angular/core';
import { RealDebridStatus, Torrent } from './models/torrent.model';
import { FileSizePipe } from './filesize.pipe';
@Pipe({ name: 'status' })
export class TorrentStatusPipe implements PipeTransform {
constructor(private pipe: FileSizePipe) {}
private pipe = inject(FileSizePipe);
transform(torrent: Torrent): string {
if (torrent.error) {

View file

@ -10,16 +10,16 @@
<br />
Available: {{ diskSpaceStatus.availableSpaceGB }} GB | Resume at: {{ diskSpaceStatus.thresholdGB * 2 }} GB
<br />
<small>Last check: {{ diskSpaceStatus.lastCheckTime | date: 'short' }}</small>
<small>Last check: {{ diskSpaceStatus.lastCheckTime | date: "short" }}</small>
</div>
}
@if (rateLimitStatus?.nextDequeueTime) {
<div class="notification is-warning">
<strong>Debrid provider rate limit reached</strong>
<br />
Processing paused until {{ rateLimitStatus.nextDequeueTime | date: 'medium' }}
Processing paused until {{ rateLimitStatus.nextDequeueTime | date: "medium" }}
@if (rateLimitStatus.secondsRemaining > 0) {
({{ rateLimitStatus.secondsRemaining | number: '1.0-0' }} seconds remaining)
({{ rateLimitStatus.secondsRemaining | number: "1.0-0" }} seconds remaining)
}
</div>
}
@ -107,10 +107,16 @@
}
</div>
<div class="mobile-card-details">
<span class="mobile-card-detail"><span class="detail-label">Size</span> {{ torrent.rdSize | filesize }}</span>
<span class="mobile-card-detail"
><span class="detail-label">Size</span> {{ torrent.rdSize | filesize }}</span
>
<span class="mobile-card-detail"><span class="detail-label">Seeders</span> {{ torrent.rdSeeders }}</span>
<span class="mobile-card-detail"><span class="detail-label">Files</span> {{ torrent.files.length | number }}</span>
<span class="mobile-card-detail"><span class="detail-label">Downloads</span> {{ torrent.downloads.length | number }}</span>
<span class="mobile-card-detail"
><span class="detail-label">Files</span> {{ torrent.files.length | number }}</span
>
<span class="mobile-card-detail"
><span class="detail-label">Downloads</span> {{ torrent.downloads.length | number }}</span
>
</div>
</div>
</div>

View file

@ -32,7 +32,7 @@ table {
flex-shrink: 0;
padding-top: 0.125rem;
input[type='checkbox'] {
input[type="checkbox"] {
width: 1.1rem;
height: 1.1rem;
cursor: pointer;

View file

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Torrent } from '../models/torrent.model';
import { DiskSpaceStatus } from '../models/disk-space-status.model';
@ -19,6 +19,9 @@ import { FileSizePipe } from '../filesize.pipe';
standalone: true,
})
export class TorrentTableComponent implements OnInit, OnDestroy {
private router = inject(Router);
private torrentService = inject(TorrentService);
public torrents: Torrent[] = [];
public selectedTorrents: string[] = [];
public error: string;
@ -57,11 +60,6 @@ export class TorrentTableComponent implements OnInit, OnDestroy {
private mobileQuery: MediaQueryList;
private mobileQueryListener: (e: MediaQueryListEvent) => void;
constructor(
private router: Router,
private torrentService: TorrentService,
) {}
ngOnInit(): void {
this.mobileQuery = window.matchMedia('(max-width: 768px)');
this.isMobile = this.mobileQuery.matches;

View file

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import * as signalR from '@microsoft/signalr';
import { Observable, Subject } from 'rxjs';
import { Torrent, TorrentFileAvailability } from './models/torrent.model';
@ -11,16 +11,16 @@ import { APP_BASE_HREF } from '@angular/common';
providedIn: 'root',
})
export class TorrentService {
private http = inject(HttpClient);
private baseHref = inject(APP_BASE_HREF);
public update$: Subject<Torrent[]> = new Subject();
public diskSpaceStatus$: Subject<DiskSpaceStatus> = new Subject();
public rateLimitStatus$: Subject<RateLimitStatus> = new Subject();
private connection: signalR.HubConnection;
constructor(
private http: HttpClient,
@Inject(APP_BASE_HREF) private baseHref: string,
) {
constructor() {
this.connect();
}

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { saveAs } from 'file-saver-es';
import { Torrent } from '../models/torrent.model';
@ -28,6 +28,10 @@ import { FileSizePipe } from '../filesize.pipe';
standalone: true,
})
export class TorrentComponent implements OnInit {
private activatedRoute = inject(ActivatedRoute);
private router = inject(Router);
private torrentService = inject(TorrentService);
public torrent: Torrent;
public activeTab: number = 0;
@ -66,12 +70,6 @@ export class TorrentComponent implements OnInit {
public updating: boolean;
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private torrentService: TorrentService,
) {}
ngOnInit(): void {
this.activatedRoute.params.subscribe((params) => {
const torrentId = params['id'];

View file

@ -1,7 +1,6 @@
import { enableProdMode, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';
import { FileSizePipe } from './app/filesize.pipe';
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
@ -18,12 +17,12 @@ if (environment.production) {
}
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),importProvidersFrom(BrowserModule, AppRoutingModule, FormsModule, ClipboardModule),
FileSizePipe,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: APP_BASE_HREF, useValue: (window as any)['_app_base'] || '/' },
provideHttpClient(withInterceptorsFromDi()),
]
})
.catch((err) => console.error(err));
providers: [
provideZoneChangeDetection(),
importProvidersFrom(BrowserModule, AppRoutingModule, FormsModule, ClipboardModule),
FileSizePipe,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: APP_BASE_HREF, useValue: (window as any)['_app_base'] || '/' },
provideHttpClient(withInterceptorsFromDi()),
],
}).catch((err) => console.error(err));

View file

@ -8,11 +8,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.3">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.5" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -15,9 +15,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="SharpCompress" Version="0.42.1" />
<PackageReference Include="SharpCompress" Version="[0.42.1]" />
<PackageReference Include="TestableIO.System.IO.Abstractions" Version="22.1.0" />
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="22.1.0" />
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" Version="22.1.0" />

View file

@ -330,7 +330,8 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
usenetApiMock.Setup(m => m.AddFileAsync(bytes, It.IsAny<Int32>(), name, It.IsAny<String?>(), It.IsAny<Boolean>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<UsenetAddResult> { Data = new UsenetAddResult { Hash = "new-hash" } });
.ReturnsAsync(new Response<UsenetAddResult> { Data = new()
{ Hash = "new-hash" } });
// Act
var result = await clientMock.Object.AddNzbFile(bytes, name);
@ -605,7 +606,9 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
userApiMock.Setup(m => m.GetAsync(true, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<User> { Data = new User { Settings = new UserSettings { SeedTorrents = 5 } } });
.ReturnsAsync(new Response<User> { Data = new()
{ Settings = new()
{ SeedTorrents = 5 } } });
torrentsApiMock.Setup(m => m.AddMagnetAsync(magnetLink, 5, It.IsAny<Boolean>(), It.IsAny<String?>(), false, It.IsAny<CancellationToken>()))
.ThrowsAsync(new TorBoxException("active_limit", "Active limit reached"));
@ -632,10 +635,12 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
userApiMock.Setup(m => m.GetAsync(true, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<User> { Data = new User { Settings = new UserSettings { SeedTorrents = 5 } } });
.ReturnsAsync(new Response<User> { Data = new()
{ Settings = new()
{ SeedTorrents = 5 } } });
torrentsApiMock.Setup(m => m.AddMagnetAsync(magnetLink, 5, It.IsAny<Boolean>(), It.IsAny<String?>(), false, It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("slow_down"));
.ThrowsAsync(new("slow_down"));
// Act & Assert
await Assert.ThrowsAsync<RateLimitException>(() => clientMock.Object.AddTorrentMagnet(magnetLink));
@ -657,7 +662,9 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
userApiMock.Setup(m => m.GetAsync(true, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<User> { Data = new User { Settings = new UserSettings { SeedTorrents = 5 } } });
.ReturnsAsync(new Response<User> { Data = new()
{ Settings = new()
{ SeedTorrents = 5 } } });
torrentsApiMock.Setup(m => m.AddMagnetAsync(magnetLink, 5, It.IsAny<Boolean>(), It.IsAny<String?>(), false, It.IsAny<CancellationToken>()))
.ThrowsAsync(new RateLimitException("TorBox rate limit exceeded", TimeSpan.FromMinutes(60)));
@ -683,10 +690,12 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
userApiMock.Setup(m => m.GetAsync(true, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<User> { Data = new User { Settings = new UserSettings { SeedTorrents = 5 } } });
.ReturnsAsync(new Response<User> { Data = new()
{ Settings = new()
{ SeedTorrents = 5 } } });
torrentsApiMock.Setup(m => m.AddMagnetAsync(magnetLink, 5, It.IsAny<Boolean>(), It.IsAny<String?>(), false, It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("Wrapped", new RateLimitException("TorBox rate limit exceeded", TimeSpan.FromMinutes(60))));
.ThrowsAsync(new("Wrapped", new RateLimitException("TorBox rate limit exceeded", TimeSpan.FromMinutes(60))));
// Act & Assert
var ex = await Assert.ThrowsAsync<RateLimitException>(() => clientMock.Object.AddTorrentMagnet(magnetLink));
@ -708,7 +717,9 @@ public class TorBoxDebridClientTest
clientMock.Protected().Setup<ITorBoxNetClient>("GetClient", ItExpr.IsAny<String>()).Returns(torBoxClientMock.Object);
userApiMock.Setup(m => m.GetAsync(true, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Response<User> { Data = new User { Settings = new UserSettings { SeedTorrents = 5 } } });
.ReturnsAsync(new Response<User> { Data = new()
{ Settings = new()
{ SeedTorrents = 5 } } });
torrentsApiMock.Setup(m => m.AddFileAsync(bytes, 5, It.IsAny<Boolean>(), It.IsAny<String?>(), false, It.IsAny<CancellationToken>()))
.ThrowsAsync(new TorBoxException("active_limit", "Active limit reached"));

View file

@ -119,7 +119,7 @@ public static class DiConfig
if (delay >= timeout)
{
return new ValueTask<TimeSpan?>((TimeSpan?)null);
return new((TimeSpan?)null);
}
return new(delay);

View file

@ -12,18 +12,18 @@
<PackageReference Include="AllDebrid.NET" Version="1.0.18" />
<PackageReference Include="Aria2.NET" Version="1.0.6" />
<PackageReference Include="DebridLinkFr.NET" Version="1.0.4" />
<PackageReference Include="Downloader" Version="4.1.1" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.3.0" />
<PackageReference Include="Downloader" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.4.0" />
<PackageReference Include="MonoTorrent" Version="3.0.2" />
<PackageReference Include="Polly" Version="8.6.5" />
<PackageReference Include="Polly" Version="8.6.6" />
<PackageReference Include="Premiumize.NET" Version="1.0.10" />
<PackageReference Include="RateLimitHeaders.Polly" Version="1.0.0" />
<PackageReference Include="RD.NET" Version="2.1.11" />
<PackageReference Include="Serilog" Version="4.3.1" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="SharpCompress" Version="0.42.1" />
<PackageReference Include="Synology.Api.Client" Version="0.3.93" />
<PackageReference Include="SharpCompress" Version="[0.42.1]" />
<PackageReference Include="Synology.Api.Client" Version="[0.3.93]" />
<PackageReference Include="TestableIO.System.IO.Abstractions" Version="22.1.0" />
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" Version="22.1.0" />
<PackageReference Include="TorBox.NET" Version="1.6.2" />

View file

@ -10,9 +10,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="SharpCompress" Version="0.42.1" />
<PackageReference Include="SharpCompress" Version="[0.42.1]" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>

View file

@ -30,18 +30,18 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.3">
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.5" />
<PackageReference Include="Serilog" Version="4.3.1" />
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="SharpCompress" Version="0.42.1" />
<PackageReference Include="SharpCompress" Version="[0.42.1]" />
</ItemGroup>
<ItemGroup>