mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 21:03:17 -07:00
Merge 853ca6b6bd
into cfe2b6ac0f
This commit is contained in:
commit
d1b7dcf52d
7 changed files with 576 additions and 290 deletions
|
@ -0,0 +1,113 @@
|
|||
<h1 mat-dialog-title>Server Configuration</h1>
|
||||
<mat-dialog-content>
|
||||
<form #embyServerForm="ngForm">
|
||||
<h2>Connection</h2>
|
||||
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Server Name</mat-label>
|
||||
<input matInput placeholder="Server Name" name="name" [(ngModel)]="server.name" value="{{server.name}}"
|
||||
(change)="processChangeEvent()">
|
||||
<mat-hint>Auto populated during discovery of the server if left empty.</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-6 col-12" appearance="outline" floatLabel=auto>
|
||||
<mat-label>Hostname / IP</mat-label>
|
||||
<input matInput placeholder="Hostname or IP" name="ip" [(ngModel)]="server.ip" value="{{server.ip}}"
|
||||
(change)="processChangeEvent()" #serverHostnameIpControl="ngModel" required>
|
||||
<mat-error *ngIf="serverHostnameIpControl.hasError('required')">Must be specified.</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="col-md-4 col-7" appearance="outline" floatLabel=auto>
|
||||
<mat-label>Port</mat-label>
|
||||
<input matInput placeholder="Port" name="port" [(ngModel)]="server.port" value="{{server.port}}"
|
||||
(change)="processChangeEvent()" #serverPortControl="ngModel" required pattern="^[0-9]*$">
|
||||
<mat-error *ngIf="serverPortControl.hasError('required')">Must be specified.</mat-error>
|
||||
<mat-error *ngIf="serverPortControl.hasError('pattern')">Must be a number.</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-slide-toggle class="col-md-2 col-5 mt-3" id="ssl" name="ssl" [(ngModel)]="server.ssl" [checked]="server.ssl"
|
||||
(change)="processChangeEvent()">
|
||||
SSL
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Base URL</mat-label>
|
||||
<input matInput placeholder="Base Url" name="subDir" [(ngModel)]="server.subDir" value="{{server.subDir}}"
|
||||
(change)="processChangeEvent()">
|
||||
<mat-hint>Optional url path to be used with reverse proxy. Example: 'emby' to get
|
||||
'https://ip:port/emby'.</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>API Key</mat-label>
|
||||
<input matInput placeholder="Api Key" name="apiKey" [(ngModel)]="server.apiKey" value="{{server.apiKey}}"
|
||||
(change)="processChangeEvent()" #serverApiKeyControl="ngModel" required>
|
||||
<mat-error *ngIf="serverApiKeyControl.hasError('required')">Must be specified.</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Externally Facing Hostname</mat-label>
|
||||
<input matInput placeholder="e.g. https://emby.server.com/" name="serverHostname"
|
||||
[(ngModel)]="server.serverHostname" value="{{server.serverHostname}}" (change)="processChangeEvent()">
|
||||
<mat-hint>
|
||||
The external address that users will navigate to when they press the 'View On Emby'
|
||||
button.
|
||||
<br />
|
||||
<span>Current URL: {{server.serverHostname ? server.serverHostname :
|
||||
'https://app.emby.media'}}/#!/item/item.html?id=1</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<h2>Libraries</h2>
|
||||
<label *ngIf="server.embySelectedLibraries && server.embySelectedLibraries.length == 0">
|
||||
Discover the server to load available libraries. If you still not seeing any libraries, make sure they are
|
||||
configured in Emby.</label>
|
||||
<div *ngIf="server.embySelectedLibraries && server.embySelectedLibraries.length > 0">
|
||||
<label>Please select the libraries for Ombi to monitor. If nothing is selected, Ombi will monitor all
|
||||
libraries.</label>
|
||||
<div *ngFor="let lib of server.embySelectedLibraries">
|
||||
<div class="md-form-field">
|
||||
<div class="checkbox">
|
||||
<mat-slide-toggle name="library-{{lib.key}}" [(ngModel)]="lib.enabled" [checked]="lib.enabled"
|
||||
(change)="processChangeEvent()">
|
||||
{{lib.title}}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions align=end>
|
||||
<button style="margin: .5em 0 0 .5em;" align-middle mat-stroked-button color="warn" *ngIf="!data.isNewServer"
|
||||
(click)="delete()">
|
||||
<span style="display: flex; align-items: baseline; white-space: pre-wrap;">
|
||||
<i class="fas fa-trash"></i>
|
||||
<span> Delete</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button style="margin: .5em 0 0 0.5em;" mat-stroked-button color="basic" (click)="cancel()">
|
||||
<span style="display: flex; align-items: baseline; white-space: pre-wrap;">
|
||||
<i class="fas fa-times"></i>
|
||||
<span> Cancel</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button style="margin: .5em 0 0 .5em;" mat-stroked-button color="{{serverDiscoveryRequired ? 'accent' : 'basic'}}"
|
||||
(click)="discoverServer()" id="discover">
|
||||
<span>Discover Server</span>
|
||||
</button>
|
||||
|
||||
<button style="margin: .5em 0 0 .5em;" mat-stroked-button color="accent"
|
||||
[disabled]="!isChangeDetected || serverDiscoveryRequired || isServerNameMissing" (click)="save()">
|
||||
<span style="display: flex; align-items: baseline; white-space: pre-wrap;">
|
||||
<i style="vertical-align: text-top;" class="fas fa-plus"></i>
|
||||
<span> Save</span>
|
||||
</span>
|
||||
</button>
|
||||
</mat-dialog-actions>
|
|
@ -0,0 +1,28 @@
|
|||
@media (max-width: 978px) {
|
||||
::ng-deep .mat-dialog-container {
|
||||
overflow: unset;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.mat-dialog-content{
|
||||
max-height: unset;
|
||||
}
|
||||
|
||||
.mat-dialog-actions{
|
||||
min-height: unset;
|
||||
}
|
||||
|
||||
emby-server-dialog-component {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep mat-form-field .mat-form-field {
|
||||
&-subscript-wrapper {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
import { Component, Inject, ViewChild } from "@angular/core";
|
||||
import { NgForm } from "@angular/forms";
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
|
||||
import {
|
||||
IEmbyLibrariesSettings,
|
||||
IEmbyServer,
|
||||
IEmbySettings,
|
||||
} from "app/interfaces";
|
||||
import {
|
||||
EmbyService,
|
||||
NotificationService,
|
||||
SettingsService,
|
||||
TesterService,
|
||||
} from "app/services";
|
||||
import { isEqual } from "lodash";
|
||||
|
||||
export interface EmbyServerDialogData {
|
||||
server: IEmbyServer;
|
||||
isNewServer: boolean;
|
||||
savedSettings: IEmbySettings;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "emby-server-dialog-component",
|
||||
templateUrl: "emby-server-dialog.component.html",
|
||||
styleUrls: ["emby-server-dialog.component.scss"],
|
||||
})
|
||||
export class EmbyServerDialog {
|
||||
@ViewChild("embyServerForm") embyServerForm: NgForm;
|
||||
public server: IEmbyServer;
|
||||
public isServerNameMissing: boolean;
|
||||
public isChangeDetected: boolean;
|
||||
public serverDiscoveryRequired: boolean;
|
||||
private validatedFields: {
|
||||
ip: string;
|
||||
port: number;
|
||||
ssl: boolean;
|
||||
apiKey: string;
|
||||
subDir: string;
|
||||
};
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<EmbyServerDialog>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: EmbyServerDialogData,
|
||||
private notificationService: NotificationService,
|
||||
private settingsService: SettingsService,
|
||||
private testerService: TesterService,
|
||||
private embyService: EmbyService
|
||||
) {
|
||||
this.server = structuredClone(data.server);
|
||||
this.isChangeDetected = false;
|
||||
this.serverDiscoveryRequired = data.isNewServer;
|
||||
this.isServerNameMissing = !this.server.name;
|
||||
this.validatedFields = {
|
||||
ip: this.server.ip,
|
||||
port: this.server.port,
|
||||
ssl: this.server.ssl,
|
||||
apiKey: this.server.apiKey,
|
||||
subDir: this.server.subDir,
|
||||
};
|
||||
}
|
||||
|
||||
public processChangeEvent() {
|
||||
if (
|
||||
this.validatedFields.ip !== this.server.ip ||
|
||||
this.validatedFields.port?.toString() !== this.server.port?.toString() ||
|
||||
this.validatedFields.ssl !== this.server.ssl ||
|
||||
this.validatedFields.apiKey !== this.server.apiKey ||
|
||||
this.validatedFields.subDir !== this.server.subDir ||
|
||||
!this.embyServerForm.valid
|
||||
) {
|
||||
this.serverDiscoveryRequired = true;
|
||||
} else {
|
||||
this.serverDiscoveryRequired = false;
|
||||
}
|
||||
|
||||
this.isServerNameMissing = !this.server.name;
|
||||
this.isChangeDetected = !isEqual(this.data.server, this.server);
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
public delete() {
|
||||
const settings: IEmbySettings = structuredClone(this.data.savedSettings);
|
||||
const index = settings.servers.findIndex((i) => i.id === this.server.id);
|
||||
if (index == -1) return;
|
||||
|
||||
settings.servers.splice(index, 1);
|
||||
const errorMessage = "There was an error removing the server.";
|
||||
this.settingsService.saveEmby(settings).subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.data.savedSettings.servers.splice(index, 1);
|
||||
this.dialogRef.close();
|
||||
} else {
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public save() {
|
||||
const settings: IEmbySettings = structuredClone(this.data.savedSettings);
|
||||
if (this.data.isNewServer) {
|
||||
settings.servers.push(this.server);
|
||||
} else {
|
||||
const index = settings.servers.findIndex((i) => i.id === this.server.id);
|
||||
if (index !== -1) settings.servers[index] = this.server;
|
||||
}
|
||||
|
||||
const errorMessage = "There was an error saving the server.";
|
||||
this.settingsService.saveEmby(settings).subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
if (this.data.isNewServer) {
|
||||
this.data.savedSettings.servers.push(this.server);
|
||||
} else {
|
||||
const index = this.data.savedSettings.servers.findIndex(
|
||||
(i) => i.id === this.server.id
|
||||
);
|
||||
if (index !== -1)
|
||||
this.data.savedSettings.servers[index] = this.server;
|
||||
}
|
||||
this.dialogRef.close();
|
||||
} else {
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public discoverServer() {
|
||||
this.embyServerForm.form.markAllAsTouched();
|
||||
if (!this.embyServerForm.valid) return;
|
||||
|
||||
const errorMessage = `Failed to connect to the server. Make sure configuration is correct.`;
|
||||
this.testerService.embyTest(this.server).subscribe({
|
||||
next: (result) => {
|
||||
if (!result) {
|
||||
this.notificationService.error(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
this.retrieveServerNameAndId(this.server);
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private retrieveServerNameAndId(server: IEmbyServer) {
|
||||
const errorMessage =
|
||||
"Failed to discover server. Make sure configuration is correct.";
|
||||
this.embyService.getPublicInfo(server).subscribe({
|
||||
next: (result) => {
|
||||
if (!result) {
|
||||
this.notificationService.error(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.name) {
|
||||
server.name = result.serverName;
|
||||
this.isServerNameMissing = false;
|
||||
}
|
||||
server.serverId = result.id;
|
||||
this.loadLibraries(server);
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private loadLibraries(server: IEmbyServer) {
|
||||
this.embyService.getLibraries(server).subscribe({
|
||||
next: (result) => {
|
||||
server.embySelectedLibraries = result.items.map((item) => {
|
||||
const index = server.embySelectedLibraries.findIndex(
|
||||
(x) => x.key == item.id
|
||||
);
|
||||
const enabled =
|
||||
index === -1 ? false : server.embySelectedLibraries[index].enabled;
|
||||
const lib: IEmbyLibrariesSettings = {
|
||||
key: item.id,
|
||||
title: item.name,
|
||||
enabled: enabled,
|
||||
collectionType: item.collectionType,
|
||||
};
|
||||
return lib;
|
||||
});
|
||||
|
||||
this.serverDiscoveryRequired = false;
|
||||
this.validatedFields = {
|
||||
ip: this.server.ip,
|
||||
port: this.server.port,
|
||||
ssl: this.server.ssl,
|
||||
apiKey: this.server.apiKey,
|
||||
subDir: this.server.subDir,
|
||||
};
|
||||
this.notificationService.success("Successfully discovered the server.");
|
||||
},
|
||||
error: () => {
|
||||
const errorMessage = "There was an error retrieving libraries.";
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,142 +1,56 @@
|
|||
|
||||
<settings-menu></settings-menu>
|
||||
<settings-menu></settings-menu>
|
||||
<div class="small-middle-container">
|
||||
<div *ngIf="settings">
|
||||
<fieldset>
|
||||
<legend>
|
||||
Emby Configuration
|
||||
</legend>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-6 col-sm-6">
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle [(ngModel)]="settings.enable" (change)="toggle()" [checked]="settings.enable">Enable
|
||||
</mat-slide-toggle>
|
||||
</div> </div>
|
||||
</div>
|
||||
<mat-tab-group #tabGroup [selectedIndex]="selected.value" (selectedTabChange)="addTab($event)" (selectedIndexChange)="selected.setValue($event)" animationDuration="0ms" style="display:block;">
|
||||
<mat-tab *ngFor="let server of settings.servers" [label]="server.name">
|
||||
<div class="col-md-6 col-6 col-sm-6" style="float: right; width:100%; text-align:right;">
|
||||
<button type="button" (click)="removeServer(server)" class="mat-focus-indicator mat-flat-button mat-button-base mat-warn">Remove Server</button>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div class="col-md-10 col-10 col-sm-12">
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Server Name</mat-label>
|
||||
<input matInput placeholder="Server Name" [(ngModel)]="server.name" value="{{server.name}}">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Hostname / IP</mat-label>
|
||||
<input matInput placeholder="Hostname or IP" [(ngModel)]="server.ip" value="{{server.ip}}">
|
||||
</mat-form-field>
|
||||
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Server ID</mat-label>
|
||||
<input disabled matInput placeholder="Server Id" [(ngModel)]="server.serverId" value="{{server.serverId}}">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Port</mat-label>
|
||||
<input matInput placeholder="Port" [(ngModel)]="server.port" value="{{server.port}}">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-slide-toggle id="ssl" [(ngModel)]="server.ssl" [checked]="server.ssl">
|
||||
SSL
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>API Key</mat-label>
|
||||
<input matInput placeholder="Api Key" [(ngModel)]="server.apiKey" value="{{server.apiKey}}">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Base URL</mat-label>
|
||||
<input matInput placeholder="Base Url" [(ngModel)]="server.subDir" value="{{server.subDir}}">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-form-field appearance="outline" floatLabel=auto>
|
||||
<mat-label>Externally Facing Hostname</mat-label>
|
||||
<input matInput placeholder="e.g. https://jellyfin.server.com/" [(ngModel)]="server.serverHostname" value="{{server.serverHostname}}" matTooltip="This will be the external address that users will navigate to when they press the 'View On Emby' button">
|
||||
</mat-form-field>
|
||||
<small>
|
||||
<span *ngIf="server.serverHostname">Current URL: "{{server.serverHostname}}/#!/item/item.html?id=1"</span>
|
||||
<span *ngIf="!server.serverHostname">Current URL: "https://app.emby.media/#!/item/item.html?id=1</span>
|
||||
</small>
|
||||
</div>
|
||||
<label>Please select the libraries you want Ombi to look in for content</label>
|
||||
<br />
|
||||
<small>Note: if nothing is selected, we will monitor all libraries</small>
|
||||
<div class="md-form-field">
|
||||
<div>
|
||||
<button mat-raised-button (click)="loadLibraries(server)"
|
||||
class="mat-focus-indicator mat-stroked-button mat-button-base">Load Libraries
|
||||
<i class="fas fa-film"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div *ngIf="server.embySelectedLibraries">
|
||||
<div *ngFor="let lib of server.embySelectedLibraries">
|
||||
<div class="md-form-field">
|
||||
<div class="checkbox">
|
||||
<mat-slide-toggle [(ngModel)]="lib.enabled" [checked]="lib.enabled"
|
||||
for="{{lib.title}}">{{lib.title}}</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button mat-raised-button id="testEmby" type="button" (click)="test(server)" class="mat-focus-indicator mat-stroked-button mat-button-base">Test Connectivity <div id="spinner"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button mat-raised-button id="discover" type="button" (click)="discoverServerInfo(server)" class="mat-focus-indicator mat-stroked-button mat-button-base">Discover Server Information <div id="spinner"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button mat-raised-button (click)="runCacher()" type="button" id="save" class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Full Sync</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button mat-raised-button (click)="runRecentlyAddedCacher()" type="button" id="recentlyAddedSync"
|
||||
class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Recently
|
||||
Added Sync</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button mat-raised-button (click)="clearDataAndResync()" type="button" id="clearData"
|
||||
class="mat-focus-indicator mat-stroked-button mat-button-base">
|
||||
Clear Data And Resync
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="" disabled=true> </mat-tab>
|
||||
<mat-tab label="Add Server" position=100> </mat-tab>
|
||||
|
||||
</mat-tab-group>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div *ngIf="savedSettings">
|
||||
<fieldset>
|
||||
<legend style="margin-bottom: 1em;">Emby Configuration</legend>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button mat-raised-button [disabled]="!hasDiscoveredOrDirty" (click)="save()" type="submit" id="save" class="mat-focus-indicator mat-raised-button mat-button-base mat-accent">Submit</button>
|
||||
<div style="margin-bottom: 2em;">
|
||||
<mat-slide-toggle (change)="toggleEnableFlag($event)" [checked]="savedSettings.enable">
|
||||
Enable
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 1em;">
|
||||
<h2 style="margin: 0 0 .5em 0;">Servers</h2>
|
||||
<div style="display:flex; flex-flow: wrap;">
|
||||
<mat-card class="emby-server-card" *ngFor="let server of savedSettings.servers">
|
||||
<button mat-button (click)="editServer(server)">
|
||||
<h3>{{server.name}}</h3>
|
||||
</button>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="emby-server-card new-server-card">
|
||||
<button mat-button (click)="newServer()">
|
||||
<i class="fas fa-plus fa-xl"></i>
|
||||
<h3>New Server</h3>
|
||||
</button>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 1em;">
|
||||
<h2 style="margin: 0 0 .5em 0;">Actions</h2>
|
||||
<div class="md-form-field">
|
||||
<button mat-stroked-button
|
||||
[disabled]="!savedSettings.enable || savedSettings.servers.length == 0"
|
||||
style="margin: 0 1em 1em 0;" (click)="runIncrementalSync()" type="button"
|
||||
id="recentlyAddedSync">
|
||||
Run Incremental Sync
|
||||
</button>
|
||||
<button mat-stroked-button
|
||||
[disabled]="!savedSettings.enable|| savedSettings.servers.length == 0"
|
||||
style="margin: 0 1em 1em 0;" (click)="runFullSync()" type="button" id="save">
|
||||
Run Full Sync
|
||||
</button>
|
||||
<button mat-stroked-button
|
||||
[disabled]="!savedSettings.enable|| savedSettings.servers.length == 0"
|
||||
style="margin: 0 1em 1em 0;" (click)="runCacheWipeWithFullSync()" type="button"
|
||||
id="clearData">
|
||||
Clear Data And Resync
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,41 +1,29 @@
|
|||
@import "./styles/shared.scss";
|
||||
.small-middle-container {
|
||||
margin: auto;
|
||||
width: 95%;
|
||||
margin-top: 10px;
|
||||
margin: auto;
|
||||
width: 95%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.col-md-10 {
|
||||
display: grid;
|
||||
}
|
||||
.emby-server-card {
|
||||
margin: 0em 1em 1em 0;
|
||||
width: 13em;
|
||||
min-height: 8em;
|
||||
|
||||
.col-md-2 {
|
||||
display: contents;
|
||||
}
|
||||
button {
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-weight: 400;
|
||||
}
|
||||
i {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
h3 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-danger-outline {
|
||||
background-color: #E84C3D;
|
||||
}
|
||||
|
||||
.btn-success-outline {
|
||||
background-color: #1b9d1b;
|
||||
}
|
||||
|
||||
::ng-deep .dark .btn:hover {
|
||||
box-shadow: 0 5px 11px 0 rgba(255, 255, 255, 0.18), 0 4px 15px 0 rgba(255, 255, 255, 0.15);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@media (min-width:1440px) {
|
||||
.col-md-2 {
|
||||
display: inline-table;
|
||||
}
|
||||
}
|
|
@ -1,136 +1,160 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { EmbyService, JobService, NotificationService, SettingsService, TesterService } from "../../services";
|
||||
import { IEmbyLibrariesSettings, IEmbyServer, IEmbySettings } from "../../interfaces";
|
||||
|
||||
import {UntypedFormControl} from '@angular/forms';
|
||||
import { MatTabChangeEvent } from "@angular/material/tabs";
|
||||
import {
|
||||
JobService,
|
||||
NotificationService,
|
||||
SettingsService,
|
||||
} from "../../services";
|
||||
import { IEmbyServer, IEmbySettings } from "../../interfaces";
|
||||
import { MatSlideToggleChange } from "@angular/material/slide-toggle";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import {
|
||||
EmbyServerDialog,
|
||||
EmbyServerDialogData,
|
||||
} from "./emby-server-dialog/emby-server-dialog.component";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./emby.component.html",
|
||||
styleUrls: ["./emby.component.scss"]
|
||||
templateUrl: "./emby.component.html",
|
||||
styleUrls: ["./emby.component.scss"],
|
||||
})
|
||||
export class EmbyComponent implements OnInit {
|
||||
public savedSettings: IEmbySettings;
|
||||
|
||||
public settings: IEmbySettings;
|
||||
public hasDiscoveredOrDirty: boolean;
|
||||
selected = new UntypedFormControl(0);
|
||||
constructor(
|
||||
private settingsService: SettingsService,
|
||||
private notificationService: NotificationService,
|
||||
private jobService: JobService,
|
||||
private dialog: MatDialog
|
||||
) {}
|
||||
|
||||
constructor(private settingsService: SettingsService,
|
||||
private notificationService: NotificationService,
|
||||
private testerService: TesterService,
|
||||
private jobService: JobService,
|
||||
private embyService: EmbyService) { }
|
||||
public ngOnInit() {
|
||||
this.settingsService.getEmby().subscribe({
|
||||
next: (result) => {
|
||||
if (result.servers == null) result.servers = [];
|
||||
this.savedSettings = result;
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error("Failed to retrieve Emby settings.");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
this.settingsService.getEmby().subscribe(x => this.settings = x);
|
||||
}
|
||||
|
||||
public async discoverServerInfo(server: IEmbyServer) {
|
||||
const result = await this.embyService.getPublicInfo(server).toPromise();
|
||||
server.name = result.serverName;
|
||||
server.serverId = result.id;
|
||||
this.hasDiscoveredOrDirty = true;
|
||||
}
|
||||
|
||||
public addTab(event: MatTabChangeEvent) {
|
||||
const tabName = event.tab.textLabel;
|
||||
if (tabName == "Add Server"){
|
||||
if (this.settings.servers == null) {
|
||||
this.settings.servers = [];
|
||||
}
|
||||
this.settings.servers.push({
|
||||
name: "New " + this.settings.servers.length + "*",
|
||||
id: Math.floor(Math.random() * (99999 - 0 + 1) + 1),
|
||||
apiKey: "",
|
||||
administratorId: "",
|
||||
enableEpisodeSearching: false,
|
||||
ip: "",
|
||||
port: 0,
|
||||
ssl: false,
|
||||
subDir: "",
|
||||
} as IEmbyServer);
|
||||
this.selected.setValue(this.settings.servers.length - 1);
|
||||
public toggleEnableFlag(event: MatSlideToggleChange) {
|
||||
const newSettings: IEmbySettings = {
|
||||
...structuredClone(this.savedSettings),
|
||||
enable: event.checked,
|
||||
};
|
||||
const errorMessage = event.checked
|
||||
? "There was an error enabling Emby settings. Check that all servers are configured correctly."
|
||||
: "There was an error disabling Emby settings.";
|
||||
this.settingsService.saveEmby(newSettings).subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.savedSettings.enable = event.checked;
|
||||
this.notificationService.success(
|
||||
`Successfully ${
|
||||
event.checked ? "enabled" : "disabled"
|
||||
} Emby settings.`
|
||||
);
|
||||
} else {
|
||||
event.source.checked = !event.checked;
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
event.source.checked = !event.checked;
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public toggle() {
|
||||
this.hasDiscoveredOrDirty = true;
|
||||
}
|
||||
public newServer() {
|
||||
const newServer: IEmbyServer = {
|
||||
name: "",
|
||||
id: Math.floor(Math.random() * 99999 + 1),
|
||||
apiKey: "",
|
||||
administratorId: "",
|
||||
enableEpisodeSearching: false,
|
||||
ip: "",
|
||||
port: undefined,
|
||||
ssl: false,
|
||||
subDir: "",
|
||||
serverId: "",
|
||||
serverHostname: "",
|
||||
embySelectedLibraries: [],
|
||||
};
|
||||
const data: EmbyServerDialogData = {
|
||||
server: newServer,
|
||||
isNewServer: true,
|
||||
savedSettings: this.savedSettings,
|
||||
};
|
||||
this.dialog.open(EmbyServerDialog, {
|
||||
width: "700px",
|
||||
data: data,
|
||||
panelClass: "modal-panel",
|
||||
});
|
||||
}
|
||||
|
||||
public test(server: IEmbyServer) {
|
||||
this.testerService.embyTest(server).subscribe(x => {
|
||||
if (x === true) {
|
||||
this.notificationService.success(`Successfully connected to the Emby server ${server.name}!`);
|
||||
} else {
|
||||
this.notificationService.error(`We could not connect to the Emby server ${server.name}!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
public editServer(server: IEmbyServer) {
|
||||
const data: EmbyServerDialogData = {
|
||||
server: server,
|
||||
isNewServer: false,
|
||||
savedSettings: this.savedSettings,
|
||||
};
|
||||
this.dialog.open(EmbyServerDialog, {
|
||||
width: "700px",
|
||||
data: data,
|
||||
panelClass: "modal-panel",
|
||||
});
|
||||
}
|
||||
|
||||
public removeServer(server: IEmbyServer) {
|
||||
const index = this.settings.servers.indexOf(server, 0);
|
||||
if (index > -1) {
|
||||
this.settings.servers.splice(index, 1);
|
||||
this.selected.setValue(this.settings.servers.length - 1);
|
||||
this.toggle();
|
||||
public runIncrementalSync(): void {
|
||||
const errorMessage = "There was an error triggering the incremental sync.";
|
||||
this.jobService.runEmbyRecentlyAddedCacher().subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.notificationService.success("Triggered the incremental sync.");
|
||||
} else {
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public save() {
|
||||
this.settingsService.saveEmby(this.settings).subscribe(x => {
|
||||
if (x) {
|
||||
this.notificationService.success("Successfully saved Emby settings");
|
||||
} else {
|
||||
this.notificationService.success("There was an error when saving the Emby settings");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runCacher(): void {
|
||||
this.jobService.runEmbyCacher().subscribe(x => {
|
||||
if(x) {
|
||||
this.notificationService.success("Triggered the Emby Content Cacher");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runRecentlyAddedCacher(): void {
|
||||
this.jobService.runEmbyRecentlyAddedCacher().subscribe(x => {
|
||||
if (x) {
|
||||
this.notificationService.success("Triggered the Emby Recently Added Sync");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public clearDataAndResync(): void {
|
||||
this.jobService.clearMediaserverData().subscribe(x => {
|
||||
if (x) {
|
||||
this.notificationService.success("Triggered the Clear MediaServer Resync");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public loadLibraries(server: IEmbyServer) {
|
||||
if (server.ip == null) {
|
||||
this.notificationService.error("Emby is not yet configured correctly");
|
||||
return;
|
||||
public runFullSync(): void {
|
||||
const errorMessage = "There was an error triggering the full sync.";
|
||||
this.jobService.runEmbyCacher().subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.notificationService.success("Triggered the full sync.");
|
||||
} else {
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
this.embyService.getLibraries(server).subscribe(x => {
|
||||
server.embySelectedLibraries = [];
|
||||
if (x.totalRecordCount > 0) {
|
||||
x.items.forEach((item) => {
|
||||
const lib: IEmbyLibrariesSettings = {
|
||||
key: item.id,
|
||||
title: item.name,
|
||||
enabled: false,
|
||||
collectionType: item.collectionType
|
||||
};
|
||||
server.embySelectedLibraries.push(lib);
|
||||
});
|
||||
} else {
|
||||
this.notificationService.error("Couldn't find any libraries");
|
||||
}
|
||||
},
|
||||
err => { this.notificationService.error(err); });
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public runCacheWipeWithFullSync(): void {
|
||||
const errorMessage =
|
||||
"There was an error triggering the cache wipe with a full sync.";
|
||||
this.jobService.clearMediaserverData().subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.notificationService.success(
|
||||
"Triggered the cache wipe with a full sync."
|
||||
);
|
||||
} else {
|
||||
this.notificationService.error(errorMessage);
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.notificationService.error(errorMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import { DiscordComponent } from "./notifications/discord.component";
|
|||
import { DogNzbComponent } from "./dognzb/dognzb.component";
|
||||
import { EmailNotificationComponent } from "./notifications/emailnotification.component";
|
||||
import { EmbyComponent } from "./emby/emby.component";
|
||||
import { EmbyServerDialog } from "./emby/emby-server-dialog/emby-server-dialog.component";
|
||||
import { FailedRequestsComponent } from "./failedrequests/failedrequests.component";
|
||||
import { FeaturesComponent } from "./features/features.component";
|
||||
import { GotifyComponent } from "./notifications/gotify.component";
|
||||
|
@ -154,6 +155,7 @@ const routes: Routes = [
|
|||
OmbiComponent,
|
||||
PlexComponent,
|
||||
EmbyComponent,
|
||||
EmbyServerDialog,
|
||||
JellyfinComponent,
|
||||
JobsComponent,
|
||||
LandingPageComponent,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue