#865 Added support for multiple plex servers

This commit is contained in:
Jamie.Rees 2017-05-15 15:30:12 +01:00
commit 3879fc04de
11 changed files with 270 additions and 177 deletions

View file

@ -73,7 +73,8 @@ namespace Ombi.Schedule.Jobs
StartTheCache(plexSettings).Wait();
}
catch (Exception e) {
catch (Exception e)
{
Logger.LogWarning(LoggingEvents.CacherException, e, "Exception thrown when attempting to cache the Plex Content");
}
}
@ -119,7 +120,10 @@ namespace Ombi.Schedule.Jobs
private async Task StartTheCache(PlexSettings plexSettings)
{
var allContent = GetAllContent(plexSettings);
foreach (var servers in plexSettings.Servers ?? new List<PlexServers>())
{
var allContent = GetAllContent(servers);
// Let's now process this.
@ -131,7 +135,7 @@ namespace Ombi.Schedule.Jobs
// Process Shows
foreach (var metadata in content.Metadata)
{
var seasonList = await PlexApi.GetSeasons(plexSettings.PlexAuthToken, plexSettings.FullUri,
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
metadata.ratingKey);
var seasonsContent = new List<SeasonsContent>();
foreach (var season in seasonList.MediaContainer.Metadata)
@ -166,7 +170,7 @@ namespace Ombi.Schedule.Jobs
// Get the show metadata... This sucks since the `metadata` var contains all information about the show
// But it does not contain the `guid` property that we need to pull out thetvdb id...
var showMetadata = await PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
metadata.ratingKey);
var item = new PlexContent
{
@ -178,7 +182,7 @@ namespace Ombi.Schedule.Jobs
ReleaseYear = metadata.year.ToString(),
Type = PlexMediaTypeEntity.Show,
Title = metadata.title,
Url = PlexHelper.GetPlexMediaUrl(plexSettings.MachineIdentifier, metadata.ratingKey),
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, metadata.ratingKey),
Seasons = new List<SeasonsContent>()
};
@ -194,9 +198,11 @@ namespace Ombi.Schedule.Jobs
{
await Repo.AddRange(contentToAdd);
}
}
}
private List<Mediacontainer> GetAllContent(PlexSettings plexSettings)
private List<Mediacontainer> GetAllContent(PlexServers plexSettings)
{
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri).Result;
@ -232,11 +238,14 @@ namespace Ombi.Schedule.Jobs
{
if (plex.Enable)
{
if (string.IsNullOrEmpty(plex?.Ip) || string.IsNullOrEmpty(plex?.PlexAuthToken))
foreach (var server in plex.Servers ?? new List<PlexServers>())
{
if (string.IsNullOrEmpty(server?.Ip) || string.IsNullOrEmpty(server?.PlexAuthToken))
{
return false;
}
}
}
return plex.Enable;
}
}

View file

