Add MeTube UI controls for hasharr integration settings.
Expose hasharr enabled/url/service-id/timeout controls in Advanced Options and wire them to hasharr-settings backend endpoints so integration can be configured directly from the MeTube web UI. Made-with: Cursor
This commit is contained in:
parent
e49f11c67b
commit
c6b86690ae
3 changed files with 131 additions and 1 deletions
|
|
@ -428,6 +428,60 @@
|
|||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr class="my-3">
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-12">
|
||||
<div class="action-group-label">Hasharr Integration</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-check form-switch mt-2">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="hasharrEnabled"
|
||||
name="hasharrEnabled" [(ngModel)]="hasharrEnabled"
|
||||
[disabled]="addInProgress || downloads.loading">
|
||||
<label class="form-check-label" for="hasharrEnabled">Enabled</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Hasharr URL</span>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
placeholder="http://hasharr:9995"
|
||||
name="hasharrUrl"
|
||||
[(ngModel)]="hasharrUrl"
|
||||
[disabled]="addInProgress || downloads.loading">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Service ID</span>
|
||||
<input type="number"
|
||||
min="1"
|
||||
class="form-control"
|
||||
name="hasharrServiceID"
|
||||
[(ngModel)]="hasharrServiceID"
|
||||
[disabled]="addInProgress || downloads.loading">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Timeout</span>
|
||||
<input type="number"
|
||||
min="1"
|
||||
class="form-control"
|
||||
name="hasharrTimeoutSec"
|
||||
[(ngModel)]="hasharrTimeoutSec"
|
||||
[disabled]="addInProgress || downloads.loading">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="button" class="btn btn-secondary" (click)="saveHasharrSettings()">
|
||||
Save Hasharr Settings
|
||||
</button>
|
||||
@if (hasharrSettingsStatus) {
|
||||
<span class="ms-3 text-muted">{{ hasharrSettingsStatus }}</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<div class="action-group-label">Cookies</div>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { NgSelectModule } from '@ng-select/ng-select';
|
|||
import { faTrashAlt, faCheckCircle, faTimesCircle, faRedoAlt, faSun, faMoon, faCheck, faCircleHalfStroke, faDownload, faExternalLinkAlt, faFileImport, faFileExport, faCopy, faClock, faTachometerAlt, faSortAmountDown, faSortAmountUp, faChevronRight, faChevronDown, faUpload } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons';
|
||||
import { CookieService } from 'ngx-cookie-service';
|
||||
import { AddDownloadPayload, DownloadsService } from './services/downloads.service';
|
||||
import { AddDownloadPayload, DownloadsService, HasharrSettings } from './services/downloads.service';
|
||||
import { Themes } from './theme';
|
||||
import {
|
||||
Download,
|
||||
|
|
@ -96,6 +96,11 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
ytDlpVersion: string | null = null;
|
||||
metubeVersion: string | null = null;
|
||||
isAdvancedOpen = false;
|
||||
hasharrEnabled = false;
|
||||
hasharrUrl = 'http://hasharr:9995';
|
||||
hasharrServiceID = 1;
|
||||
hasharrTimeoutSec = 20;
|
||||
hasharrSettingsStatus = '';
|
||||
sortAscending = false;
|
||||
expandedErrors: Set<string> = new Set<string>();
|
||||
cachedSortedDone: [string, Download][] = [];
|
||||
|
|
@ -268,6 +273,7 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
this.cdr.markForCheck();
|
||||
});
|
||||
this.getConfiguration();
|
||||
this.loadHasharrSettings();
|
||||
this.getYtdlOptionsUpdateTime();
|
||||
this.customDirs$ = this.getMatchingCustomDir();
|
||||
this.setTheme(this.activeTheme!);
|
||||
|
|
@ -275,6 +281,57 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
this.colorSchemeMediaQuery.addEventListener('change', this.onColorSchemeChanged);
|
||||
}
|
||||
|
||||
loadHasharrSettings() {
|
||||
this.downloads.getHasharrSettings().pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
||||
next: (data) => {
|
||||
if (!data || typeof data !== 'object' || ('status' in data && data.status === 'error')) {
|
||||
this.hasharrSettingsStatus = 'Unable to load hasharr settings.';
|
||||
this.cdr.markForCheck();
|
||||
return;
|
||||
}
|
||||
const settings = data as HasharrSettings;
|
||||
this.hasharrEnabled = !!settings.enabled;
|
||||
this.hasharrUrl = String(settings.url || 'http://hasharr:9995');
|
||||
this.hasharrServiceID = Math.max(1, Number(settings.service_id || 1));
|
||||
this.hasharrTimeoutSec = Math.max(1, Number(settings.timeout_sec || 20));
|
||||
this.hasharrSettingsStatus = '';
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
error: () => {
|
||||
this.hasharrSettingsStatus = 'Unable to load hasharr settings.';
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
saveHasharrSettings() {
|
||||
const payload: HasharrSettings = {
|
||||
enabled: !!this.hasharrEnabled,
|
||||
url: String(this.hasharrUrl || '').trim(),
|
||||
service_id: Math.max(1, Number(this.hasharrServiceID || 1)),
|
||||
timeout_sec: Math.max(1, Number(this.hasharrTimeoutSec || 20)),
|
||||
};
|
||||
if (!payload.url) {
|
||||
this.hasharrSettingsStatus = 'Hasharr URL is required.';
|
||||
this.cdr.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.downloads.saveHasharrSettings(payload).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
||||
next: (out) => {
|
||||
if (out && typeof out === 'object' && 'status' in out && out.status === 'ok') {
|
||||
this.hasharrSettingsStatus = 'Hasharr settings saved.';
|
||||
} else {
|
||||
this.hasharrSettingsStatus = 'Failed to save hasharr settings.';
|
||||
}
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
error: () => {
|
||||
this.hasharrSettingsStatus = 'Failed to save hasharr settings.';
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.downloads.queueChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||
this.queueMasterCheckbox()?.selectionChanged();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@ import { MeTubeSocket } from './metube-socket.service';
|
|||
import { Download, Status, State } from '../interfaces';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
export interface HasharrSettings {
|
||||
enabled: boolean;
|
||||
url: string;
|
||||
service_id: number;
|
||||
timeout_sec: number;
|
||||
}
|
||||
|
||||
export interface AddDownloadPayload {
|
||||
url: string;
|
||||
downloadType: string;
|
||||
|
|
@ -224,4 +231,16 @@ export class DownloadsService {
|
|||
catchError(this.handleHTTPError)
|
||||
);
|
||||
}
|
||||
|
||||
getHasharrSettings() {
|
||||
return this.http.get<HasharrSettings>('hasharr-settings').pipe(
|
||||
catchError(this.handleHTTPError)
|
||||
);
|
||||
}
|
||||
|
||||
saveHasharrSettings(settings: HasharrSettings) {
|
||||
return this.http.post<{ status: string; msg?: string }>('hasharr-settings', settings).pipe(
|
||||
catchError(this.handleHTTPError)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue