diff --git a/src/Ombi/ClientApp/src/app/settings/plex/components/models/PlexServerDialogData.ts b/src/Ombi/ClientApp/src/app/settings/plex/components/models/PlexServerDialogData.ts new file mode 100644 index 000000000..703ab297a --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/plex/components/models/PlexServerDialogData.ts @@ -0,0 +1,7 @@ +import { IPlexServer } from "../../../../interfaces"; + +export interface PlexServerDialogData { + server: IPlexServer; + deleted?: boolean; + closed?: boolean; +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/plex/components/models/index.ts b/src/Ombi/ClientApp/src/app/settings/plex/components/models/index.ts index 1569393f8..e6ffcfb23 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/components/models/index.ts +++ b/src/Ombi/ClientApp/src/app/settings/plex/components/models/index.ts @@ -1,2 +1,3 @@ export * from './PlexSyncType'; -export * from './PlexCreds'; \ No newline at end of file +export * from './PlexCreds'; +export * from './PlexServerDialogData'; \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.html b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.html new file mode 100644 index 000000000..606dda639 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.html @@ -0,0 +1,121 @@ +

Server Configuration

+ +

Connection

+ + + + Server Name + + + +
+ + Hostname / IP + + Must be specified. + + + + Port + + Must be specified. + Must be a number. + + + + SSL + +
+ + + Plex Authorization Token + + Must be specified. + + + + Machine Identifier + + Must be specified. + + + + Externally Facing Hostname + + + This will be the external address that users will navigate to when they press the 'View On Plex' button +
+ Current URL: "{{this.data.server.serverHostname}}/web/app#!/server/{{this.data.server.machineIdentifier}}/details?key=%2flibrary%2Fmetadata%2F53334" + Current URL: "https://app.plex.tv/web/app#!/server/{{this.data.server.machineIdentifier}}/details?key=%2flibrary%2Fmetadata%2F53334" + +
+
+ + + Episode Batch Size + + + 150 by default, you shouldn't need to change this, this sets how many episodes we request from Plex at a single time. + + + +

Libraries

+
+ +
+
+ +
+
+
+ {{lib.title}} +
+
+
+
+ +
+ + + + + + + + + + + \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.scss b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.scss new file mode 100644 index 000000000..33ad7a09b --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.scss @@ -0,0 +1,27 @@ +@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; + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.ts b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.ts new file mode 100644 index 000000000..851b5d287 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/plex/components/plex-server-dialog/plex-server-dialog.component.ts @@ -0,0 +1,79 @@ +import { Component, Inject } from "@angular/core"; +import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; + +import { + PlexService, + NotificationService, + TesterService, +} from "../../../../services"; +import { take } from "rxjs"; +import { IPlexLibrariesSettings } from "../../../../interfaces"; +import { PlexServerDialogData } from "../models"; + +@Component({ + selector: "plex-server-dialog-component", + templateUrl: "plex-server-dialog.component.html", + styleUrls: ["plex-server-dialog.component.scss"], +}) +export class PlexServerDialogComponent { + + + public password: string; + public username: string; + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: PlexServerDialogData, + private notificationService: NotificationService, + private testerService: TesterService, + private plexService: PlexService + ) { + } + + + public cancel() { + this.dialogRef.close({closed: true}); + } + + public testPlex() { + this.testerService.plexTest(this.data.server).pipe(take(1)) + .subscribe(x => { + if (x === true) { + this.notificationService.success(`Successfully connected to the Plex server ${this.data.server.name}!`); + } else { + this.notificationService.error(`We could not connect to the Plex server ${this.data.server.name}!`); + } + }); +} + + public delete() { + this.dialogRef.close({deleted: true}); + } + + public save() { + this.dialogRef.close({server: this.data.server}); + } + + public loadLibraries() { + if (this.data.server.ip == null) { + this.notificationService.error("Plex is not yet configured correctly"); + return; + } + this.plexService.getLibraries(this.data.server).subscribe(x => { + this.data.server.plexSelectedLibraries = []; + if (x.successful) { + x.data.mediaContainer.directory.forEach((item) => { + const lib: IPlexLibrariesSettings = { + key: item.key, + title: item.title, + enabled: false, + }; + this.data.server.plexSelectedLibraries.push(lib); + }); + } else { + this.notificationService.error(x.message); + } + }); + } + +} diff --git a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html index 23c02be58..8bd1629e3 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html @@ -2,54 +2,71 @@
Plex Configuration +
+
+ +
+
When a Plex User adds something to their watchlist in Plex, it will turn up in Ombi as a Request if enabled. This only applies to users that are logging in with their Plex Account
Request limits if set are all still applied
-
- - - If true then watchlist requests for TV Shows, it will request the whole season. Otherwise it will only request the latest season. - - + + - -
+ +
+
+

