Merge pull request #818 from Cucumberrbob/feat/angular-control-flow

migrate to new Angular Control Flow syntax
This commit is contained in:
Roger Far 2025-05-18 11:13:50 -06:00 committed by GitHub
commit 772816ced0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 899 additions and 760 deletions

View file

@ -84,11 +84,15 @@
</div>
</div>
</div>
<p class="help" *ngIf="provider === 'AllDebrid'">
@if (provider === "AllDebrid") {
<p class="help">
When downloading with AllDebrid it cannot be guaranteed that only files above this limit will be download as
some files are grouped together in 1 large archive.
</p>
<p class="help" *ngIf="downloadAction === 2">This setting does not apply to manually selected files.</p>
}
@if (downloadAction === 2) {
<p class="help">This setting does not apply to manually selected files.</p>
}
</div>
<div class="field">
@ -104,8 +108,12 @@
Select only the files that are matching this regular expression. Only use this setting OR the Exclude files
setting, not both.
</p>
<p class="help" *ngIf="downloadAction === 2">This setting does not apply to manually selected files.</p>
<p class="help is-danger" *ngIf="includeRegexError">{{ includeRegexError }}</p>
@if (downloadAction === 2) {
<p class="help">This setting does not apply to manually selected files.</p>
}
@if (includeRegexError) {
<p class="help is-danger">{{ includeRegexError }}</p>
}
</div>
<div class="field">
@ -121,8 +129,12 @@
Ignore files that are matching this regular expression. Only use this setting OR the Include files setting, not
both.
</p>
<p class="help" *ngIf="downloadAction === 2">This setting does not apply to manually selected files.</p>
<p class="help is-danger" *ngIf="excludeRegexError">{{ excludeRegexError }}</p>
@if (downloadAction === 2) {
<p class="help">This setting does not apply to manually selected files.</p>
}
@if (excludeRegexError) {
<p class="help is-danger">{{ excludeRegexError }}</p>
}
</div>
<div class="field">
@ -130,8 +142,10 @@
<div class="control select is-fullwidth">
<select [(ngModel)]="finishedAction">
<option [ngValue]="0">Do nothing</option>
<option [ngValue]="1" *ngIf="downloadClient !== 2">Remove torrent from provider and client</option>
<option [ngValue]="2" *ngIf="downloadClient !== 2">Remove torrent from provider</option>
@if (downloadClient !== 2) {
<option [ngValue]="1">Remove torrent from provider and client</option>
<option [ngValue]="2">Remove torrent from provider</option>
}
<option [ngValue]="3">Remove torrent from client</option>
</select>
</div>
@ -196,7 +210,9 @@
<div class="field">
<div class="control">
<div class="notification is-danger is-light" *ngIf="error">{{ error }}</div>
@if (error) {
<div class="notification is-danger is-light">{{ error }}</div>
}
</div>
</div>

View file

@ -41,9 +41,11 @@
Login
</button>
</div>
<div class="notification is-danger is-light" *ngIf="error?.length > 0">
@if (error?.length > 0) {
<div class="notification is-danger is-light">
{{ error }}
</div>
}
</form>
</div>
</div>

View file

@ -38,13 +38,18 @@
</span>
<span>Settings</span>
</a>
<a class="navbar-item" *ngIf="profile" href="{{ providerLink }}" target="_blank" rel="noopener">
@if (profile) {
<a class="navbar-item" href="{{ providerLink }}" target="_blank" rel="noopener">
<span class="icon">
<i class="fas fa-euro-sign" aria-hidden="true"></i>
</span>
<span *ngIf="profile.expiration">Premium Status: {{ profile.expiration | date }}</span>
<span *ngIf="!profile.expiration" class="no-premium">Not premium</span>
@if (profile.expiration) {
<span>Premium Status: {{ profile.expiration | date }}</span>
} @else {
<span class="no-premium">Not premium</span>
}
</a>
}
</div>
<div class="navbar-end">
@ -61,19 +66,20 @@
</div>
</div>
</nav>
<div
class="notification"
[ngClass]="profile.isInsecure ? 'is-danger' : 'is-warning'"
*ngIf="
@if (
profile &&
(!profile.disableUpdateNotification || profile.isInsecure) &&
profile.latestVersion &&
profile.currentVersion !== profile.latestVersion
"
>
<span *ngIf="profile.isInsecure"> Your current version is insecure. </span>
) {
<div class="notification" [ngClass]="profile.isInsecure ? 'is-danger' : 'is-warning'">
@if (profile.isInsecure) {
<span> Your current version is insecure. </span>
}
<span>
Version {{ profile.latestVersion }} of RealDebrid Client was found. You are currently on version
{{ profile.currentVersion }}.
</span>
</div>
}

