From 98308737cfa78a41ec22a2b23a80bf316bd779ea Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Thu, 16 Mar 2023 20:25:31 -0700 Subject: [PATCH] New: Improved Plex library updating --- .../Plex/Server/PlexServerProxy.cs | 65 +--------- .../Plex/Server/PlexServerService.cs | 114 ++++++------------ 2 files changed, 39 insertions(+), 140 deletions(-) diff --git a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs index 523706334..47242a0bc 100644 --- a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs +++ b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; +using System.Web; using NLog; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; @@ -14,11 +15,8 @@ namespace NzbDrone.Core.Notifications.Plex.Server public interface IPlexServerProxy { List GetTvSections(PlexServerSettings settings); - void Update(int sectionId, PlexServerSettings settings); - void UpdateSeries(string metadataId, PlexServerSettings settings); string Version(PlexServerSettings settings); - List Preferences(PlexServerSettings settings); - string GetMetadataId(int sectionId, int tvdbId, string language, PlexServerSettings settings); + void Update(int sectionId, string path, PlexServerSettings settings); } public class PlexServerProxy : IPlexServerProxy @@ -63,19 +61,13 @@ namespace NzbDrone.Core.Notifications.Plex.Server .ToList(); } - public void Update(int sectionId, PlexServerSettings settings) + public void Update(int sectionId, string path, PlexServerSettings settings) { var resource = $"library/sections/{sectionId}/refresh"; var request = BuildRequest(resource, HttpMethod.Get, settings); - var response = ProcessRequest(request); - CheckForError(response); - } + request.AddQueryParam("path", path); - public void UpdateSeries(string metadataId, PlexServerSettings settings) - { - var resource = $"library/metadata/{metadataId}/refresh"; - var request = BuildRequest(resource, HttpMethod.Put, settings); var response = ProcessRequest(request); CheckForError(response); @@ -99,55 +91,6 @@ namespace NzbDrone.Core.Notifications.Plex.Server .Version; } - public List Preferences(PlexServerSettings settings) - { - var request = BuildRequest(":/prefs", HttpMethod.Get, settings); - var response = ProcessRequest(request); - - CheckForError(response); - - if (response.Contains("_children")) - { - return Json.Deserialize(response) - .Preferences; - } - - return Json.Deserialize>(response) - .MediaContainer - .Preferences; - } - - public string GetMetadataId(int sectionId, int tvdbId, string language, PlexServerSettings settings) - { - var guid = $"com.plexapp.agents.thetvdb://{tvdbId}?lang={language}"; - var resource = $"library/sections/{sectionId}/all?guid={System.Web.HttpUtility.UrlEncode(guid)}"; - var request = BuildRequest(resource, HttpMethod.Get, settings); - var response = ProcessRequest(request); - - CheckForError(response); - - List items; - - if (response.Contains("_children")) - { - items = Json.Deserialize(response) - .Items; - } - else - { - items = Json.Deserialize>(response) - .MediaContainer - .Items; - } - - if (items == null || items.Empty()) - { - return null; - } - - return items.First().Id; - } - private HttpRequestBuilder BuildRequest(string resource, HttpMethod method, PlexServerSettings settings) { var scheme = settings.UseSsl ? "https" : "http"; diff --git a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerService.cs b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerService.cs index 1b4914ec1..30bf9fde3 100644 --- a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerService.cs +++ b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerService.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using FluentValidation.Results; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.RootFolders; using NzbDrone.Core.Tv; using NzbDrone.Core.Validation; @@ -22,15 +24,15 @@ namespace NzbDrone.Core.Notifications.Plex.Server public class PlexServerService : IPlexServerService { private readonly ICached _versionCache; - private readonly ICached _partialUpdateCache; private readonly IPlexServerProxy _plexServerProxy; + private readonly IRootFolderService _rootFolderService; private readonly Logger _logger; - public PlexServerService(ICacheManager cacheManager, IPlexServerProxy plexServerProxy, Logger logger) + public PlexServerService(ICacheManager cacheManager, IPlexServerProxy plexServerProxy, IRootFolderService rootFolderService, Logger logger) { _versionCache = cacheManager.GetCache(GetType(), "versionCache"); - _partialUpdateCache = cacheManager.GetCache(GetType(), "partialUpdateCache"); _plexServerProxy = plexServerProxy; + _rootFolderService = rootFolderService; _logger = logger; } @@ -50,32 +52,10 @@ namespace NzbDrone.Core.Notifications.Plex.Server ValidateVersion(version); var sections = GetSections(settings); - var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings, version), TimeSpan.FromHours(2)); - if (partialUpdates) + foreach (var series in multipleSeries) { - var partiallyUpdated = true; - - foreach (var series in multipleSeries) - { - partiallyUpdated &= UpdatePartialSection(series, sections, settings); - - if (!partiallyUpdated) - { - break; - } - } - - // Only update complete sections if all partial updates failed - if (!partiallyUpdated) - { - _logger.Debug("Unable to update partial section, updating all TV sections"); - sections.ForEach(s => UpdateSection(s.Id, settings)); - } - } - else - { - sections.ForEach(s => UpdateSection(s.Id, settings)); + UpdateSections(series, sections, settings); } _logger.Debug("Finished sending Update Request to Plex Server (took {0} ms)", watch.ElapsedMilliseconds); @@ -94,31 +74,6 @@ namespace NzbDrone.Core.Notifications.Plex.Server return _plexServerProxy.GetTvSections(settings).ToList(); } - private bool PartialUpdatesAllowed(PlexServerSettings settings, Version version) - { - try - { - if (version >= new Version(0, 9, 12, 0)) - { - var preferences = GetPreferences(settings); - var partialScanPreference = preferences.SingleOrDefault(p => p.Id.Equals("FSEventLibraryPartialScanEnabled")); - - if (partialScanPreference == null) - { - return false; - } - - return Convert.ToBoolean(partialScanPreference.Value); - } - } - catch (Exception ex) - { - _logger.Warn(ex, "Unable to check if partial updates are allowed"); - } - - return false; - } - private void ValidateVersion(Version version) { if (version >= new Version(1, 3, 0) && version < new Version(1, 3, 1)) @@ -137,45 +92,47 @@ namespace NzbDrone.Core.Notifications.Plex.Server return version; } - private List GetPreferences(PlexServerSettings settings) + private void UpdateSections(Series series, List sections, PlexServerSettings settings) { - _logger.Debug("Getting preferences from Plex host: {0}", settings.Host); - - return _plexServerProxy.Preferences(settings); - } - - private void UpdateSection(int sectionId, PlexServerSettings settings) - { - _logger.Debug("Updating Plex host: {0}, Section: {1}", settings.Host, sectionId); - - _plexServerProxy.Update(sectionId, settings); - } - - private bool UpdatePartialSection(Series series, List sections, PlexServerSettings settings) - { - var partiallyUpdated = false; + var rootFolderPath = _rootFolderService.GetBestRootFolderPath(series.Path); + var seriesRelativePath = rootFolderPath.GetRelativePath(series.Path); + // Try to update a matching section location before falling back to updating all section locations. foreach (var section in sections) { - var metadataId = GetMetadataId(section.Id, series, section.Language, settings); - - if (metadataId.IsNotNullOrWhiteSpace()) + foreach (var location in section.Locations) { - _logger.Debug("Updating Plex host: {0}, Section: {1}, Series: {2}", settings.Host, section.Id, series); - _plexServerProxy.UpdateSeries(metadataId, settings); + if (location.Path.PathEquals(rootFolderPath)) + { + _logger.Debug("Updating matching section location, {0}", location.Path); + UpdateSectionPath(seriesRelativePath, section, location, settings); - partiallyUpdated = true; + return; + } } } - return partiallyUpdated; + _logger.Debug("Unable to find matching section location, updating all TV sections"); + + foreach (var section in sections) + { + foreach (var location in section.Locations) + { + UpdateSectionPath(seriesRelativePath, section, location, settings); + } + } } - private string GetMetadataId(int sectionId, Series series, string language, PlexServerSettings settings) + private void UpdateSectionPath(string seriesRelativePath, PlexSection section, PlexSectionLocation location, PlexServerSettings settings) { - _logger.Debug("Getting metadata from Plex host: {0} for series: {1}", settings.Host, series); + var separator = location.Path.Contains('\\') ? "\\" : "/"; + var locationRelativePath = seriesRelativePath.Replace("\\", separator).Replace("/", separator); - return _plexServerProxy.GetMetadataId(sectionId, series.TvdbId, language, settings); + // Plex location paths trim trailing extraneous separator characters, so it doesn't need to be trimmed + var pathToUpdate = $"{location.Path}{separator}{locationRelativePath}"; + + _logger.Debug("Updating section location, {0}", location.Path); + _plexServerProxy.Update(section.Id, pathToUpdate, settings); } public ValidationFailure Test(PlexServerSettings settings) @@ -183,7 +140,6 @@ namespace NzbDrone.Core.Notifications.Plex.Server try { _versionCache.Remove(settings.Host); - _partialUpdateCache.Remove(settings.Host); var sections = GetSections(settings); if (sections.Empty())