New: Synology Media Indexer support in Connect.

pull/4/head
Taloth Saldono 9 years ago
parent 93c6047cd5
commit 15eeb19cd5

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Notifications.Synology;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.NotificationTests
{
[TestFixture]
public class SynologyIndexerFixture : CoreTest<SynologyIndexer>
{
private Series _series;
private DownloadMessage _upgrade;
[SetUp]
public void SetUp()
{
_series = new Series()
{
Path = @"C:\Test\".AsOsAgnostic()
};
_upgrade = new DownloadMessage()
{
Series = _series,
EpisodeFile = new EpisodeFile
{
RelativePath = "file1.S01E01E02.mkv"
},
OldFiles = new List<EpisodeFile>
{
new EpisodeFile
{
RelativePath = "file1.S01E01.mkv"
},
new EpisodeFile
{
RelativePath = "file1.S01E02.mkv"
}
}
};
Subject.Definition = new NotificationDefinition
{
Settings = new SynologyIndexerSettings
{
UpdateLibrary = true
}
};
}
[Test]
public void should_not_update_library_if_disabled()
{
(Subject.Definition.Settings as SynologyIndexerSettings).UpdateLibrary = false;
Subject.AfterRename(_series);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.UpdateFolder(_series.Path), Times.Never());
}
[Test]
public void should_remove_old_episodes_on_upgrade()
{
Subject.OnDownload(_upgrade);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E01.mkv".AsOsAgnostic()), Times.Once());
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E02.mkv".AsOsAgnostic()), Times.Once());
}
[Test]
public void should_add_new_episode_on_upgrade()
{
Subject.OnDownload(_upgrade);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.AddFile(@"C:\Test\file1.S01E01E02.mkv".AsOsAgnostic()), Times.Once());
}
[Test]
public void should_update_entire_series_folder_on_rename()
{
Subject.AfterRename(_series);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.UpdateFolder(@"C:\Test\".AsOsAgnostic()), Times.Once());
}
}
}

@ -241,6 +241,7 @@
<Compile Include="MetadataSourceTests\TvdbDataProxyFixture.cs" />
<Compile Include="MetadataSourceTests\SearchSeriesComparerFixture.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxyFixture.cs" />
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\EpisodeTitleCollapseFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\MultiEpisodeFixture.cs" />

@ -0,0 +1,15 @@
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Notifications.Synology
{
public class SynologyException : NzbDroneException
{
public SynologyException(string message) : base(message)
{
}
public SynologyException(string message, params object[] args) : base(message, args)
{
}
}
}

@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.IO;
using FluentValidation.Results;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Synology
{
public class SynologyIndexer : NotificationBase<SynologyIndexerSettings>
{
private readonly ISynologyIndexerProxy _indexerProxy;
public SynologyIndexer(ISynologyIndexerProxy indexerProxy)
{
_indexerProxy = indexerProxy;
}
public override string Link
{
get { return "http://www.synology.com"; }
}
public override void OnGrab(string message)
{
}
public override void OnDownload(DownloadMessage message)
{
if (Settings.UpdateLibrary)
{
foreach (var oldFile in message.OldFiles)
{
var fullPath = Path.Combine(message.Series.Path, oldFile.RelativePath);
_indexerProxy.DeleteFile(fullPath);
}
{
var fullPath = Path.Combine(message.Series.Path, message.EpisodeFile.RelativePath);
_indexerProxy.AddFile(fullPath);
}
}
}
public override void AfterRename(Series series)
{
if (Settings.UpdateLibrary)
{
_indexerProxy.UpdateFolder(series.Path);
}
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(TestConnection());
return new ValidationResult(failures);
}
protected virtual ValidationFailure TestConnection()
{
if (!OsInfo.IsLinux)
{
return new ValidationFailure(null, "Must be a Synology");
}
if (!_indexerProxy.Test())
{
return new ValidationFailure(null, "Not a Synology or synoindex not available");
}
return null;
}
}
}

@ -0,0 +1,96 @@
using System;
using System.Linq;
using NLog;
using NzbDrone.Common.Processes;
namespace NzbDrone.Core.Notifications.Synology
{
public interface ISynologyIndexerProxy
{
bool Test();
void AddFile(string filepath);
void DeleteFile(string filepath);
void AddFolder(string folderpath);
void DeleteFolder(string folderpath);
void UpdateFolder(string folderpath);
void UpdateLibrary();
}
public class SynologyIndexerProxy : ISynologyIndexerProxy
{
private const string SynoIndexPath = "/usr/syno/bin/synoindex";
private readonly IProcessProvider _processProvider;
private readonly Logger _logger;
public SynologyIndexerProxy(IProcessProvider processProvider, Logger logger)
{
_processProvider = processProvider;
_logger = logger;
}
public bool Test()
{
try
{
ExecuteCommand("--help", false);
return true;
}
catch (Exception ex)
{
_logger.WarnException("synoindex not available", ex);
return false;
}
}
public void AddFile(string filePath)
{
ExecuteCommand("-a " + Escape(filePath));
}
public void DeleteFile(string filePath)
{
ExecuteCommand("-d " + Escape(filePath));
}
public void AddFolder(string folderPath)
{
ExecuteCommand("-A " + Escape(folderPath));
}
public void DeleteFolder(string folderPath)
{
ExecuteCommand("-D " + Escape(folderPath));
}
public void UpdateFolder(string folderPath)
{
ExecuteCommand("-R " + Escape(folderPath));
}
public void UpdateLibrary()
{
ExecuteCommand("-R video");
}
private void ExecuteCommand(string args, bool throwOnStdOut = true)
{
var output = _processProvider.StartAndCapture(SynoIndexPath, args);
if (output.Standard.Count != 0 && throwOnStdOut)
{
throw new SynologyException("synoindex returned an error: {0}", string.Join("\n", output.Standard));
}
if (output.Error.Count != 0)
{
throw new SynologyException("synoindex returned an error: {0}", string.Join("\n", output.Error));
}
}
private string Escape(string arg)
{
return string.Format("\"{0}\"", arg.Replace("\"", "\\\""));
}
}
}

@ -0,0 +1,35 @@
using System;
using FluentValidation;
using FluentValidation.Results;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Synology
{
public class SynologyIndexerSettingsValidator : AbstractValidator<SynologyIndexerSettings>
{
public SynologyIndexerSettingsValidator()
{
}
}
public class SynologyIndexerSettings : IProviderConfig
{
private static readonly SynologyIndexerSettingsValidator Validator = new SynologyIndexerSettingsValidator();
public SynologyIndexerSettings()
{
UpdateLibrary = true;
}
[FieldDefinition(0, Label = "Update Library", Type = FieldType.Checkbox, HelpText = "Call synoindex on localhost to update a library file")]
public Boolean UpdateLibrary { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -665,6 +665,10 @@
<Compile Include="Metadata\MetadataType.cs" />
<Compile Include="MetadataSource\IProvideSeriesInfo.cs" />
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
<Compile Include="Notifications\Synology\SynologyException.cs" />
<Compile Include="Notifications\Synology\SynologyIndexer.cs" />
<Compile Include="Notifications\Synology\SynologyIndexerProxy.cs" />
<Compile Include="Notifications\Synology\SynologyIndexerSettings.cs" />
<Compile Include="Profiles\Delay\DelayProfile.cs" />
<Compile Include="Profiles\Delay\DelayProfileService.cs" />
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />

Loading…
Cancel
Save