View file

@ -19,13 +19,17 @@
<div class="field">
<div class="control">
<div class="notification is-danger is-light" *ngIf="error !== null">Error saving: {{ error }}</div>
@if (error !== null) {
<div class="notification is-danger is-light">Error saving: {{ error }}</div>
}
</div>
</div>
<div class="field">
<div class="control">
<div class="notification is-success is-light" *ngIf="success">Your profile has been updated</div>
@if (success) {
<div class="notification is-success is-light">Your profile has been updated</div>
}
</div>
</div>

View file

@ -1,45 +1,60 @@
<div class="tabs">
<ul>
<li [ngClass]="{ 'is-active': activeTab === i }" (click)="activeTab = i" *ngFor="let tab of tabs; let i = index">
@for (tab of tabs; track tab.key; let i = $index) {
<li [ngClass]="{ 'is-active': activeTab === i }" (click)="activeTab = i">
<a>{{ tab.displayName }}</a>
</li>
}
<li [ngClass]="{ 'is-active': activeTab === 99 }" (click)="activeTab = 99">
<a>Speed Tests</a>
</li>
</ul>
</div>
<div *ngFor="let tab of tabs; let i = index" [hidden]="activeTab !== i">
@for (tab of tabs; track tab.key; let i = $index) {
<div [hidden]="activeTab !== i">
<h3>{{ tab.description }}</h3>
<ng-container *ngFor="let setting of tab.settings">
<h3 *ngIf="setting.type === 'Object'" class="title is-3" style="margin-top: 1.2rem">{{ setting.displayName }}</h3>
@for (setting of tab.settings; track setting.key) {
@if (setting.type === "Object") {
<h3 class="title is-3" style="margin-top: 1.2rem">{{ setting.displayName }}</h3>
}
<div class="field">
<label class="label" *ngIf="setting.type !== 'Boolean' && setting.type !== 'Object'">{{
setting.displayName
}}</label>
<ng-container [ngSwitch]="setting.type">
<div class="control" *ngSwitchCase="'String'">
@if (setting.type !== "Boolean" && setting.type !== "Object") {
<label class="label">{{ setting.displayName }}</label>
}
@switch (setting.type) {
@case ("String") {
<div class="control">
<input class="input" type="text" [(ngModel)]="setting.value" />
</div>
<div class="control" *ngSwitchCase="'Int32'">
}
@case ("Int32") {
<div class="control">
<input class="input" type="number" [(ngModel)]="setting.value" />
</div>
<label class="checkbox" *ngSwitchCase="'Boolean'">
}
@case ("Boolean") {
<label class="checkbox">
<input type="checkbox" [(ngModel)]="setting.value" />
{{ setting.displayName }}
</label>
<div class="control select is-fullwidth" *ngSwitchCase="'Enum'">
}
@case ("Enum") {
<div class="control select is-fullwidth">
<select [(ngModel)]="setting.value">
<option [value]="kvp.key" *ngFor="let kvp of setting.enumValues | keyvalue">{{ kvp.value }}</option>
@for (kvp of setting.enumValues | keyvalue; track kvp) {
<option [value]="kvp.key">{{ kvp.value }}</option>
}
</select>
</div>
<ng-container *ngSwitchCase="'Object'"></ng-container>
<div class="control" *ngSwitchDefault>Invalid setting type {{ setting.type }}</div>
</ng-container>
}
@case ("Object") {}
@default {
<div class="control">Invalid setting type {{ setting.type }}</div>
}
}
<p class="help" [innerHtml]="setting.description | nl2br"></p>
<ng-container *ngIf="setting.key === 'DownloadClient:Aria2cSecret'">
@if (setting.key === "DownloadClient:Aria2cSecret") {
<button
class="button is-warning"
(click)="testAria2cConnection()"
@ -48,100 +63,111 @@
>
Test aria2 connection
</button>
<div class="notification is-danger is-light" style="margin-top: 1rem" *ngIf="testAria2cConnectionError">
@if (testAria2cConnectionError) {
<div class="notification is-danger is-light" style="margin-top: 1rem">
Could connect to Aria2 client<br />
{{ testAria2cConnectionError }}
</div>
<div class="notification is-success is-light" style="margin-top: 1rem" *ngIf="testAria2cConnectionSuccess">
}
@if (testAria2cConnectionSuccess) {
<div class="notification is-success is-light" style="margin-top: 1rem">
Found Aria2 client version {{ testAria2cConnectionSuccess }}
</div>
</ng-container>
}
}
</div>
</ng-container>
}
</div>
}
<div *ngIf="activeTab === 99">
@if (activeTab === 99) {
<div>
<div class="field">
<label class="label">Test download path permissions</label>
<div class="control">
@if (!testPathError && !testPathSuccess) {
<button
class="button is-warning"
(click)="testDownloadPath()"
[disabled]="saving"
[ngClass]="{ 'is-loading': saving }"
*ngIf="!testPathError && !testPathSuccess"
>
Test permissions
</button>
<div class="notification is-danger is-light" *ngIf="testPathError">
}
@if (testPathError) {
<div class="notification is-danger is-light">
Could not test your download path<br />
{{ testPathError }}
</div>
<div class="notification is-success is-light" *ngIf="testPathSuccess">Your download path looks good!</div>
}
@if (testPathSuccess) {
<div class="notification is-success is-light">Your download path looks good!</div>
}
</div>
<div class="help">This will check if the download folder has write permissions.</div>
</div>
<div class="field">
<label class="label">Test Real-Debrid download speed</label>
<div class="control">
@if (testDownloadSpeedError) {
<div class="notification is-danger is-light">
Could not test your download speed<br />
{{ testDownloadSpeedError }}
</div>
} @else if (testDownloadSpeedSuccess) {
<div class="notification is-success is-light">Download speed {{ testDownloadSpeedSuccess | filesize }}/s</div>
} @else {
<button
class="button is-warning"
(click)="testDownloadSpeed()"
[disabled]="saving"
[ngClass]="{ 'is-loading': saving }"
*ngIf="!testDownloadSpeedError && !testDownloadSpeedSuccess"
>
Test download speed
</button>
<div class="notification is-danger is-light" *ngIf="testDownloadSpeedError">
Could not test your download speed<br />
{{ testDownloadSpeedError }}
</div>
<div class="notification is-success is-light" *ngIf="testDownloadSpeedSuccess">
Download speed {{ testDownloadSpeedSuccess | filesize }}/s
</div>
}
</div>
<div class="help">
This will attempt to download a 10GB file from Real-Debrid. When 50MB has been downloaded the test will stop.
</div>
</div>
<div class="field">
<label class="label">Test download folder write speed</label>
<div class="control">
@if (testWriteSpeedError) {
<div class="notification is-danger is-light">
Could not test your download speed<br />
{{ testWriteSpeedError }}
</div>
} @else if (testWriteSpeedSuccess) {
<div class="notification is-success is-light">Write speed {{ testWriteSpeedSuccess | filesize }}/s</div>
} @else {
<button
class="button is-warning"
(click)="testWriteSpeed()"
[disabled]="saving"
[ngClass]="{ 'is-loading': saving }"
*ngIf="!testWriteSpeedError && !testWriteSpeedSuccess"
>
Test write speed
</button>
<div class="notification is-danger is-light" *ngIf="testWriteSpeedError">
Could not test your download speed<br />
{{ testWriteSpeedError }}
</div>
<div class="notification is-success is-light" *ngIf="testWriteSpeedSuccess">
Write speed {{ testWriteSpeedSuccess | filesize }}/s
</div>
}
</div>
<div class="help">This will write a small file to your download folder to see how fast it can write to it.</div>
</div>
</div>
}
<div class="field">
<div class="control">
<div class="notification is-danger is-light" *ngIf="error?.length > 0">Error saving settings: {{ error }}</div>
@if (error?.length > 0) {
<div class="notification is-danger is-light">Error saving settings: {{ error }}</div>
}
</div>
</div>
<div class="field" *ngIf="activeTab === 0">
@if (activeTab === 0) {
<div class="field">
<label class="label">Register client as magnet link handler</label>
<div class="control">
<button
@ -157,11 +183,15 @@
</div>
<p class="help">
@if (canRegisterMagnetHandler) {
This will attempt to register the client as your browser's default handler for magnet links and automatically open
them in the new torrent screen for downloading.
This will attempt to register the client as your browser's default handler for magnet links and automatically
open them in the new torrent screen for downloading.
} @else {
Magnet link registration is unavailable. Your
<a href="https://caniuse.com/mdn-api_navigator_registerprotocolhandler" target="_blank" rel="noopener noreferrer">
<a
href="https://caniuse.com/mdn-api_navigator_registerprotocolhandler"
target="_blank"
rel="noopener noreferrer"
>
browser may not support this feature
</a>
, or the client is not being served in a
@ -176,11 +206,14 @@
}
</p>
</div>
}
<div class="field" *ngIf="activeTab < 99">
@if (activeTab < 99) {
<div class="field">
<div class="control">
<button class="button is-success" (click)="ok()" [disabled]="saving" [ngClass]="{ 'is-loading': saving }">
Save Settings
</button>
</div>
</div>
}

