mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-05 02:22:31 +01:00
New: Synology Media Indexer support in Connect.
This commit is contained in:
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
80
src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs
Normal file
80
src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs
Normal file
@ -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…
Reference in New Issue
Block a user