@ -2,10 +2,16 @@
namespace Ombi.Core.Settings.Models.External
{
public sealed class PlexSettings : ExternalSettings
public sealed class PlexSettings : Ombi.Settings.Settings.Models.Settings
{
public bool Enable { get; set; }
public List<PlexServers> Servers { get; set; }
}
public class PlexServers : ExternalSettings
{
public string Name { get; set; }
public bool EnableEpisodeSearching { get; set; }
public string PlexAuthToken { get; set; }
@ -13,7 +19,6 @@ namespace Ombi.Core.Settings.Models.External
public List<PlexSelectedLibraries> PlexSelectedLibraries { get; set; }
}
public class PlexSelectedLibraries
{
public int Key { get; set; }

View file

@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -28,29 +30,42 @@ namespace Ombi.Controllers.External
{
// Do we already have settings?
var settings = await PlexSettings.GetSettingsAsync();
if (!string.IsNullOrEmpty(settings?.PlexAuthToken)) return null;
if (!settings.Servers?.Any() ?? false) return null;
var result = await PlexApi.SignIn(request);
if (!string.IsNullOrEmpty(result.user?.authentication_token))
{
var server = await PlexApi.GetServer(result.user.authentication_token);
var firstServer = server.Server.FirstOrDefault();
await PlexSettings.SaveSettingsAsync(new PlexSettings
var servers = server.Server;
settings.Servers = new List<PlexServers>();
var serverNumber = 0;
foreach (var s in servers)
{
if (string.IsNullOrEmpty(s.LocalAddresses) || string.IsNullOrEmpty(s.Port))
{
continue;
}
settings.Servers.Add(new PlexServers
{
Enable = true,
PlexAuthToken = result.user.authentication_token,
Ip = firstServer.LocalAddresses,
MachineIdentifier = firstServer.MachineIdentifier,
Port = int.Parse(firstServer.Port),
Ssl = firstServer.Scheme != "http",
Id = new Random().Next(),
Ip = s.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
MachineIdentifier = s.MachineIdentifier,
Port = int.Parse(s.Port),
Ssl = s.Scheme != "http",
Name = $"Server{serverNumber++}"
});
}
await PlexSettings.SaveSettingsAsync(settings);
}
return result;
}
[HttpPost("Libraries")]
public async Task<PlexLibraries> GetPlexLibraries([FromBody] PlexSettings settings)
public async Task<PlexLibraries> GetPlexLibraries([FromBody] PlexServers settings)
{
var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);

View file

@ -35,6 +35,7 @@ var paths = {
'@angular/forms',
'@angular/platform-browser/animations',
'@angular/material',
'@ng-bootstrap/ng-bootstrap',
'ngx-infinite-scroll'
],
dest: './lib'

View file

@ -15,6 +15,7 @@
"@angular/platform-browser-dynamic": "^4.1.0",
"@angular/platform-server": "^4.1.0",
"@angular/router": "^4.1.0",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.25",
"@types/jquery": "^2.0.33",
"@types/systemjs": "^0.20.2",
"angular2-jwt": "^0.2.0",

View file

@ -2,7 +2,8 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { MdButtonModule} from '@angular/material';
import { MdButtonModule } from '@angular/material';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
@ -75,7 +76,8 @@ const routes: Routes = [
AuthModule,
WizardModule,
DialogModule,
MdButtonModule
MdButtonModule,
NgbModule.forRoot(),
],
declarations: [
AppComponent,

View file

@ -4,7 +4,6 @@
export interface IExternalSettings extends ISettings {
ssl: boolean,
enable:boolean,
subDir: string,
ip: string,
port:number,
@ -20,15 +19,23 @@ export interface IOmbiSettings extends ISettings {
export interface IEmbySettings extends IExternalSettings {
apiKey: string,
enable: boolean,
administratorId: string,
enableEpisodeSearching:boolean,
}
export interface IPlexSettings extends IExternalSettings {
export interface IPlexSettings extends ISettings {
enable: boolean,
servers : IPlexServer[]
}
export interface IPlexServer extends IExternalSettings {
name:string,
enableEpisodeSearching: boolean,
plexAuthToken: string,
machineIdentifier: string,
plexSelectedLibraries : IPlexLibraries[],
plexSelectedLibraries: IPlexLibraries[],
}
export interface IPlexLibraries {
@ -39,6 +46,7 @@ export interface IPlexLibraries {
export interface ISonarrSettings extends IExternalSettings {
apiKey: string,
enable: boolean,
qualityProfile: string,
seasonFolders: boolean,
rootPath: string,

View file

@ -2,7 +2,7 @@
<h1>Login</h1>
<div>
<p>
@UI.UserLogin_Paragraph <span title="@UI.UserLogin_Paragraph_SpanHover"><i class="fa fa-question-circle"></i></span>
Hey! Welcome, login with your credentails below!
</p>
</div>
<form method="POST" id="loginForm">

View file

@ -10,25 +10,47 @@
<label for="enable">Enable</label>
</div>
</div>
<div style="float: right;">
<button type="submit" (click)="addTab()" class="btn btn-success-outline">Add Server</button>
</div>
<ngb-tabset>
<div *ngFor="let server of settings.servers">
<ngb-tab [id]="server.id" [title]="server.name">
<ng-template ngbTabContent>
<br/>
<br/>
<div style="float: right;">
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
</div>
<br/>
<br/>
<div class="form-group">
<label for="name" class="control-label">Server name</label>
<div>
<input type="text" class="form-control form-control-custom " id="name" name="name" placeholder="Server" [(ngModel)]="server.name" value="{{server.name}}">
</div>
</div>
<div class="form-group">
<label for="Ip" class="control-label">Hostname or IP</label>
<div>
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" [(ngModel)]="settings.ip" value="{{settings.ip}}">
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" [(ngModel)]="server.ip" value="{{server.ip}}">
</div>
</div>
<div class="form-group">
<label for="portNumber" class="control-label">Port</label>
<div>
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{settings.port}}">
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{server.port}}">
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="ssl" [(ngModel)]="settings.ssl" ng-checked="settings.ssl">
<input type="checkbox" id="ssl" [(ngModel)]="server.ssl" ng-checked="server.ssl">
<label for="ssl">SSL</label>
</div>
</div>
@ -37,7 +59,7 @@
<div class="checkbox">
<input type="checkbox" id="EnableTvEpisodeSearching" [(ngModel)]="settings.enableEpisodeSearching" ng-checked="settings.enableEpisodeSearching">
<input type="checkbox" id="EnableTvEpisodeSearching" [(ngModel)]="server.enableEpisodeSearching" ng-checked="server.enableEpisodeSearching">
<label for="EnableTvEpisodeSearching">Enable Episode Searching</label>
</div>
@ -51,14 +73,14 @@
<div class="form-group">
<label for="authToken" class="control-label">Plex Authorization Token</label>
<div class="">
<input type="text" class="form-control-custom form-control" id="authToken" [(ngModel)]="settings.plexAuthToken" placeholder="Plex Auth Token" value="{{settings.plexAuthToken}}">
<input type="text" class="form-control-custom form-control" id="authToken" [(ngModel)]="server.plexAuthToken" placeholder="Plex Auth Token" value="{{server.plexAuthToken}}">
</div>
</div>
<div class="form-group">
<label for="MachineIdentifier" class="control-label">Machine Identifier</label>
<div class="">
<input type="text" class="form-control-custom form-control" id="MachineIdentifier" name="MachineIdentifier" [(ngModel)]="settings.machineIdentifier" value="{{settings.machineIdentifier}}">
<input type="text" class="form-control-custom form-control" id="MachineIdentifier" name="MachineIdentifier" [(ngModel)]="server.machineIdentifier" value="{{server.machineIdentifier}}">
</div>
</div>
@ -67,7 +89,7 @@
<div>
<input type="text" class="form-control form-control-custom" id="username" [(ngModel)]="username" placeholder="username">
</div>
<br />
<br/>
<div>
<input type="password" class="form-control form-control-custom" id="password" [(ngModel)]="password" placeholder="Password">
</div>
@ -84,8 +106,8 @@
<button (click)="loadLibraries()" class="btn btn-primary-outline">Load Libraries <i class="fa fa-film"></i></button>
</div>
</div>
<div *ngIf="settings.plexSelectedLibraries">
<div *ngFor="let lib of settings.plexSelectedLibraries">
<div *ngIf="server.plexSelectedLibraries">
<div *ngFor="let lib of server.plexSelectedLibraries">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="{{lib.title}}" [(ngModel)]="lib.enabled" ng-checked="lib.enabled">
@ -98,9 +120,17 @@
<div class="form-group">
<div>
<button id="testPlex" type="submit" (click)="testPlex()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
<button id="testPlex" type="submit" (click)="testPlex()" class="btn btn-primary-outline">
Test Connectivity
<div id="spinner"></div>
</button>
</div>
</div>
</ng-template>
</ngb-tab>
</div>
</ngb-tabset>

View file

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { IPlexSettings, IPlexLibraries } from '../../interfaces/ISettings'
import { IPlexSettings, IPlexLibraries, IPlexServer } from '../../interfaces/ISettings'
import { SettingsService } from '../../services/settings.service';
@ -21,7 +21,10 @@ export class PlexComponent implements OnInit {
password: string;
ngOnInit(): void {
this.settingsService.getPlex().subscribe(x => this.settings = x);
this.settingsService.getPlex().subscribe(x => {
this.settings = x;
}
);
}
requestToken() {
@ -32,23 +35,40 @@ export class PlexComponent implements OnInit {
// TODO Plex Service
}
loadLibraries() {
addTab() {
//this.settings.servers.push(<IPlexServer>{ name: "New*", id: Math.floor(Math.random() * (99999 - 0 + 1) + 1) });
this.notificationService.warning("Disabled", "This feature is currently disabled");
}
removeServer(server: IPlexServer) {
this.notificationService.warning("Disabled", "This feature is currently disabled");
//var index = this.settings.servers.indexOf(server, 0);
//if (index > -1) {
// this.settings.servers.splice(index, 1);
//}
}
loadLibraries(server:IPlexServer) {
this.plexService.getLibraries(this.settings).subscribe(x => {
this.settings.plexSelectedLibraries = [];
server.plexSelectedLibraries = [];
x.mediaContainer.directory.forEach((item, index) => {
var lib: IPlexLibraries = {
key: item.key,
title: item.title,
enabled: false
};
this.settings.plexSelectedLibraries.push(lib);
server.plexSelectedLibraries.push(lib);
});
});
}
save() {
var filtered = this.settings.servers.filter(x => x.name !== "");
this.settings.servers = filtered;
this.settingsService.savePlex(this.settings).subscribe(x => {
if (x) {
this.notificationService.success("Settings Saved", "Successfully saved Plex settings");

View file

@ -2,6 +2,7 @@
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AuthService } from '../auth/auth.service';
import { AuthGuard } from '../auth/auth.guard';
@ -34,7 +35,8 @@ const routes: Routes = [
MenuModule,
InputSwitchModule,
InputTextModule,
AuthModule
AuthModule,
NgbModule
],
declarations: [
SettingsMenuComponent,