View file

@ -4,7 +4,8 @@
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<img src="assets/logo.png" />
<div class="box" *ngIf="step === 1">
@if (step === 1) {
<div class="box">
<div class="notification is-primary">
Welcome to Real-Debrid Client. Please create your account by entering a username and password.
</div>
@ -32,13 +33,17 @@
Setup
</button>
</div>
<div class="notification is-danger is-light" *ngIf="error?.length > 0">
@if (error?.length > 0) {
<div class="notification is-danger is-light">
{{ error }}
</div>
}
</form>
</div>
}
<div class="box" *ngIf="step === 2">
@if (step === 2) {
<div class="box">
<div class="notification is-primary">
To be able to use the Real-Debrid Client you need a premium subscription to download torrents.
<br /><br />
@ -80,36 +85,46 @@
<div class="control">
<input type="text" placeholder="" class="input" name="token" [(ngModel)]="token" required />
</div>
<p class="help" *ngIf="provider === 0">
@if (provider === 0) {
<p class="help">
You can find your API key here:
<a href="https://real-debrid.com/apitoken" target="_blank" rel="noopener"
>https://real-debrid.com/apitoken</a
>.
</p>
<p class="help" *ngIf="provider === 1">
}
@if (provider === 1) {
<p class="help">
You can find your API key here:
<a href="https://alldebrid.com/apikeys/" target="_blank" rel="noopener"
>https://alldebrid.com/apikeys/</a
>.
</p>
<p class="help" *ngIf="provider === 2">
}
@if (provider === 2) {
<p class="help">
You can find your API key here:
<a href="https://www.premiumize.me/account" target="_blank" rel="noopener"
>https://www.premiumize.me/account</a
>.
</p>
<p class="help" *ngIf="provider === 3">
}
@if (provider === 3) {
<p class="help">
You can find your API key here:
<a href="https://torbox.app/settings" target="_blank" rel="noopener">https://torbox.app/settings</a>.
<a href="https://torbox.app/settings" target="_blank" rel="noopener">https://torbox.app/settings</a
>.
</p>
<p class="help" *ngIf="provider === 4">
}
@if (provider === 4) {
<p class="help">
You can find your API key here:
<a href="https://debrid-link.com/webapp/apikey" target="_blank" rel="noopener"
>https://debrid-link.com/webapp/apikey</a
>.
</p>
}
</div>
<div class="field">
<button
class="button is-success"
@ -120,12 +135,16 @@
Setup
</button>
</div>
<div class="notification is-danger is-light" *ngIf="error?.length > 0">
@if (error?.length > 0) {
<div class="notification is-danger is-light">
{{ error }}
</div>
}
</div>
}
<div class="box" *ngIf="step === 3">
@if (step === 3) {
<div class="box">
<div class="notification is-primary">
You are now connected to Real-Debrid! To setup Radarr or Sonarr, please following the instructions here:
<a href="https://github.com/rogerfar/rdt-client/" target="_blank" rel="noopener"
@ -143,6 +162,7 @@
</button>
</div>
</div>
}
</div>
</div>
</div>

