|
|
@ -1,12 +1,14 @@
|
|
|
|
using System;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
using FluentValidation.Results;
|
|
|
|
using FluentValidation.Results;
|
|
|
|
using NLog;
|
|
|
|
using NLog;
|
|
|
|
using NzbDrone.Common.Cache;
|
|
|
|
using NzbDrone.Common.Cache;
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
|
|
|
|
using NzbDrone.Core.RootFolders;
|
|
|
|
using NzbDrone.Core.Tv;
|
|
|
|
using NzbDrone.Core.Tv;
|
|
|
|
using NzbDrone.Core.Validation;
|
|
|
|
using NzbDrone.Core.Validation;
|
|
|
|
|
|
|
|
|
|
|
@ -22,15 +24,15 @@ namespace NzbDrone.Core.Notifications.Plex.Server
|
|
|
|
public class PlexServerService : IPlexServerService
|
|
|
|
public class PlexServerService : IPlexServerService
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private readonly ICached<Version> _versionCache;
|
|
|
|
private readonly ICached<Version> _versionCache;
|
|
|
|
private readonly ICached<bool> _partialUpdateCache;
|
|
|
|
|
|
|
|
private readonly IPlexServerProxy _plexServerProxy;
|
|
|
|
private readonly IPlexServerProxy _plexServerProxy;
|
|
|
|
|
|
|
|
private readonly IRootFolderService _rootFolderService;
|
|
|
|
private readonly Logger _logger;
|
|
|
|
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<Version>(GetType(), "versionCache");
|
|
|
|
_versionCache = cacheManager.GetCache<Version>(GetType(), "versionCache");
|
|
|
|
_partialUpdateCache = cacheManager.GetCache<bool>(GetType(), "partialUpdateCache");
|
|
|
|
|
|
|
|
_plexServerProxy = plexServerProxy;
|
|
|
|
_plexServerProxy = plexServerProxy;
|
|
|
|
|
|
|
|
_rootFolderService = rootFolderService;
|
|
|
|
_logger = logger;
|
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -50,32 +52,10 @@ namespace NzbDrone.Core.Notifications.Plex.Server
|
|
|
|
ValidateVersion(version);
|
|
|
|
ValidateVersion(version);
|
|
|
|
|
|
|
|
|
|
|
|
var sections = GetSections(settings);
|
|
|
|
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;
|
|
|
|
UpdateSections(series, sections, settings);
|
|
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_logger.Debug("Finished sending Update Request to Plex Server (took {0} ms)", watch.ElapsedMilliseconds);
|
|
|
|
_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();
|
|
|
|
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)
|
|
|
|
private void ValidateVersion(Version version)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (version >= new Version(1, 3, 0) && version < new Version(1, 3, 1))
|
|
|
|
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;
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<PlexPreference> GetPreferences(PlexServerSettings settings)
|
|
|
|
private void UpdateSections(Series series, List<PlexSection> sections, PlexServerSettings settings)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_logger.Debug("Getting preferences from Plex host: {0}", settings.Host);
|
|
|
|
var rootFolderPath = _rootFolderService.GetBestRootFolderPath(series.Path);
|
|
|
|
|
|
|
|
var seriesRelativePath = rootFolderPath.GetRelativePath(series.Path);
|
|
|
|
return _plexServerProxy.Preferences(settings);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateSection(int sectionId, PlexServerSettings settings)
|
|
|
|
// Try to update a matching section location before falling back to updating all section locations.
|
|
|
|
{
|
|
|
|
foreach (var section in sections)
|
|
|
|
_logger.Debug("Updating Plex host: {0}, Section: {1}", settings.Host, sectionId);
|
|
|
|
{
|
|
|
|
|
|
|
|
foreach (var location in section.Locations)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (location.Path.PathEquals(rootFolderPath))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_logger.Debug("Updating matching section location, {0}", location.Path);
|
|
|
|
|
|
|
|
UpdateSectionPath(seriesRelativePath, section, location, settings);
|
|
|
|
|
|
|
|
|
|
|
|
_plexServerProxy.Update(sectionId, settings);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool UpdatePartialSection(Series series, List<PlexSection> sections, PlexServerSettings settings)
|
|
|
|
_logger.Debug("Unable to find matching section location, updating all TV sections");
|
|
|
|
{
|
|
|
|
|
|
|
|
var partiallyUpdated = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var section in sections)
|
|
|
|
foreach (var section in sections)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var metadataId = GetMetadataId(section.Id, series, section.Language, settings);
|
|
|
|
foreach (var location in section.Locations)
|
|
|
|
|
|
|
|
|
|
|
|
if (metadataId.IsNotNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_logger.Debug("Updating Plex host: {0}, Section: {1}, Series: {2}", settings.Host, section.Id, series);
|
|
|
|
UpdateSectionPath(seriesRelativePath, section, location, settings);
|
|
|
|
_plexServerProxy.UpdateSeries(metadataId, settings);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
partiallyUpdated = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return partiallyUpdated;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Plex location paths trim trailing extraneous separator characters, so it doesn't need to be trimmed
|
|
|
|
|
|
|
|
var pathToUpdate = $"{location.Path}{separator}{locationRelativePath}";
|
|
|
|
|
|
|
|
|
|
|
|
return _plexServerProxy.GetMetadataId(sectionId, series.TvdbId, language, settings);
|
|
|
|
_logger.Debug("Updating section location, {0}", location.Path);
|
|
|
|
|
|
|
|
_plexServerProxy.Update(section.Id, pathToUpdate, settings);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ValidationFailure Test(PlexServerSettings settings)
|
|
|
|
public ValidationFailure Test(PlexServerSettings settings)
|
|
|
@ -183,7 +140,6 @@ namespace NzbDrone.Core.Notifications.Plex.Server
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_versionCache.Remove(settings.Host);
|
|
|
|
_versionCache.Remove(settings.Host);
|
|
|
|
_partialUpdateCache.Remove(settings.Host);
|
|
|
|
|
|
|
|
var sections = GetSections(settings);
|
|
|
|
var sections = GetSections(settings);
|
|
|
|
|
|
|
|
|
|
|
|
if (sections.Empty())
|
|
|
|
if (sections.Empty())
|
|
|
|