Servers

+ + + + -
- - + + + + -
- -
-
-
- - +
- - - +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
-
@@ -59,6 +76,57 @@
+ +
+ +
+
+ +
+ + + + +
+
+ +
+
+ +
+
+ Please select the server: +
+
+
+ + + +
+ +
+ + + + {{s.name}} + + +
+
+
+
+
+
diff --git a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.scss b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.scss index 7acdcf6f0..b6e3bd73e 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.scss +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.scss @@ -21,4 +21,26 @@ ::ng-deep div .mat-tab-body-content { overflow: hidden; -} \ No newline at end of file +} +.server-card { + margin: 0em 1em 1em 0; + width: 13em; + min-height: 8em; + + button { + text-align: center; + align-content: center; + white-space: normal; + overflow-wrap: anywhere; + height: 100%; + width: 100%; + } + + i { + margin-top: 0.25em; + } + + h3 { + margin: 0; + } + } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts index d026fd1dd..cad3a05bd 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts @@ -1,14 +1,14 @@ -import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; -import { Subject } from "rxjs"; -import { takeUntil } from "rxjs/operators"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { EMPTY, Subject } from "rxjs"; +import { catchError, takeUntil } from "rxjs/operators"; -import { IPlexLibrariesSettings, IPlexServer, IPlexServerResponse, IPlexServerViewModel, IPlexSettings } from "../../interfaces"; -import { JobService, NotificationService, PlexService, SettingsService, TesterService } from "../../services"; -import { MatTabChangeEvent, MatTabGroup } from "@angular/material/tabs"; +import { IPlexServer, IPlexServerResponse, IPlexServerViewModel, IPlexSettings } from "../../interfaces"; +import { JobService, NotificationService, PlexService, SettingsService } from "../../services"; import {UntypedFormControl} from '@angular/forms'; import { MatDialog } from "@angular/material/dialog"; import { PlexWatchlistComponent } from "./components/watchlist/plex-watchlist.component"; -import { PlexCreds, PlexSyncType } from "./components/models"; +import { PlexServerDialogComponent } from "./components/plex-server-dialog/plex-server-dialog.component"; +import { PlexServerDialogData, PlexSyncType } from "./components/models"; @Component({ templateUrl: "./plex.component.html", @@ -19,17 +19,17 @@ export class PlexComponent implements OnInit, OnDestroy { public loadedServers: IPlexServerViewModel; // This comes from the api call for the user to select a server public serversButton = false; selected = new UntypedFormControl(0); - @ViewChild("tabGroup", {static: false}) public tagGroup: MatTabGroup; - public advanced = false; + public username: string; + public password: string; private subscriptions = new Subject(); + public PlexSyncType = PlexSyncType; constructor( private settingsService: SettingsService, private notificationService: NotificationService, private plexService: PlexService, - private testerService: TesterService, private jobService: JobService, private dialog: MatDialog) { } @@ -39,9 +39,13 @@ export class PlexComponent implements OnInit, OnDestroy { }); } - public requestServers({ username, password }: PlexCreds) { - this.plexService.getServers(username, password).pipe( + public requestServers() { + this.plexService.getServers(this.username, this.password).pipe( takeUntil(this.subscriptions), + catchError(() => { + this.notificationService.error("There was an issue. Please make sure your username and password are correct"); + return EMPTY; + }) ).subscribe(x => { if (x.success) { this.loadedServers = x; @@ -53,7 +57,9 @@ export class PlexComponent implements OnInit, OnDestroy { }); } - public selectServer(selectedServer: IPlexServerResponse, server: IPlexServer) { + public selectServer(selectedServer: IPlexServerResponse) { + const server = { name: "New" + this.settings.servers.length + "*", id: Math.floor(Math.random() * (99999 - 0 + 1) + 1) }; + var splitServers = selectedServer.localAddresses.split(","); if (splitServers.length > 1) { server.ip = splitServers[splitServers.length - 1]; @@ -68,61 +74,7 @@ export class PlexComponent implements OnInit, OnDestroy { server.serverHostname = ""; this.notificationService.success(`Selected ${server.name}!`); - } - - public testPlex(server: IPlexServer) { - this.testerService.plexTest(server).subscribe(x => { - if (x === true) { - this.notificationService.success(`Successfully connected to the Plex server ${server.name}!`); - } else { - this.notificationService.error(`We could not connect to the Plex server ${server.name}!`); - } - }); - } - - 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) }); - - //this.tagGroup.selectedIndex = (0); - this.selected.setValue(this.settings.servers.length - 1); - } - } - - public removeServer(server: IPlexServer) { - 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); - } - } - - public loadLibraries(server: IPlexServer) { - if (server.ip == null) { - this.notificationService.error("Plex is not yet configured correctly"); - return; - } - this.plexService.getLibraries(server).subscribe(x => { - server.plexSelectedLibraries = []; - if (x.successful) { - x.data.mediaContainer.directory.forEach((item) => { - const lib: IPlexLibrariesSettings = { - key: item.key, - title: item.title, - enabled: false, - }; - server.plexSelectedLibraries.push(lib); - }); - } else { - this.notificationService.error(x.message); - } - }, - err => { this.notificationService.error(err); }); + this.newServer(server); } public save() { @@ -167,6 +119,55 @@ export class PlexComponent implements OnInit, OnDestroy { } } + public edit(server: IPlexServer) { + const data: PlexServerDialogData = { + server: server, + }; + const dialog = this.dialog.open(PlexServerDialogComponent, { + width: "700px", + data: data, + panelClass: "modal-panel", + }); + dialog.afterClosed().subscribe((x) => { + if (x.deleted) { + this.removeServer(server); + } + if (x.server) { + console.log(x.server); + var idx = this.settings.servers.findIndex(server => server.id === x.server.id); + if (idx >= 0) { + this.settings.servers[idx] = x.server; + } else { + this.settings.servers.push(x.server); + } + } + }); + } + + public newServer(server: IPlexServer) { + if(!server) { + server = { name: "New" + this.settings.servers.length + "*", id: Math.floor(Math.random() * (99999 - 0 + 1) + 1) }; + } + const dialog = this.dialog.open(PlexServerDialogComponent, { + width: "700px", + data: {server: server}, + panelClass: "modal-panel", + }); + dialog.afterClosed().subscribe((x) => { + if (x.server) { + this.settings.servers.push(x.server); + } + }); + } + + private removeServer(server: IPlexServer) { + 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); + } + } + private runCacher(): void { this.jobService.runPlexCacher().subscribe(x => { if (x) { diff --git a/src/Ombi/ClientApp/src/app/settings/settings.module.ts b/src/Ombi/ClientApp/src/app/settings/settings.module.ts index a1b530f11..990e89837 100644 --- a/src/Ombi/ClientApp/src/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/src/app/settings/settings.module.ts @@ -50,7 +50,7 @@ import { LandingPageComponent } from "./landingpage/landingpage.component"; import { LidarrComponent } from "./lidarr/lidarr.component"; import { LogsComponent } from "./logs/logs.component"; import { MassEmailComponent } from "./massemail/massemail.component"; -import { MatDialogModule } from "@angular/material/dialog"; +import { MatDialogActions, MatDialogModule } from "@angular/material/dialog"; import { MatMenuModule } from "@angular/material/menu"; import { MattermostComponent } from "./notifications/mattermost.component"; import {MenuModule} from "primeng/menu"; @@ -86,6 +86,7 @@ import { WikiComponent } from "./wiki.component"; import { PlexWatchlistComponent } from "./plex/components/watchlist/plex-watchlist.component"; import { PlexFormComponent } from "./plex/components/plex-form/plex-form.component"; import { PlexFormFieldComponent } from "./plex/components/form-field/plex-form-field.component"; +import { PlexServerDialogComponent } from "./plex/components/plex-server-dialog/plex-server-dialog.component"; const routes: Routes = [ { path: "Ombi", component: OmbiComponent, canActivate: [AuthGuard] }, @@ -146,7 +147,7 @@ const routes: Routes = [ DialogModule, SharedModule, MatMenuModule, - MatDialogModule + MatDialogModule, ], declarations: [ SettingsMenuComponent, @@ -195,6 +196,7 @@ const routes: Routes = [ PlexWatchlistComponent, PlexFormComponent, PlexFormFieldComponent, + PlexServerDialogComponent, ], exports: [ RouterModule,