View file

@ -1,7 +1,9 @@
<div class="notification is-danger is-light" *ngIf="error && error.length > 0">
An error has occured: {{ error }}<br />
@if (error && error.length > 0) {
<div class="notification is-danger is-light">
An error has occurred: {{ error }}<br />
Please refresh the screen after fixing this error.
</div>
}
<div class="table-container">
<table class="table is-fullwidth is-hoverable">
<thead>
@ -25,7 +27,8 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let torrent of torrents | sort: sortProperty : sortDirection; trackBy: trackByMethod">
@for (torrent of torrents | sort: sortProperty : sortDirection; track torrent.torrentId) {
<tr>
<td>
<input
type="checkbox"
@ -61,36 +64,22 @@
{{ torrent | status }}
</td>
</tr>
}
</tbody>
</table>
<div class="flex-container">
<button
class="button is-danger"
(click)="showDeleteModal()"
[disabled]="selectedTorrents.length === 0"
*ngIf="torrents.length > 0"
>
@if (torrents.length > 0) {
<button class="button is-danger" (click)="showDeleteModal()" [disabled]="selectedTorrents.length === 0">
Delete Selected
</button>
<button
class="button is-primary"
(click)="showRetryModal()"
[disabled]="selectedTorrents.length === 0"
*ngIf="torrents.length > 0"
>
<button class="button is-primary" (click)="showRetryModal()" [disabled]="selectedTorrents.length === 0">
Retry Selected
</button>
<button
class="button is-primary"
(click)="changeSettingsModal()"
[disabled]="selectedTorrents.length === 0"
*ngIf="torrents.length > 0"
>
<button class="button is-primary" (click)="changeSettingsModal()" [disabled]="selectedTorrents.length === 0">
Change Settings
</button>
}
</div>
</div>
@ -131,9 +120,9 @@
<div class="notification is-primary">
Deleting a torrent from Real-Debrid will automatically delete it here too.
</div>
<div class="notification is-danger is-light" *ngIf="deleteError?.length > 0">
Error deleting torrent: {{ deleteError }}
</div>
@if (deleteError?.length > 0) {
<div class="notification is-danger is-light">Error deleting torrent: {{ deleteError }}</div>
}
</section>
<footer class="modal-card-foot">
<button
@ -164,9 +153,9 @@
This action will delete all the torrent data + all local downloads. Then it will re-add the original magnet link
or torrent file to the debrid provider.
</p>
<div class="notification is-danger is-light" *ngIf="retryError?.length > 0">
Error retrying torrent: {{ retryError }}
</div>
@if (retryError?.length > 0) {
<div class="notification is-danger is-light">Error retrying torrent: {{ retryError }}</div>
}
</section>
<footer class="modal-card-foot">
<button
@ -296,9 +285,9 @@
</p>
</div>
<div class="notification is-danger is-light" *ngIf="changeSettingsError?.length > 0">
Error changing settings: {{ changeSettingsError }}
</div>
@if (changeSettingsError?.length > 0) {
<div class="notification is-danger is-light">Error changing settings: {{ changeSettingsError }}</div>
}
</section>
<footer class="modal-card-foot">
<button

