diff --git a/ui/src/app/app.html b/ui/src/app/app.html index 8ef50f8..22be60d 100644 --- a/ui/src/app/app.html +++ b/ui/src/app/app.html @@ -428,6 +428,60 @@

+
+
+
Hasharr Integration
+
+
+
+ + +
+
+
+
+ Hasharr URL + +
+
+
+
+ Service ID + +
+
+
+
+ Timeout + +
+
+
+ + @if (hasharrSettingsStatus) { + {{ hasharrSettingsStatus }} + } +
+
Cookies
diff --git a/ui/src/app/app.ts b/ui/src/app/app.ts index b1b8c1e..f909c4e 100644 --- a/ui/src/app/app.ts +++ b/ui/src/app/app.ts @@ -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 = new Set(); 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(); diff --git a/ui/src/app/services/downloads.service.ts b/ui/src/app/services/downloads.service.ts index 94d43c8..a2ff8e9 100644 --- a/ui/src/app/services/downloads.service.ts +++ b/ui/src/app/services/downloads.service.ts @@ -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('hasharr-settings').pipe( + catchError(this.handleHTTPError) + ); + } + + saveHasharrSettings(settings: HasharrSettings) { + return this.http.post<{ status: string; msg?: string }>('hasharr-settings', settings).pipe( + catchError(this.handleHTTPError) + ); + } }