diff --git a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs index 5a2b6ed98..42e97f5f7 100644 --- a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Store.Entities; using Ombi.Store.Repository; @@ -11,10 +13,13 @@ namespace Ombi.Core.Rule.Rules.Search { public class PlexAvailabilityRule : BaseSearchRule, IRules { - public PlexAvailabilityRule(IPlexContentRepository repo, ILogger log) + private readonly ISettingsService _plexSettings; + + public PlexAvailabilityRule(IPlexContentRepository repo, ILogger log, ISettingsService plexSettings) { PlexContentRepository = repo; Log = log; + _plexSettings = plexSettings; } private IPlexContentRepository PlexContentRepository { get; } @@ -72,13 +77,20 @@ namespace Ombi.Core.Rule.Rules.Search if (item != null) { + var settings = await _plexSettings.GetSettingsAsync(); + var firstServer = settings.Servers.FirstOrDefault(); + var host = string.Empty; + if (firstServer != null) + { + host = firstServer.ServerHostname; + } if (useId) { obj.TheMovieDbId = obj.Id.ToString(); useTheMovieDb = true; } obj.Available = true; - obj.PlexUrl = item.Url; + obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host); obj.Quality = item.Quality; if (obj.Type == RequestType.TvShow) diff --git a/src/Ombi.Helpers.Tests/PlexHelperTests.cs b/src/Ombi.Helpers.Tests/PlexHelperTests.cs index e7d35a583..e54df6644 100644 --- a/src/Ombi.Helpers.Tests/PlexHelperTests.cs +++ b/src/Ombi.Helpers.Tests/PlexHelperTests.cs @@ -76,6 +76,29 @@ namespace Ombi.Helpers.Tests } } + [TestCaseSource(nameof(PlexBuildUrlData))] + public string BuildPlexMediaUrlTest(string saved, string hostname) + { + return PlexHelper.BuildPlexMediaUrl(saved, hostname); + } + + public static IEnumerable PlexBuildUrlData + { + get + { + yield return new TestCaseData("web/app#!/server/df5", "https://myhost.com/").Returns("https://myhost.com/web/app#!/server/df5"); + yield return new TestCaseData("web/app#!/server/df5", "").Returns("https://app.plex.tv/web/app#!/server/df5"); + yield return new TestCaseData("web/app#!/server/df5", "https://myhost.com").Returns("https://myhost.com/web/app#!/server/df5"); + yield return new TestCaseData("web/app#!/server/df5", "http://myhost.com").Returns("http://myhost.com/web/app#!/server/df5"); + yield return new TestCaseData("web/app#!/server/df5", "http://www.myhost.com").Returns("http://www.myhost.com/web/app#!/server/df5"); + yield return new TestCaseData("web/app#!/server/df5", "http://www.myhost.com:3456").Returns("http://www.myhost.com:3456/web/app#!/server/df5").SetName("PortTest"); + yield return new TestCaseData("https://app.plex.tv/web/app#!/server/df5", "http://www.myhost.com:3456").Returns("http://www.myhost.com:3456/web/app#!/server/df5"); + yield return new TestCaseData("https://app.plex.tv/web/app#!/server/df5", "https://tidusjar.com:3456").Returns("https://tidusjar.com:3456/web/app#!/server/df5"); + yield return new TestCaseData("https://app.plex.tv/web/app#!/server/df5", "").Returns("https://app.plex.tv/web/app#!/server/df5").SetName("OldUrl_BlankHost"); + } + } + + public enum ProviderIdType { Imdb, diff --git a/src/Ombi.Helpers/PlexHelper.cs b/src/Ombi.Helpers/PlexHelper.cs index 506e0939f..37579d0d0 100644 --- a/src/Ombi.Helpers/PlexHelper.cs +++ b/src/Ombi.Helpers/PlexHelper.cs @@ -107,10 +107,40 @@ namespace Ombi.Helpers public static string GetPlexMediaUrl(string machineId, int mediaId) { var url = - $"https://app.plex.tv/web/app#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}"; + $"web/app#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}"; return url; } + public static string BuildPlexMediaUrl(string savedUrl, string plexHost) + { + if (savedUrl.Contains("app.plex.tv")) + { + var split = savedUrl.Split("https://app.plex.tv/", StringSplitOptions.RemoveEmptyEntries); + if (split.Length == 1) + { + savedUrl = split[0]; + } + else + { + throw new ArgumentException($"Attempt to parse url {savedUrl} and could not"); + } + } + if (!plexHost.HasValue()) + { + plexHost = "https://app.plex.tv/"; + } + else + { + if (plexHost[plexHost.Length - 1] != '/') + { + plexHost += '/'; + } + } + + + return $"{plexHost}{savedUrl}"; + } + public static ProviderId GetProviderIdsFromMetadata(params string[] guids) { var providerIds = new ProviderId(); diff --git a/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs b/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs index 8fc8111f7..6cf021f7c 100644 --- a/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs @@ -21,6 +21,7 @@ namespace Ombi.Core.Settings.Models.External public string MachineIdentifier { get; set; } public int EpisodeBatchSize { get; set; } + public string ServerHostname { get; set; } = "https://app.plex.tv"; public List PlexSelectedLibraries { get; set; } = new List(); } diff --git a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts index 236dd12d6..841ff2d86 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts @@ -115,6 +115,7 @@ export interface IPlexServer extends IExternalSettings { machineIdentifier: string; episodeBatchSize: number; plexSelectedLibraries: IPlexLibrariesSettings[]; + serverHostname: string; } export interface IPlexLibrariesSettings { 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 3b05e4585..f84395043 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.html @@ -68,6 +68,16 @@ [(ngModel)]="server.machineIdentifier" value="{{server.machineIdentifier}}"> +
+ + Externally Facing Hostname + + + + Current URL: "{{server.serverHostname}}/web/app#!/server/{{server.machineIdentifier}}/details?key=%2flibrary%2Fmetadata%2F53334" + Current URL: "https://app.plex.tv/web/app#!/server/{{server.machineIdentifier}}/details?key=%2flibrary%2Fmetadata%2F53334" + +
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 894f9ef6a..b1e4de171 100644 --- a/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/plex/plex.component.ts @@ -55,6 +55,8 @@ export class PlexComponent implements OnInit, OnDestroy { var splitServers = selectedServer.localAddresses.split(","); if (splitServers.length > 1) { server.ip = splitServers[splitServers.length - 1]; + } else { + server.ip = selectedServer.localAddresses; } server.name = selectedServer.name; server.machineIdentifier = selectedServer.machineIdentifier; @@ -123,6 +125,19 @@ export class PlexComponent implements OnInit, OnDestroy { public save() { const filtered = this.settings.servers.filter(x => x.name !== ""); this.settings.servers = filtered; + let invalid = false; + + this.settings.servers.forEach(server => { + if (server.serverHostname.length > 0 && !server.serverHostname.startsWith("http")) { + invalid = true; + } + }); + + if (invalid) { + this.notificationService.error("Please ensure that your External Hostname is a full URL including the Scheme (http/https)") + return; + } + this.settingsService.savePlex(this.settings).subscribe(x => { if (x) { this.notificationService.success("Successfully saved Plex settings");