View file

@ -71,10 +71,6 @@ export class TorrentTableComponent implements OnInit {
this.router.navigate([`/torrent/${torrentId}`]);
}
public trackByMethod(index: number, el: Torrent): string {
return el.torrentId;
}
public toggleDeleteSelectAll(event: any) {
this.selectedTorrents = [];

View file

@ -12,13 +12,16 @@
</ul>
</div>
<div *ngIf="torrent === null || torrent === undefined">
@if (torrent === null || torrent === undefined) {
<div>
<div class="fa-3x">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<div *ngIf="torrent !== null && torrent !== undefined">
<div class="flex-container" *ngIf="activeTab === 0">
} @else {
<div>
@if (activeTab === 0) {
<div class="flex-container">
<div style="flex: 1 1 0">
<div class="field is-grouped">
<div class="control">
@ -53,39 +56,65 @@
</div>
<div class="field">
<label class="label">Downloader</label>
<ng-container [ngSwitch]="torrent.downloadClient">
<ng-container *ngSwitchCase="0">Internal Downloader</ng-container>
<ng-container *ngSwitchCase="1">Bezadd</ng-container>
<ng-container *ngSwitchCase="2">Aria2c</ng-container>
<ng-container *ngSwitchCase="3">Symlink Downloader</ng-container>
<ng-component *ngSwitchCase="4">Synology DownloadStation</ng-component>
</ng-container>
@switch (torrent.downloadClient) {
@case (0) {
Internal Downloader
}
@case (1) {
Bezadd
}
@case (2) {
Aria2c
}
@case (3) {
Symlink Downloader
}
@case (4) {
Synology DownloadStation
}
}
</div>
<div class="field">
<label class="label">Post Download Action</label>
<ng-container [ngSwitch]="torrent.hostDownloadAction">
<ng-container *ngSwitchCase="0">Download all files to host</ng-container>
<ng-container *ngSwitchCase="1">Don't download files to host</ng-container>
</ng-container>
@switch (torrent.hostDownloadAction) {
@case (0) {
Download all files to host
}
@case (1) {
Don't download files to host
}
}
</div>
<div class="field">
<label class="label">Post Torrent Download Action</label>
<ng-container [ngSwitch]="torrent.downloadAction">
<ng-container *ngSwitchCase="0">Download all files above a certain size</ng-container>
<ng-container *ngSwitchCase="1"
>Download all available files on Real-Debrid above a certain size</ng-container
>
<ng-container *ngSwitchCase="2">Pick files I want to download</ng-container>
</ng-container>
@switch (torrent.downloadAction) {
@case (0) {
Download all files above a certain size
}
@case (1) {
Download all available files on Real-Debrid above a certain size
}
@case (2) {
Pick files I want to download
}
}
</div>
<div class="field">
<label class="label">Finished action</label>
<ng-container [ngSwitch]="torrent.finishedAction">
<ng-container *ngSwitchCase="0">Do nothing</ng-container>
<ng-container *ngSwitchCase="1">Remove torrent from Real-Debrid and Real-Debrid Client</ng-container>
<ng-container *ngSwitchCase="2">Remove torrent from Real-Debrid</ng-container>
<ng-container *ngSwitchCase="3">Remove torrent from client</ng-container>
</ng-container>
@switch (torrent.finishedAction) {
@case (0) {
Do nothing
}
@case (1) {
Remove torrent from Real-Debrid and Real-Debrid Client
}
@case (2) {
Remove torrent from Real-Debrid
}
@case (3) {
Remove torrent from client
}
}
</div>
<div class="field">
<label class="label">Minimum file size to download</label>
@ -99,34 +128,42 @@
<label class="label">Exclude files</label>
{{ torrent.excludeRegex }}
</div>
<div class="field" *ngIf="!torrent.isFile">
@if (!torrent.isFile) {
<div class="field">
<label class="label">Magnet</label>
<span [cdkCopyToClipboard]="torrent.fileOrMagnet" (click)="copied = true" *ngIf="!copied"
>Click to copy magnet link to clipboard</span
>
<span *ngIf="copied">Link copied to clipboard!</span>
@if (!copied) {
<span [cdkCopyToClipboard]="torrent.fileOrMagnet" (click)="copied = true">
Click to copy magnet link to clipboard
</span>
} @else {
<span>Link copied to clipboard!</span>
}
</div>
<div class="field" *ngIf="torrent.isFile">
} @else {
<div class="field">
<label class="label">Torrent file</label>
<span (click)="download()">Click to download torrent file</span>
</div>
}
<div class="field">
<label class="label">Added on</label>
{{ torrent.added | date: "fullDate" }} {{ torrent.added | date: "mediumTime" }}
</div>
<div class="field">
<label class="label">Files selected on</label>
<ng-container *ngIf="torrent.filesSelected === null">(no files selected yet) </ng-container>
<ng-container *ngIf="torrent.filesSelected !== null">
@if (torrent.filesSelected === null) {
(no files selected yet)
} @else {
{{ torrent.filesSelected | date: "fullDate" }} {{ torrent.filesSelected | date: "mediumTime" }}
</ng-container>
}
</div>
<div class="field">
<label class="label">Completed on</label>
<ng-container *ngIf="torrent.completed === null">(not completed yet) </ng-container>
<ng-container *ngIf="torrent.completed !== null">
@if (torrent.completed === null) {
(not completed yet)
} @else {
{{ torrent.completed | date: "fullDate" }} {{ torrent.completed | date: "mediumTime" }}
</ng-container>
}
</div>
</div>
<div style="flex: 1 1 0">
@ -156,13 +193,23 @@
</div>
<div class="field">
<label class="label">Real-Debrid Status</label>
<ng-container [ngSwitch]="torrent.rdStatus">
<ng-container *ngSwitchCase="0">Processing</ng-container>
<ng-container *ngSwitchCase="1">Waiting For File Selection</ng-container>
<ng-container *ngSwitchCase="2">Downloading</ng-container>
<ng-container *ngSwitchCase="3">Finished</ng-container>
<ng-container *ngSwitchCase="99">Error</ng-container>
</ng-container>
@switch (torrent.rdStatus) {
@case (0) {
Processing
}
@case (1) {
Waiting For File Selection
}
@case (2) {
Downloading
}
@case (3) {
Finished
}
@case (99) {
Error
}
}
({{ torrent.rdStatusRaw }})
</div>
<div class="field">
@ -183,7 +230,9 @@
</div>
</div>
</div>
<div *ngIf="activeTab === 1">
}
@if (activeTab === 1) {
<div>
<div class="field">
<table class="table is-fullwidth">
<thead>
@ -195,7 +244,8 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let file of torrent.files">
@for (file of torrent.files; track file.id) {
<tr>
<td>
{{ file.id }}
</td>
@ -206,15 +256,21 @@
{{ file.bytes | filesize }}
</td>
<td>
<i class="fas fa-check" *ngIf="file.selected" style="color: green"></i>
<i class="fas fa-times" *ngIf="!file.selected" style="color: red"></i>
@if (file.selected) {
<i class="fas fa-check" style="color: green"></i>
} @else {
<i class="fas fa-times" style="color: red"></i>
}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div *ngIf="activeTab === 2">
}
@if (activeTab === 2) {
<div>
<div class="field">
<table class="table is-fullwidth is-hoverable">
<thead>
@ -226,20 +282,23 @@
</tr>
</thead>
<tbody>
<ng-container *ngFor="let download of torrent.downloads">
<tr (click)="downloadExpanded[download.downloadId] = !downloadExpanded[download.downloadId]">
@for (download of torrent.downloads; track download.downloadId) {
@let expanded = downloadExpanded[download.downloadId];
<tr (click)="downloadExpanded[download.downloadId] = !expanded">
<td style="width: 35px">
<i class="fas fa-caret-right" *ngIf="!downloadExpanded[download.downloadId]"></i>
<i class="fas fa-caret-down" *ngIf="downloadExpanded[download.downloadId]"></i>
@if (!expanded) {
<i class="fas fa-caret-right"></i>
} @else {
<i class="fas fa-caret-down"></i>
}
</td>
<td>
<ng-container *ngIf="download.link">
@if (download.link) {
{{ download.link | decodeURI }}
</ng-container>
<ng-container *ngIf="!download.link">
}
@if (!download.link) {
{{ download.path }}
</ng-container>
}
</td>
<td>
{{ download.bytesTotal | filesize }}
@ -248,7 +307,8 @@
{{ download | downloadStatus }}
</td>
</tr>
<tr *ngIf="downloadExpanded[download.downloadId]" class="separator">
@if (expanded) {
<tr class="separator">
<td style="width: 35px"></td>
<td colspan="5">
<div class="flex-container">
@ -260,15 +320,17 @@
</button>
</div>
</div>
<div class="field" *ngIf="download.error">
@if (download.error) {
<div class="field">
<label class="label">Error</label>
{{ download.error }}
</div>
}
<div class="field">
<label class="label">Real-Debrid Unrestricted Link</label>
<a href="{{ download.link }}" target="_blank" *ngIf="download.link">
{{ download.link | decodeURI }}</a
>
@if (download.link) {
<a href="{{ download.link }}" target="_blank"> {{ download.link | decodeURI }}</a>
}
</div>
<div class="field">
<label class="label">Real-Debrid Link</label>
@ -288,77 +350,88 @@
<div style="flex: 1 1 0">
<div class="field">
<label class="label">Added</label>
<ng-container *ngIf="download.added">
@if (download.added) {
{{ download.added | date: "fullDate" }} {{ download.added | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.added">(not added yet) </ng-container>
} @else {
(not added yet)
}
</div>
<div class="field">
<label class="label">Download Queued</label>
<ng-container *ngIf="download.downloadQueued">
@if (download.downloadQueued) {
{{ download.downloadQueued | date: "fullDate" }}
{{ download.downloadQueued | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.downloadQueued">(not queued for downloading yet) </ng-container>
} @else {
(not queued for downloading yet)
}
</div>
<div class="field">
<label class="label">Download Started</label>
<ng-container *ngIf="download.downloadStarted">
@if (download.downloadStarted) {
{{ download.downloadStarted | date: "fullDate" }}
{{ download.downloadStarted | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.downloadStarted">(not started downloading yet) </ng-container>
} @else {
(not started downloading yet)
}
</div>
<div class="field">
<label class="label">Download Finished</label>
<ng-container *ngIf="download.downloadFinished">
@if (download.downloadFinished) {
{{ download.downloadFinished | date: "fullDate" }}
{{ download.downloadFinished | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.downloadFinished">(not finished yet) </ng-container>
} @else {
(not finished yet)
}
</div>
<div class="field">
<label class="label">Unpacking Queued</label>
<ng-container *ngIf="download.unpackingQueued">
@if (download.unpackingQueued) {
{{ download.unpackingQueued | date: "fullDate" }}
{{ download.unpackingQueued | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.unpackingQueued">(not queued for unpacking yet) </ng-container>
} @else {
(not queued for unpacking yet)
}
</div>
<div class="field">
<label class="label">Unpacking Started</label>
<ng-container *ngIf="download.unpackingStarted">
@if (download.unpackingStarted) {
{{ download.unpackingStarted | date: "fullDate" }}
{{ download.unpackingStarted | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.unpackingStarted">(not started unpacking yet) </ng-container>
} @else {
(not started unpacking yet)
}
</div>
<div class="field">
<label class="label">Unpacking Finished</label>
<ng-container *ngIf="download.unpackingFinished">
@if (download.unpackingFinished) {
{{ download.unpackingFinished | date: "fullDate" }}
{{ download.unpackingFinished | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.unpackingFinished">(not finished unpacking yet) </ng-container>
} @else {
(not finished unpacking yet)
}
</div>
<div class="field">
<label class="label">Completed</label>
<ng-container *ngIf="download.completed">
@if (download.completed) {
{{ download.completed | date: "fullDate" }}
{{ download.completed | date: "mediumTime" }}
</ng-container>
<ng-container *ngIf="!download.completed">(not completed yet) </ng-container>
} @else {
(not completed yet)
}
</div>
</div>
</div>
</td>
</tr>
</ng-container>
}
}
</tbody>
</table>
</div>
</div>
}
</div>
}
<div class="modal" [class.is-active]="isDeleteModalActive">
<div class="modal-background"></div>
@ -391,9 +464,9 @@
<div class="notification is-primary">
Deleting a torrent from Real-Debrid will automatically delete it here too.
</div>
<div class="notification is-danger is-light" *ngIf="deleteError?.length > 0">
Error deleting torrent: {{ deleteError }}
</div>
@if (deleteError?.length > 0) {
<div class="notification is-danger is-light">Error deleting torrent: {{ deleteError }}</div>
}
</section>
<footer class="modal-card-foot">
<button
@ -424,9 +497,9 @@
This action will delete all the torrent data + all local downloads. Then it will re-add the original magnet link
or torrent file to Real-Debrid.
</p>
<div class="notification is-danger is-light" *ngIf="retryError?.length > 0">
Error retrying torrent: {{ retryError }}
</div>
@if (retryError?.length > 0) {
<div class="notification is-danger is-light">Error retrying torrent: {{ retryError }}</div>
}
</section>
<footer class="modal-card-foot">
<button
@ -454,9 +527,9 @@
<section class="modal-card-body">
<p>Are you sure you want to retry this download?</p>
<p>This action will remove the local download and re-download the file from Real-Debrid.</p>
<div class="notification is-danger is-light" *ngIf="downloadRetryError?.length > 0">
Error retrying download: {{ downloadRetryError }}
</div>
@if (downloadRetryError?.length > 0) {
<div class="notification is-danger is-light">Error retrying download: {{ downloadRetryError }}</div>
}
</section>
<footer class="modal-card-foot">
<button