Download clients now use thingy provider
This commit is contained in:
parent
ba22600412
commit
606d78f5e1
|
@ -0,0 +1,18 @@
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.DownloadClient
|
||||||
|
{
|
||||||
|
public class DownloadClientModule : ProviderModuleBase<DownloadClientResource, IDownloadClient, DownloadClientDefinition>
|
||||||
|
{
|
||||||
|
public DownloadClientModule(IDownloadClientFactory downloadClientFactory)
|
||||||
|
: base(downloadClientFactory, "downloadclient")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Validate(DownloadClientDefinition definition)
|
||||||
|
{
|
||||||
|
if (!definition.Enable) return;
|
||||||
|
base.Validate(definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.DownloadClient
|
||||||
|
{
|
||||||
|
public class DownloadClientResource : ProviderResource
|
||||||
|
{
|
||||||
|
public Boolean Enable { get; set; }
|
||||||
|
public Int32 Protocol { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Api.ClientSchema;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.DownloadClient
|
||||||
|
{
|
||||||
|
public class DownloadClientSchemaModule : NzbDroneRestModule<DownloadClientResource>
|
||||||
|
{
|
||||||
|
private readonly IDownloadClientFactory _notificationFactory;
|
||||||
|
|
||||||
|
public DownloadClientSchemaModule(IDownloadClientFactory notificationFactory)
|
||||||
|
: base("downloadclient/schema")
|
||||||
|
{
|
||||||
|
_notificationFactory = notificationFactory;
|
||||||
|
GetResourceAll = GetSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DownloadClientResource> GetSchema()
|
||||||
|
{
|
||||||
|
var notifications = _notificationFactory.Templates();
|
||||||
|
|
||||||
|
var result = new List<DownloadClientResource>(notifications.Count);
|
||||||
|
|
||||||
|
foreach (var notification in notifications)
|
||||||
|
{
|
||||||
|
var notificationResource = new DownloadClientResource();
|
||||||
|
notificationResource.InjectFrom(notification);
|
||||||
|
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
|
||||||
|
|
||||||
|
result.Add(notificationResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,6 +94,8 @@
|
||||||
<Compile Include="Commands\CommandResource.cs" />
|
<Compile Include="Commands\CommandResource.cs" />
|
||||||
<Compile Include="Config\NamingConfigResource.cs" />
|
<Compile Include="Config\NamingConfigResource.cs" />
|
||||||
<Compile Include="Config\NamingModule.cs" />
|
<Compile Include="Config\NamingModule.cs" />
|
||||||
|
<Compile Include="DownloadClient\DownloadClientModule.cs" />
|
||||||
|
<Compile Include="DownloadClient\DownloadClientResource.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpaceModule.cs" />
|
<Compile Include="DiskSpace\DiskSpaceModule.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpaceResource.cs" />
|
<Compile Include="DiskSpace\DiskSpaceResource.cs" />
|
||||||
<Compile Include="EpisodeFiles\EpisodeFileModule.cs" />
|
<Compile Include="EpisodeFiles\EpisodeFileModule.cs" />
|
||||||
|
@ -122,6 +124,7 @@
|
||||||
<Compile Include="History\HistoryModule.cs" />
|
<Compile Include="History\HistoryModule.cs" />
|
||||||
<Compile Include="Metadata\MetadataResource.cs" />
|
<Compile Include="Metadata\MetadataResource.cs" />
|
||||||
<Compile Include="Metadata\MetadataModule.cs" />
|
<Compile Include="Metadata\MetadataModule.cs" />
|
||||||
|
<Compile Include="Notifications\NotificationSchemaModule.cs" />
|
||||||
<Compile Include="ProviderResource.cs" />
|
<Compile Include="ProviderResource.cs" />
|
||||||
<Compile Include="ProviderModuleBase.cs" />
|
<Compile Include="ProviderModuleBase.cs" />
|
||||||
<Compile Include="Indexers\IndexerSchemaModule.cs" />
|
<Compile Include="Indexers\IndexerSchemaModule.cs" />
|
||||||
|
@ -145,7 +148,7 @@
|
||||||
<Compile Include="Queue\QueueModule.cs" />
|
<Compile Include="Queue\QueueModule.cs" />
|
||||||
<Compile Include="Queue\QueueResource.cs" />
|
<Compile Include="Queue\QueueResource.cs" />
|
||||||
<Compile Include="ResourceChangeMessage.cs" />
|
<Compile Include="ResourceChangeMessage.cs" />
|
||||||
<Compile Include="Notifications\NotificationSchemaModule.cs" />
|
<Compile Include="DownloadClient\DownloadClientSchemaModule.cs" />
|
||||||
<Compile Include="Notifications\NotificationModule.cs" />
|
<Compile Include="Notifications\NotificationModule.cs" />
|
||||||
<Compile Include="Notifications\NotificationResource.cs" />
|
<Compile Include="Notifications\NotificationResource.cs" />
|
||||||
<Compile Include="NzbDroneRestModule.cs" />
|
<Compile Include="NzbDroneRestModule.cs" />
|
||||||
|
|
|
@ -105,16 +105,6 @@ namespace NzbDrone.Core.Test.Configuration
|
||||||
Subject.GetValue(key, value2).Should().Be(value2);
|
Subject.GetValue(key, value2).Should().Be(value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void updating_a_vakye_should_update_its_value()
|
|
||||||
{
|
|
||||||
Subject.SabHost = "Test";
|
|
||||||
Subject.SabHost.Should().Be("Test");
|
|
||||||
|
|
||||||
Subject.SabHost = "Test2";
|
|
||||||
Subject.SabHost.Should().Be("Test2");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[Description("This test will use reflection to ensure each config property read/writes to a unique key")]
|
[Description("This test will use reflection to ensure each config property read/writes to a unique key")]
|
||||||
public void config_properties_should_write_and_read_using_same_key()
|
public void config_properties_should_write_and_read_using_same_key()
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
private void GivenSabnzbdDownloadClient()
|
private void GivenSabnzbdDownloadClient()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(c => c.GetDownloadClient()).Returns(Mocker.Resolve<SabnzbdClient>());
|
.Setup(c => c.GetDownloadClient()).Returns(Mocker.Resolve<Sabnzbd>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenMostRecentForEpisode(HistoryEventType eventType)
|
private void GivenMostRecentForEpisode(HistoryEventType eventType)
|
||||||
|
|
|
@ -56,9 +56,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClient())
|
.Setup(s => s.GetDownloadClient())
|
||||||
.Returns(_downloadClient.Object);
|
.Returns(_downloadClient.Object);
|
||||||
|
|
||||||
_downloadClient.SetupGet(s => s.IsConfigured)
|
|
||||||
.Returns(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenEmptyQueue()
|
private void GivenEmptyQueue()
|
||||||
|
|
|
@ -4,8 +4,9 @@ using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
|
using NzbDrone.Core.Download.Clients.Blackhole;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
|
@ -13,7 +14,7 @@ using NzbDrone.Test.Common;
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BlackholeProviderFixture : CoreTest<BlackholeProvider>
|
public class BlackholeProviderFixture : CoreTest<Blackhole>
|
||||||
{
|
{
|
||||||
private const string _nzbUrl = "http://www.nzbs.com/url";
|
private const string _nzbUrl = "http://www.nzbs.com/url";
|
||||||
private const string _title = "some_nzb_title";
|
private const string _title = "some_nzb_title";
|
||||||
|
@ -27,13 +28,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||||
_blackHoleFolder = @"c:\nzb\blackhole\".AsOsAgnostic();
|
_blackHoleFolder = @"c:\nzb\blackhole\".AsOsAgnostic();
|
||||||
_nzbPath = @"c:\nzb\blackhole\some_nzb_title.nzb".AsOsAgnostic();
|
_nzbPath = @"c:\nzb\blackhole\some_nzb_title.nzb".AsOsAgnostic();
|
||||||
|
|
||||||
|
|
||||||
Mocker.GetMock<IConfigService>().SetupGet(c => c.BlackholeFolder).Returns(_blackHoleFolder);
|
|
||||||
|
|
||||||
_remoteEpisode = new RemoteEpisode();
|
_remoteEpisode = new RemoteEpisode();
|
||||||
_remoteEpisode.Release = new ReleaseInfo();
|
_remoteEpisode.Release = new ReleaseInfo();
|
||||||
_remoteEpisode.Release.Title = _title;
|
_remoteEpisode.Release.Title = _title;
|
||||||
_remoteEpisode.Release.DownloadUrl = _nzbUrl;
|
_remoteEpisode.Release.DownloadUrl = _nzbUrl;
|
||||||
|
|
||||||
|
Subject.Definition = new DownloadClientDefinition();
|
||||||
|
Subject.Definition.Settings = new FolderSettings
|
||||||
|
{
|
||||||
|
Folder = _blackHoleFolder
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithExistingFile()
|
private void WithExistingFile()
|
||||||
|
|
|
@ -3,17 +3,15 @@ using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
|
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||||
{
|
{
|
||||||
public class DownloadNzbFixture : CoreTest
|
public class DownloadNzbFixture : CoreTest<Nzbget>
|
||||||
{
|
{
|
||||||
private const string _url = "http://www.nzbdrone.com";
|
private const string _url = "http://www.nzbdrone.com";
|
||||||
private const string _title = "30.Rock.S01E01.Pilot.720p.hdtv";
|
private const string _title = "30.Rock.S01E01.Pilot.720p.hdtv";
|
||||||
|
@ -32,6 +30,17 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
|
||||||
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
||||||
.Build()
|
.Build()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
Subject.Definition = new DownloadClientDefinition();
|
||||||
|
Subject.Definition.Settings = new NzbgetSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 6789,
|
||||||
|
Username = "nzbget",
|
||||||
|
Password = "pass",
|
||||||
|
TvCategory = "tv",
|
||||||
|
RecentTvPriority = (int)NzbgetPriority.High
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -39,14 +48,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
|
||||||
{
|
{
|
||||||
var p = new object[] {"30.Rock.S01E01.Pilot.720p.hdtv.nzb", "TV", 50, false, "http://www.nzbdrone.com"};
|
var p = new object[] {"30.Rock.S01E01.Pilot.720p.hdtv.nzb", "TV", 50, false, "http://www.nzbdrone.com"};
|
||||||
|
|
||||||
Mocker.GetMock<INzbGetCommunicationProxy>()
|
Mocker.GetMock<INzbgetProxy>()
|
||||||
.Setup(s => s.AddNzb(p))
|
.Setup(s => s.AddNzb(It.IsAny<NzbgetSettings>(), p))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
Mocker.Resolve<NzbgetClient>().DownloadNzb(_remoteEpisode);
|
Subject.DownloadNzb(_remoteEpisode);
|
||||||
|
|
||||||
Mocker.GetMock<INzbGetCommunicationProxy>()
|
Mocker.GetMock<INzbgetProxy>()
|
||||||
.Verify(v => v.AddNzb(It.IsAny<object []>()), Times.Once());
|
.Verify(v => v.AddNzb(It.IsAny<NzbgetSettings>(), It.IsAny<object []>()), Times.Once());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,40 +5,52 @@ using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
|
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||||
{
|
{
|
||||||
public class QueueFixture : CoreTest<NzbgetClient>
|
public class QueueFixture : CoreTest<Nzbget>
|
||||||
{
|
{
|
||||||
private List<NzbGetQueueItem> _queue;
|
private List<NzbgetQueueItem> _queue;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
_queue = Builder<NzbGetQueueItem>.CreateListOfSize(5)
|
_queue = Builder<NzbgetQueueItem>.CreateListOfSize(5)
|
||||||
.All()
|
.All()
|
||||||
.With(q => q.NzbName = "30.Rock.S01E01.Pilot.720p.hdtv.nzb")
|
.With(q => q.NzbName = "30.Rock.S01E01.Pilot.720p.hdtv.nzb")
|
||||||
.Build()
|
.Build()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
Subject.Definition = new DownloadClientDefinition();
|
||||||
|
Subject.Definition.Settings = new NzbgetSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 6789,
|
||||||
|
Username = "nzbget",
|
||||||
|
Password = "pass",
|
||||||
|
TvCategory = "tv",
|
||||||
|
RecentTvPriority = (int)NzbgetPriority.High
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithFullQueue()
|
private void WithFullQueue()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<INzbGetCommunicationProxy>()
|
Mocker.GetMock<INzbgetProxy>()
|
||||||
.Setup(s => s.GetQueue())
|
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
|
||||||
.Returns(_queue);
|
.Returns(_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithEmptyQueue()
|
private void WithEmptyQueue()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<INzbGetCommunicationProxy>()
|
Mocker.GetMock<INzbgetProxy>()
|
||||||
.Setup(s => s.GetQueue())
|
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
|
||||||
.Returns(new List<NzbGetQueueItem>());
|
.Returns(new List<NzbgetQueueItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
|
@ -6,7 +6,9 @@ using NUnit.Framework;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
|
using NzbDrone.Core.Download.Clients.Pneumatic;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
|
@ -14,7 +16,7 @@ using NzbDrone.Test.Common;
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PneumaticProviderFixture : CoreTest<PneumaticClient>
|
public class PneumaticProviderFixture : CoreTest<Pneumatic>
|
||||||
{
|
{
|
||||||
private const string _nzbUrl = "http://www.nzbs.com/url";
|
private const string _nzbUrl = "http://www.nzbs.com/url";
|
||||||
private const string _title = "30.Rock.S01E05.hdtv.xvid-LoL";
|
private const string _title = "30.Rock.S01E05.hdtv.xvid-LoL";
|
||||||
|
@ -31,7 +33,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||||
_nzbPath = Path.Combine(_pneumaticFolder, _title + ".nzb").AsOsAgnostic();
|
_nzbPath = Path.Combine(_pneumaticFolder, _title + ".nzb").AsOsAgnostic();
|
||||||
_sabDrop = @"d:\unsorted tv\".AsOsAgnostic();
|
_sabDrop = @"d:\unsorted tv\".AsOsAgnostic();
|
||||||
|
|
||||||
Mocker.GetMock<IConfigService>().SetupGet(c => c.PneumaticFolder).Returns(_pneumaticFolder);
|
|
||||||
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop);
|
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop);
|
||||||
|
|
||||||
_remoteEpisode = new RemoteEpisode();
|
_remoteEpisode = new RemoteEpisode();
|
||||||
|
@ -41,6 +42,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||||
|
|
||||||
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo();
|
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo();
|
||||||
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
|
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
|
||||||
|
|
||||||
|
Subject.Definition = new DownloadClientDefinition();
|
||||||
|
Subject.Definition.Settings = new FolderSettings
|
||||||
|
{
|
||||||
|
Folder = _pneumaticFolder
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithExistingFile()
|
private void WithExistingFile()
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using FizzWare.NBuilder;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
|
|
||||||
public class SabProviderFixture : CoreTest<SabnzbdClient>
|
|
||||||
{
|
|
||||||
private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232";
|
|
||||||
private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]";
|
|
||||||
private RemoteEpisode _remoteEpisode;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
var fakeConfig = Mocker.GetMock<IConfigService>();
|
|
||||||
|
|
||||||
fakeConfig.SetupGet(c => c.SabHost).Returns("192.168.5.55");
|
|
||||||
fakeConfig.SetupGet(c => c.SabPort).Returns(2222);
|
|
||||||
fakeConfig.SetupGet(c => c.SabApiKey).Returns("5c770e3197e4fe763423ee7c392c25d1");
|
|
||||||
fakeConfig.SetupGet(c => c.SabUsername).Returns("admin");
|
|
||||||
fakeConfig.SetupGet(c => c.SabPassword).Returns("pass");
|
|
||||||
fakeConfig.SetupGet(c => c.SabTvCategory).Returns("tv");
|
|
||||||
|
|
||||||
_remoteEpisode = new RemoteEpisode();
|
|
||||||
_remoteEpisode.Release = new ReleaseInfo();
|
|
||||||
_remoteEpisode.Release.Title = TITLE;
|
|
||||||
_remoteEpisode.Release.DownloadUrl = URL;
|
|
||||||
|
|
||||||
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
|
||||||
.Build()
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_able_to_get_categories_when_config_is_passed_in()
|
|
||||||
{
|
|
||||||
|
|
||||||
const string host = "192.168.5.22";
|
|
||||||
const int port = 1111;
|
|
||||||
const string apikey = "5c770e3197e4fe763423ee7c392c25d2";
|
|
||||||
const string username = "admin2";
|
|
||||||
const string password = "pass2";
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>(MockBehavior.Strict)
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.22:1111/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d2&ma_username=admin2&ma_password=pass2"))
|
|
||||||
.Returns(ReadAllText("Files", "Categories_json.txt"));
|
|
||||||
|
|
||||||
var result = Subject.GetCategories(host, port, apikey, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().NotBeNull();
|
|
||||||
result.categories.Should().NotBeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_able_to_get_categories_using_config()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHttpProvider>(MockBehavior.Strict)
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(ReadAllText("Files", "Categories_json.txt"));
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.GetCategories();
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().NotBeNull();
|
|
||||||
result.categories.Should().NotBeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetHistory_should_return_a_list_with_items_when_the_history_has_items()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(ReadAllText("Files", "History.txt"));
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.GetHistory();
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetHistory_should_return_an_empty_list_when_the_queue_is_empty()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(ReadAllText("Files", "HistoryEmpty.txt"));
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.GetHistory();
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetHistory_should_return_an_empty_list_when_there_is_an_error_getting_the_queue()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(ReadAllText("Files", "JsonError.txt"));
|
|
||||||
|
|
||||||
|
|
||||||
Assert.Throws<ApplicationException>(() => Subject.GetHistory(), "API Key Incorrect");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetVersion_should_return_the_version_using_passed_in_values()
|
|
||||||
{
|
|
||||||
var response = "{ \"version\": \"0.6.9\" }";
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(response);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().NotBeNull();
|
|
||||||
result.Version.Should().Be("0.6.9");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetVersion_should_return_the_version_using_saved_values()
|
|
||||||
{
|
|
||||||
var response = "{ \"version\": \"0.6.9\" }";
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(response);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.GetVersion();
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().NotBeNull();
|
|
||||||
result.Version.Should().Be("0.6.9");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Test_should_return_version_as_a_string()
|
|
||||||
{
|
|
||||||
const string response = "{ \"version\": \"0.6.9\" }";
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>()
|
|
||||||
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
|
||||||
.Returns(response);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Subject.Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().Be("0.6.9");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IConfigService>()
|
|
||||||
.SetupGet(s => s.SabRecentTvPriority)
|
|
||||||
.Returns(SabPriorityType.High);
|
|
||||||
|
|
||||||
Mocker.GetMock<ISabCommunicationProxy>()
|
|
||||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabPriorityType.High))
|
|
||||||
.Returns(new SabAddResponse());
|
|
||||||
|
|
||||||
Subject.DownloadNzb(_remoteEpisode);
|
|
||||||
|
|
||||||
Mocker.GetMock<ISabCommunicationProxy>()
|
|
||||||
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabPriorityType.High), Times.Once());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
||||||
|
using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class SabnzbdFixture : CoreTest<Sabnzbd>
|
||||||
|
{
|
||||||
|
private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232";
|
||||||
|
private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]";
|
||||||
|
private RemoteEpisode _remoteEpisode;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_remoteEpisode = new RemoteEpisode();
|
||||||
|
_remoteEpisode.Release = new ReleaseInfo();
|
||||||
|
_remoteEpisode.Release.Title = TITLE;
|
||||||
|
_remoteEpisode.Release.DownloadUrl = URL;
|
||||||
|
|
||||||
|
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
||||||
|
.Build()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Subject.Definition = new DownloadClientDefinition();
|
||||||
|
Subject.Definition.Settings = new SabnzbdSettings
|
||||||
|
{
|
||||||
|
Host = "192.168.5.55",
|
||||||
|
Port = 2222,
|
||||||
|
ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
|
||||||
|
Username = "admin",
|
||||||
|
Password = "pass",
|
||||||
|
TvCategory = "tv",
|
||||||
|
RecentTvPriority = (int)SabnzbdPriority.High
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetHistory_should_return_a_list_with_items_when_the_history_has_items()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
||||||
|
.Returns(ReadAllText("Files", "History.txt"));
|
||||||
|
|
||||||
|
|
||||||
|
var result = Subject.GetHistory();
|
||||||
|
|
||||||
|
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetHistory_should_return_an_empty_list_when_the_queue_is_empty()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
||||||
|
.Returns(ReadAllText("Files", "HistoryEmpty.txt"));
|
||||||
|
|
||||||
|
|
||||||
|
var result = Subject.GetHistory();
|
||||||
|
|
||||||
|
|
||||||
|
result.Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetHistory_should_return_an_empty_list_when_there_is_an_error_getting_the_queue()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
|
||||||
|
.Returns(ReadAllText("Files", "JsonError.txt"));
|
||||||
|
|
||||||
|
|
||||||
|
Assert.Throws<ApplicationException>(() => Subject.GetHistory(), "API Key Incorrect");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<ISabnzbdProxy>()
|
||||||
|
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()))
|
||||||
|
.Returns(new SabnzbdAddResponse());
|
||||||
|
|
||||||
|
Subject.DownloadNzb(_remoteEpisode);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISabnzbdProxy>()
|
||||||
|
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
|
@ -33,9 +34,6 @@ namespace NzbDrone.Core.Test.Download
|
||||||
.With(c => c.Release = Builder<ReleaseInfo>.CreateNew().Build())
|
.With(c => c.Release = Builder<ReleaseInfo>.CreateNew().Build())
|
||||||
.With(c => c.Episodes = episodes)
|
.With(c => c.Episodes = episodes)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
Mocker.GetMock<IDownloadClient>().Setup(c => c.IsConfigured).Returns(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithSuccessfulAdd()
|
private void WithSuccessfulAdd()
|
||||||
|
@ -85,7 +83,8 @@ namespace NzbDrone.Core.Test.Download
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_attempt_download_if_client_isnt_configure()
|
public void should_not_attempt_download_if_client_isnt_configure()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IDownloadClient>().Setup(c => c.IsConfigured).Returns(false);
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
|
.Setup(c => c.GetDownloadClient()).Returns((IDownloadClient)null);
|
||||||
|
|
||||||
Subject.DownloadReport(_parseResult);
|
Subject.DownloadReport(_parseResult);
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"categories":[
|
|
||||||
"*",
|
|
||||||
"anime",
|
|
||||||
"apps",
|
|
||||||
"books",
|
|
||||||
"consoles",
|
|
||||||
"ds-games",
|
|
||||||
"emulation",
|
|
||||||
"games",
|
|
||||||
"misc",
|
|
||||||
"movies",
|
|
||||||
"music",
|
|
||||||
"pda",
|
|
||||||
"resources",
|
|
||||||
"test",
|
|
||||||
"tv",
|
|
||||||
"tv-dvd",
|
|
||||||
"unknown",
|
|
||||||
"wii-games",
|
|
||||||
"xbox-dlc",
|
|
||||||
"xbox-xbla",
|
|
||||||
"xxx"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -122,10 +122,10 @@
|
||||||
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
||||||
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" />
|
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\DownloadNzbFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\NzbgetTests\DownloadNzbFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\QueueFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\NzbgetTests\QueueFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\PneumaticProviderFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\PneumaticProviderFixture.cs" />
|
||||||
<Compile Include="Download\DownloadClientTests\SabProviderTests\SabProviderFixture.cs" />
|
<Compile Include="Download\DownloadClientTests\SabnzbdTests\SabnzbdFixture.cs" />
|
||||||
<Compile Include="Download\DownloadServiceFixture.cs" />
|
<Compile Include="Download\DownloadServiceFixture.cs" />
|
||||||
<Compile Include="Download\FailedDownloadServiceFixture.cs" />
|
<Compile Include="Download\FailedDownloadServiceFixture.cs" />
|
||||||
<Compile Include="Framework\CoreTest.cs" />
|
<Compile Include="Framework\CoreTest.cs" />
|
||||||
|
@ -330,9 +330,6 @@
|
||||||
<Content Include="Files\RSS\newznab.xml">
|
<Content Include="Files\RSS\newznab.xml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="Files\Categories_json.txt">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="Files\RSS\SizeParsing\newznab.xml">
|
<Content Include="Files\RSS\SizeParsing\newznab.xml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Core.Annotations
|
||||||
Textbox,
|
Textbox,
|
||||||
Password,
|
Password,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Select
|
Select,
|
||||||
|
Path
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -73,69 +73,6 @@ namespace NzbDrone.Core.Configuration
|
||||||
_eventAggregator.PublishEvent(new ConfigSavedEvent());
|
_eventAggregator.PublishEvent(new ConfigSavedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String SabHost
|
|
||||||
{
|
|
||||||
get { return GetValue("SabHost", "localhost"); }
|
|
||||||
|
|
||||||
set { SetValue("SabHost", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SabPort
|
|
||||||
{
|
|
||||||
get { return GetValueInt("SabPort", 8080); }
|
|
||||||
|
|
||||||
set { SetValue("SabPort", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String SabApiKey
|
|
||||||
{
|
|
||||||
get { return GetValue("SabApiKey"); }
|
|
||||||
|
|
||||||
set { SetValue("SabApiKey", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String SabUsername
|
|
||||||
{
|
|
||||||
get { return GetValue("SabUsername"); }
|
|
||||||
|
|
||||||
set { SetValue("SabUsername", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String SabPassword
|
|
||||||
{
|
|
||||||
get { return GetValue("SabPassword"); }
|
|
||||||
|
|
||||||
set { SetValue("SabPassword", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String SabTvCategory
|
|
||||||
{
|
|
||||||
get { return GetValue("SabTvCategory", "tv"); }
|
|
||||||
|
|
||||||
set { SetValue("SabTvCategory", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public SabPriorityType SabRecentTvPriority
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("SabRecentTvPriority", SabPriorityType.Default); }
|
|
||||||
|
|
||||||
set { SetValue("SabRecentTvPriority", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public SabPriorityType SabOlderTvPriority
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("SabOlderTvPriority", SabPriorityType.Default); }
|
|
||||||
|
|
||||||
set { SetValue("SabOlderTvPriority", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SabUseSsl
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("SabUseSsl", false); }
|
|
||||||
|
|
||||||
set { SetValue("SabUseSsl", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String DownloadedEpisodesFolder
|
public String DownloadedEpisodesFolder
|
||||||
{
|
{
|
||||||
get { return GetValue(ConfigKey.DownloadedEpisodesFolder.ToString()); }
|
get { return GetValue(ConfigKey.DownloadedEpisodesFolder.ToString()); }
|
||||||
|
@ -155,80 +92,12 @@ namespace NzbDrone.Core.Configuration
|
||||||
set { SetValue("Retention", value); }
|
set { SetValue("Retention", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadClientType DownloadClient
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("DownloadClient", DownloadClientType.Blackhole); }
|
|
||||||
|
|
||||||
set { SetValue("DownloadClient", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BlackholeFolder
|
|
||||||
{
|
|
||||||
get { return GetValue("BlackholeFolder", String.Empty); }
|
|
||||||
set { SetValue("BlackholeFolder", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PneumaticFolder
|
|
||||||
{
|
|
||||||
get { return GetValue("PneumaticFolder", String.Empty); }
|
|
||||||
set { SetValue("PneumaticFolder", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RecycleBin
|
public string RecycleBin
|
||||||
{
|
{
|
||||||
get { return GetValue("RecycleBin", String.Empty); }
|
get { return GetValue("RecycleBin", String.Empty); }
|
||||||
set { SetValue("RecycleBin", value); }
|
set { SetValue("RecycleBin", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public String NzbgetUsername
|
|
||||||
{
|
|
||||||
get { return GetValue("NzbgetUsername", "nzbget"); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetUsername", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String NzbgetPassword
|
|
||||||
{
|
|
||||||
get { return GetValue("NzbgetPassword", ""); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetPassword", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String NzbgetHost
|
|
||||||
{
|
|
||||||
get { return GetValue("NzbgetHost", "localhost"); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetHost", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Int32 NzbgetPort
|
|
||||||
{
|
|
||||||
get { return GetValueInt("NzbgetPort", 6789); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetPort", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public String NzbgetTvCategory
|
|
||||||
{
|
|
||||||
get { return GetValue("NzbgetTvCategory", ""); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetTvCategory", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public PriorityType NzbgetRecentTvPriority
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("NzbgetRecentTvPriority", PriorityType.Normal); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetRecentTvPriority", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public PriorityType NzbgetOlderTvPriority
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("NzbgetOlderTvPriority", PriorityType.Normal); }
|
|
||||||
|
|
||||||
set { SetValue("NzbgetOlderTvPriority", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ReleaseRestrictions
|
public string ReleaseRestrictions
|
||||||
{
|
{
|
||||||
get { return GetValue("ReleaseRestrictions", String.Empty).Trim('\r', '\n'); }
|
get { return GetValue("ReleaseRestrictions", String.Empty).Trim('\r', '\n'); }
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
|
||||||
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Configuration
|
namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
|
@ -10,29 +7,10 @@ namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
IEnumerable<Config> All();
|
IEnumerable<Config> All();
|
||||||
Dictionary<String, Object> AllWithDefaults();
|
Dictionary<String, Object> AllWithDefaults();
|
||||||
String SabHost { get; set; }
|
|
||||||
int SabPort { get; set; }
|
|
||||||
String SabApiKey { get; set; }
|
|
||||||
String SabUsername { get; set; }
|
|
||||||
String SabPassword { get; set; }
|
|
||||||
String SabTvCategory { get; set; }
|
|
||||||
SabPriorityType SabRecentTvPriority { get; set; }
|
|
||||||
SabPriorityType SabOlderTvPriority { get; set; }
|
|
||||||
Boolean SabUseSsl { get; set; }
|
|
||||||
String DownloadedEpisodesFolder { get; set; }
|
String DownloadedEpisodesFolder { get; set; }
|
||||||
bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
|
bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
|
||||||
int Retention { get; set; }
|
int Retention { get; set; }
|
||||||
DownloadClientType DownloadClient { get; set; }
|
|
||||||
string BlackholeFolder { get; set; }
|
|
||||||
string PneumaticFolder { get; set; }
|
|
||||||
string RecycleBin { get; set; }
|
string RecycleBin { get; set; }
|
||||||
String NzbgetUsername { get; set; }
|
|
||||||
String NzbgetPassword { get; set; }
|
|
||||||
String NzbgetHost { get; set; }
|
|
||||||
Int32 NzbgetPort { get; set; }
|
|
||||||
String NzbgetTvCategory { get; set; }
|
|
||||||
PriorityType NzbgetRecentTvPriority { get; set; }
|
|
||||||
PriorityType NzbgetOlderTvPriority { get; set; }
|
|
||||||
string ReleaseRestrictions { get; set; }
|
string ReleaseRestrictions { get; set; }
|
||||||
Int32 RssSyncInterval { get; set; }
|
Int32 RssSyncInterval { get; set; }
|
||||||
Boolean AutoDownloadPropers { get; set; }
|
Boolean AutoDownloadPropers { get; set; }
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(41)]
|
||||||
|
public class add_download_clients_table : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Create.TableForModel("DownloadClients")
|
||||||
|
.WithColumn("Enable").AsBoolean().NotNullable()
|
||||||
|
.WithColumn("Name").AsString().NotNullable()
|
||||||
|
.WithColumn("Implementation").AsString().NotNullable()
|
||||||
|
.WithColumn("Settings").AsString().NotNullable()
|
||||||
|
.WithColumn("ConfigContract").AsString().NotNullable()
|
||||||
|
.WithColumn("Protocol").AsInt32().NotNullable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(42)]
|
||||||
|
public class convert_config_to_download_clients : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Execute.WithConnection(ConvertToThingyProvder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConvertToThingyProvder(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
var config = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
using (IDbCommand configCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
configCmd.Transaction = tran;
|
||||||
|
configCmd.CommandText = @"SELECT * FROM Config";
|
||||||
|
using (IDataReader configReader = configCmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
var keyIndex = configReader.GetOrdinal("Key");
|
||||||
|
var valueIndex = configReader.GetOrdinal("Value");
|
||||||
|
|
||||||
|
while (configReader.Read())
|
||||||
|
{
|
||||||
|
var key = configReader.GetString(keyIndex);
|
||||||
|
var value = configReader.GetString(valueIndex);
|
||||||
|
|
||||||
|
config.Add(key.ToLowerInvariant(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = GetConfigValue(config, "DownloadClient", "");
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(client))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.Equals("sabnzbd", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var settings = new ClientSettingsForMigration
|
||||||
|
{
|
||||||
|
Host = GetConfigValue(config, "SabHost", "localhost"),
|
||||||
|
Port = GetConfigValue(config, "SabPort", 8080),
|
||||||
|
ApiKey = GetConfigValue(config, "SabApiKey", ""),
|
||||||
|
Username = GetConfigValue(config, "SabUsername", ""),
|
||||||
|
Password = GetConfigValue(config, "SabPassword", ""),
|
||||||
|
TvCategory = GetConfigValue(config, "SabTvCategory", "tv"),
|
||||||
|
RecentTvPriority = GetSabnzbdPriority(GetConfigValue(config, "NzbgetRecentTvPriority", "Default")),
|
||||||
|
OlderTvPriority = GetSabnzbdPriority(GetConfigValue(config, "NzbgetOlderTvPriority", "Default")),
|
||||||
|
UseSsl = GetConfigValue(config, "SabUseSsl", false)
|
||||||
|
};
|
||||||
|
|
||||||
|
AddDownloadClient(conn, tran, "Sabnzbd", "Sabnzbd", settings.ToJson(), "SabnzbdSettings", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (client.Equals("nzbget", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var settings = new ClientSettingsForMigration
|
||||||
|
{
|
||||||
|
Host = GetConfigValue(config, "NzbGetHost", "localhost"),
|
||||||
|
Port = GetConfigValue(config, "NzbgetPort", 6789),
|
||||||
|
Username = GetConfigValue(config, "NzbgetUsername", "nzbget"),
|
||||||
|
Password = GetConfigValue(config, "NzbgetPassword", ""),
|
||||||
|
TvCategory = GetConfigValue(config, "NzbgetTvCategory", "tv"),
|
||||||
|
RecentTvPriority = GetNzbgetPriority(GetConfigValue(config, "NzbgetRecentTvPriority", "Normal")),
|
||||||
|
OlderTvPriority = GetNzbgetPriority(GetConfigValue(config, "NzbgetOlderTvPriority", "Normal")),
|
||||||
|
};
|
||||||
|
|
||||||
|
AddDownloadClient(conn, tran, "Nzbget", "Nzbget", settings.ToJson(), "NzbgetSettings", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (client.Equals("pneumatic", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var settings = new FolderSettingsForMigration
|
||||||
|
{
|
||||||
|
Folder = GetConfigValue(config, "PneumaticFolder", "")
|
||||||
|
};
|
||||||
|
|
||||||
|
AddDownloadClient(conn, tran, "Pneumatic", "Pneumatic", settings.ToJson(), "FolderSettings", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (client.Equals("blackhole", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var settings = new FolderSettingsForMigration
|
||||||
|
{
|
||||||
|
Folder = GetConfigValue(config, "BlackholeFolder", "")
|
||||||
|
};
|
||||||
|
|
||||||
|
AddDownloadClient(conn, tran, "Blackhole", "Blackhole", settings.ToJson(), "FolderSettings", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteOldConfigValues(conn, tran);
|
||||||
|
}
|
||||||
|
|
||||||
|
private T GetConfigValue<T>(Dictionary<string, string> config, string key, T defaultValue)
|
||||||
|
{
|
||||||
|
key = key.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (config.ContainsKey(key))
|
||||||
|
{
|
||||||
|
return (T) Convert.ChangeType(config[key], typeof (T));
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDownloadClient(IDbConnection conn, IDbTransaction tran, string name, string implementation, string settings,
|
||||||
|
string configContract, int protocol)
|
||||||
|
{
|
||||||
|
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
var text = String.Format("INSERT INTO DownloadClients (Enable, Name, Implementation, Settings, ConfigContract, Protocol) VALUES (1, ?, ?, ?, ?, ?)");
|
||||||
|
updateCmd.AddParameter(name);
|
||||||
|
updateCmd.AddParameter(implementation);
|
||||||
|
updateCmd.AddParameter(settings);
|
||||||
|
updateCmd.AddParameter(configContract);
|
||||||
|
updateCmd.AddParameter(protocol);
|
||||||
|
|
||||||
|
updateCmd.Transaction = tran;
|
||||||
|
updateCmd.CommandText = text;
|
||||||
|
updateCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteOldConfigValues(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
var text = "DELETE FROM Config WHERE [KEY] IN ('nzbgetusername', 'nzbgetpassword', 'nzbgethost', 'nzbgetport', " +
|
||||||
|
"'nzbgettvcategory', 'nzbgetrecenttvpriority', 'nzbgetoldertvpriority', 'sabhost', 'sabport', " +
|
||||||
|
"'sabapikey', 'sabusername', 'sabpassword', 'sabtvcategory', 'sabrecenttvpriority', " +
|
||||||
|
"'saboldertvpriority', 'sabusessl', 'downloadclient', 'blackholefolder', 'pneumaticfolder')";
|
||||||
|
|
||||||
|
updateCmd.Transaction = tran;
|
||||||
|
updateCmd.CommandText = text;
|
||||||
|
updateCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetSabnzbdPriority(string priority)
|
||||||
|
{
|
||||||
|
return (int)Enum.Parse(typeof(SabnzbdPriorityForMigration), priority, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetNzbgetPriority(string priority)
|
||||||
|
{
|
||||||
|
return (int)Enum.Parse(typeof(NzbGetPriorityForMigration), priority, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClientSettingsForMigration
|
||||||
|
{
|
||||||
|
public String Host { get; set; }
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
public String ApiKey { get; set; }
|
||||||
|
public String Username { get; set; }
|
||||||
|
public String Password { get; set; }
|
||||||
|
public String TvCategory { get; set; }
|
||||||
|
public Int32 RecentTvPriority { get; set; }
|
||||||
|
public Int32 OlderTvPriority { get; set; }
|
||||||
|
public Boolean UseSsl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FolderSettingsForMigration
|
||||||
|
{
|
||||||
|
public String Folder { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SabnzbdPriorityForMigration
|
||||||
|
{
|
||||||
|
Default = -100,
|
||||||
|
Paused = -2,
|
||||||
|
Low = -1,
|
||||||
|
Normal = 0,
|
||||||
|
High = 1,
|
||||||
|
Force = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum NzbGetPriorityForMigration
|
||||||
|
{
|
||||||
|
VeryLow = -100,
|
||||||
|
Low = -50,
|
||||||
|
Normal = 0,
|
||||||
|
High = 50,
|
||||||
|
VeryHigh = 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ using NzbDrone.Core.Blacklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.DataAugmentation.Scene;
|
using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
using NzbDrone.Core.Datastore.Converters;
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Instrumentation;
|
using NzbDrone.Core.Instrumentation;
|
||||||
using NzbDrone.Core.Jobs;
|
using NzbDrone.Core.Jobs;
|
||||||
|
@ -39,6 +40,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
||||||
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
|
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
|
||||||
Mapper.Entity<MetadataDefinition>().RegisterModel("Metadata");
|
Mapper.Entity<MetadataDefinition>().RegisterModel("Metadata");
|
||||||
|
Mapper.Entity<DownloadClientDefinition>().RegisterModel("DownloadClients");
|
||||||
|
|
||||||
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");
|
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
{
|
{
|
||||||
|
@ -32,9 +31,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
{
|
{
|
||||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||||
|
|
||||||
if (!downloadClient.IsConfigured)
|
if (downloadClient == null)
|
||||||
{
|
{
|
||||||
_logger.Warn("Download client {0} isn't configured yet.", downloadClient.GetType().Name);
|
_logger.Warn("Download client isn't configured yet.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_downloadClientProvider.GetDownloadClient().GetType() == typeof (SabnzbdClient))
|
if (_downloadClientProvider.GetDownloadClient().GetType() == typeof (Sabnzbd))
|
||||||
{
|
{
|
||||||
_logger.Trace("Performing history status check on report");
|
_logger.Trace("Performing history status check on report");
|
||||||
foreach (var episode in subject.Episodes)
|
foreach (var episode in subject.Episodes)
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||||
|
{
|
||||||
|
public class Blackhole : DownloadClientBase<FolderSettings>, IExecute<TestBlackholeCommand>
|
||||||
|
{
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public Blackhole(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
|
||||||
|
{
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||||
|
{
|
||||||
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
var title = remoteEpisode.Release.Title;
|
||||||
|
|
||||||
|
title = FileNameBuilder.CleanFilename(title);
|
||||||
|
|
||||||
|
var filename = Path.Combine(Settings.Folder, title + ".nzb");
|
||||||
|
|
||||||
|
|
||||||
|
_logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
|
||||||
|
_httpProvider.DownloadFile(url, filename);
|
||||||
|
_logger.Trace("NZB Download succeeded, saved to: {0}", filename);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<QueueItem> GetQueue()
|
||||||
|
{
|
||||||
|
return new QueueItem[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
||||||
|
{
|
||||||
|
return new HistoryItem[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromQueue(string id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromHistory(string id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestBlackholeCommand message)
|
||||||
|
{
|
||||||
|
var testPath = Path.Combine(message.Folder, "drone_test.txt");
|
||||||
|
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
|
||||||
|
_diskProvider.DeleteFile(testPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||||
|
{
|
||||||
|
public class TestBlackholeCommand : Command
|
||||||
|
{
|
||||||
|
public override bool SendUpdatesToClient
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Folder { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Organizer;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients
|
|
||||||
{
|
|
||||||
public class BlackholeProvider : IDownloadClient
|
|
||||||
{
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly IHttpProvider _httpProvider;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
|
|
||||||
public BlackholeProvider(IConfigService configService, IHttpProvider httpProvider, Logger logger)
|
|
||||||
{
|
|
||||||
_configService = configService;
|
|
||||||
_httpProvider = httpProvider;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DownloadNzb(RemoteEpisode remoteEpisode)
|
|
||||||
{
|
|
||||||
var url = remoteEpisode.Release.DownloadUrl;
|
|
||||||
var title = remoteEpisode.Release.Title;
|
|
||||||
|
|
||||||
title = FileNameBuilder.CleanFilename(title);
|
|
||||||
|
|
||||||
var filename = Path.Combine(_configService.BlackholeFolder, title + ".nzb");
|
|
||||||
|
|
||||||
|
|
||||||
_logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
|
|
||||||
_httpProvider.DownloadFile(url, filename);
|
|
||||||
_logger.Trace("NZB Download succeeded, saved to: {0}", filename);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsConfigured
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !string.IsNullOrWhiteSpace(_configService.BlackholeFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<QueueItem> GetQueue()
|
|
||||||
{
|
|
||||||
return new QueueItem[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
|
||||||
{
|
|
||||||
return new HistoryItem[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromQueue(string id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromHistory(string id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients
|
||||||
|
{
|
||||||
|
public class FolderSettingsValidator : AbstractValidator<FolderSettings>
|
||||||
|
{
|
||||||
|
public FolderSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.Folder).NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FolderSettings : IProviderConfig
|
||||||
|
{
|
||||||
|
private static readonly FolderSettingsValidator Validator = new FolderSettingsValidator();
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Folder", Type = FieldType.Path)]
|
||||||
|
public String Folder { get; set; }
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
return Validator.Validate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
{
|
{
|
||||||
public class NzbGetQueue
|
public class NzbgetQueue
|
||||||
{
|
{
|
||||||
public String Version { get; set; }
|
public String Version { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "result")]
|
[JsonProperty(PropertyName = "result")]
|
||||||
public List<NzbGetQueueItem> QueueItems { get; set; }
|
public List<NzbgetQueueItem> QueueItems { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
{
|
{
|
||||||
public class NzbGetQueueItem
|
public class NzbgetQueueItem
|
||||||
{
|
{
|
||||||
private string _nzbName;
|
private string _nzbName;
|
||||||
|
|
||||||
public Int32 NzbId { get; set; }
|
public Int32 NzbId { get; set; }
|
||||||
|
|
||||||
public string NzbName { get; set; }
|
public string NzbName { get; set; }
|
||||||
|
|
||||||
public String Category { get; set; }
|
public String Category { get; set; }
|
||||||
public Int32 FileSizeMb { get; set; }
|
public Int32 FileSizeMb { get; set; }
|
||||||
public Int32 RemainingSizeMb { get; set; }
|
public Int32 RemainingSizeMb { get; set; }
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
|
{
|
||||||
|
public class Nzbget : DownloadClientBase<NzbgetSettings>, IExecute<TestNzbgetCommand>
|
||||||
|
{
|
||||||
|
private readonly INzbgetProxy _proxy;
|
||||||
|
private readonly IParsingService _parsingService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public Nzbget(INzbgetProxy proxy,
|
||||||
|
IParsingService parsingService,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_proxy = proxy;
|
||||||
|
_parsingService = parsingService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||||
|
{
|
||||||
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
var title = remoteEpisode.Release.Title + ".nzb";
|
||||||
|
|
||||||
|
string cat = Settings.TvCategory;
|
||||||
|
int priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
|
||||||
|
|
||||||
|
_logger.Info("Adding report [{0}] to the queue.", title);
|
||||||
|
|
||||||
|
var success = _proxy.AddNzb(Settings, title, cat, priority, false, url);
|
||||||
|
|
||||||
|
_logger.Debug("Queue Response: [{0}]", success);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<QueueItem> GetQueue()
|
||||||
|
{
|
||||||
|
var items = _proxy.GetQueue(Settings);
|
||||||
|
|
||||||
|
foreach (var nzbGetQueueItem in items)
|
||||||
|
{
|
||||||
|
var queueItem = new QueueItem();
|
||||||
|
queueItem.Id = nzbGetQueueItem.NzbId.ToString();
|
||||||
|
queueItem.Title = nzbGetQueueItem.NzbName;
|
||||||
|
queueItem.Size = nzbGetQueueItem.FileSizeMb;
|
||||||
|
queueItem.Sizeleft = nzbGetQueueItem.RemainingSizeMb;
|
||||||
|
queueItem.Status = nzbGetQueueItem.FileSizeMb == nzbGetQueueItem.PausedSizeMb ? "paused" : "queued";
|
||||||
|
|
||||||
|
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title);
|
||||||
|
if (parsedEpisodeInfo == null) continue;
|
||||||
|
|
||||||
|
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
||||||
|
if (remoteEpisode.Series == null) continue;
|
||||||
|
|
||||||
|
queueItem.RemoteEpisode = remoteEpisode;
|
||||||
|
|
||||||
|
yield return queueItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
||||||
|
{
|
||||||
|
return new HistoryItem[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromQueue(string id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromHistory(string id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VersionResponse GetVersion(string host = null, int port = 0, string username = null, string password = null)
|
||||||
|
{
|
||||||
|
return _proxy.GetVersion(Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestNzbgetCommand message)
|
||||||
|
{
|
||||||
|
var settings = new NzbgetSettings();
|
||||||
|
settings.InjectFrom(message);
|
||||||
|
|
||||||
|
_proxy.GetVersion(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,136 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Parser;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
|
||||||
{
|
|
||||||
public class NzbgetClient : IDownloadClient
|
|
||||||
{
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly IHttpProvider _httpProvider;
|
|
||||||
private readonly INzbGetCommunicationProxy _proxy;
|
|
||||||
private readonly IParsingService _parsingService;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public NzbgetClient(IConfigService configService,
|
|
||||||
IHttpProvider httpProvider,
|
|
||||||
INzbGetCommunicationProxy proxy,
|
|
||||||
IParsingService parsingService,
|
|
||||||
Logger logger)
|
|
||||||
{
|
|
||||||
_configService = configService;
|
|
||||||
_httpProvider = httpProvider;
|
|
||||||
_proxy = proxy;
|
|
||||||
_parsingService = parsingService;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DownloadNzb(RemoteEpisode remoteEpisode)
|
|
||||||
{
|
|
||||||
var url = remoteEpisode.Release.DownloadUrl;
|
|
||||||
var title = remoteEpisode.Release.Title + ".nzb";
|
|
||||||
|
|
||||||
string cat = _configService.NzbgetTvCategory;
|
|
||||||
int priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.NzbgetRecentTvPriority : (int)_configService.NzbgetOlderTvPriority;
|
|
||||||
|
|
||||||
_logger.Info("Adding report [{0}] to the queue.", title);
|
|
||||||
|
|
||||||
var success = _proxy.AddNzb(title, cat, priority, false, url);
|
|
||||||
|
|
||||||
_logger.Debug("Queue Response: [{0}]", success);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsConfigured
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !string.IsNullOrWhiteSpace(_configService.NzbgetHost) && _configService.NzbgetPort != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<QueueItem> GetQueue()
|
|
||||||
{
|
|
||||||
var items = _proxy.GetQueue();
|
|
||||||
|
|
||||||
foreach (var nzbGetQueueItem in items)
|
|
||||||
{
|
|
||||||
var queueItem = new QueueItem();
|
|
||||||
queueItem.Id = nzbGetQueueItem.NzbId.ToString();
|
|
||||||
queueItem.Title = nzbGetQueueItem.NzbName;
|
|
||||||
queueItem.Size = nzbGetQueueItem.FileSizeMb;
|
|
||||||
queueItem.Sizeleft = nzbGetQueueItem.RemainingSizeMb;
|
|
||||||
queueItem.Status = nzbGetQueueItem.FileSizeMb == nzbGetQueueItem.PausedSizeMb ? "paused" : "queued";
|
|
||||||
|
|
||||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title);
|
|
||||||
if (parsedEpisodeInfo == null) continue;
|
|
||||||
|
|
||||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
|
||||||
if (remoteEpisode.Series == null) continue;
|
|
||||||
|
|
||||||
queueItem.RemoteEpisode = remoteEpisode;
|
|
||||||
|
|
||||||
yield return queueItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
|
||||||
{
|
|
||||||
return new HistoryItem[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromQueue(string id)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromHistory(string id)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual VersionModel GetVersion(string host = null, int port = 0, string username = null, string password = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
|
|
||||||
//Get saved values if any of these are defaults
|
|
||||||
if (host == null)
|
|
||||||
host = _configService.NzbgetHost;
|
|
||||||
|
|
||||||
if (port == 0)
|
|
||||||
port = _configService.NzbgetPort;
|
|
||||||
|
|
||||||
if (username == null)
|
|
||||||
username = _configService.NzbgetUsername;
|
|
||||||
|
|
||||||
if (password == null)
|
|
||||||
password = _configService.NzbgetPassword;
|
|
||||||
|
|
||||||
|
|
||||||
var response = _proxy.GetVersion();
|
|
||||||
|
|
||||||
return Json.Deserialize<VersionModel>(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string Test(string host, int port, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var version = GetVersion(host, port, username, password);
|
|
||||||
return version.Result;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.DebugException("Failed to Test Nzbget", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
{
|
{
|
||||||
public enum PriorityType
|
public enum NzbgetPriority
|
||||||
{
|
{
|
||||||
VeryLow = -100,
|
VeryLow = -100,
|
||||||
Low = -50,
|
Low = -50,
|
|
@ -1,57 +1,52 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Rest;
|
using NzbDrone.Core.Rest;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
{
|
{
|
||||||
public interface INzbGetCommunicationProxy
|
public interface INzbgetProxy
|
||||||
{
|
{
|
||||||
bool AddNzb(params object[] parameters);
|
bool AddNzb(NzbgetSettings settings, params object[] parameters);
|
||||||
List<NzbGetQueueItem> GetQueue();
|
List<NzbgetQueueItem> GetQueue(NzbgetSettings settings);
|
||||||
string GetVersion();
|
VersionResponse GetVersion(NzbgetSettings settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NzbGetCommunicationProxy : INzbGetCommunicationProxy
|
public class NzbgetProxy : INzbgetProxy
|
||||||
{
|
{
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public NzbGetCommunicationProxy(IConfigService configService, Logger logger)
|
public NzbgetProxy(Logger logger)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddNzb(params object[] parameters)
|
public bool AddNzb(NzbgetSettings settings, params object[] parameters)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(new JsonRequest("appendurl", parameters));
|
var request = BuildRequest(new JsonRequest("appendurl", parameters));
|
||||||
|
|
||||||
return Json.Deserialize<EnqueueResponse>(ProcessRequest(request)).Result;
|
return Json.Deserialize<EnqueueResponse>(ProcessRequest(request, settings)).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<NzbGetQueueItem> GetQueue()
|
public List<NzbgetQueueItem> GetQueue(NzbgetSettings settings)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(new JsonRequest("listgroups"));
|
var request = BuildRequest(new JsonRequest("listgroups"));
|
||||||
|
|
||||||
return Json.Deserialize<NzbGetQueue>(ProcessRequest(request)).QueueItems;
|
return Json.Deserialize<NzbgetQueue>(ProcessRequest(request, settings)).QueueItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetVersion()
|
public VersionResponse GetVersion(NzbgetSettings settings)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(new JsonRequest("version"));
|
var request = BuildRequest(new JsonRequest("version"));
|
||||||
|
|
||||||
return ProcessRequest(request);
|
return Json.Deserialize<VersionResponse>(ProcessRequest(request, settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ProcessRequest(IRestRequest restRequest)
|
private string ProcessRequest(IRestRequest restRequest, NzbgetSettings settings)
|
||||||
{
|
{
|
||||||
var client = BuildClient();
|
var client = BuildClient(settings);
|
||||||
var response = client.Execute(restRequest);
|
var response = client.Execute(restRequest);
|
||||||
_logger.Trace("Response: {0}", response.Content);
|
_logger.Trace("Response: {0}", response.Content);
|
||||||
|
|
||||||
|
@ -60,14 +55,14 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
return response.Content;
|
return response.Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IRestClient BuildClient()
|
private IRestClient BuildClient(NzbgetSettings settings)
|
||||||
{
|
{
|
||||||
var url = String.Format("http://{0}:{1}/jsonrpc",
|
var url = String.Format("http://{0}:{1}/jsonrpc",
|
||||||
_configService.NzbgetHost,
|
settings.Host,
|
||||||
_configService.NzbgetPort);
|
settings.Port);
|
||||||
|
|
||||||
var client = new RestClient(url);
|
var client = new RestClient(url);
|
||||||
client.Authenticator = new HttpBasicAuthenticator(_configService.NzbgetUsername, _configService.NzbgetPassword);
|
client.Authenticator = new HttpBasicAuthenticator(settings.Username, settings.Password);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
|
{
|
||||||
|
public class NzbgetSettingsValidator : AbstractValidator<NzbgetSettings>
|
||||||
|
{
|
||||||
|
public NzbgetSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.Host).NotEmpty();
|
||||||
|
RuleFor(c => c.Port).GreaterThan(0);
|
||||||
|
RuleFor(c => c.Username).NotEmpty();
|
||||||
|
RuleFor(c => c.Password).NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NzbgetSettings : IProviderConfig
|
||||||
|
{
|
||||||
|
private static readonly NzbgetSettingsValidator Validator = new NzbgetSettingsValidator();
|
||||||
|
|
||||||
|
public NzbgetSettings()
|
||||||
|
{
|
||||||
|
Host = "localhost";
|
||||||
|
Port = 6789;
|
||||||
|
TvCategory = "tv";
|
||||||
|
RecentTvPriority = (int)NzbgetPriority.Normal;
|
||||||
|
OlderTvPriority = (int)NzbgetPriority.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
|
||||||
|
public String Host { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)]
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(2, Label = "Username", Type = FieldType.Textbox)]
|
||||||
|
public String Username { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
|
||||||
|
public String Password { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox)]
|
||||||
|
public String TvCategory { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority))]
|
||||||
|
public Int32 RecentTvPriority { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority))]
|
||||||
|
public Int32 OlderTvPriority { get; set; }
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
return Validator.Validate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
|
{
|
||||||
|
public class TestNzbgetCommand : Command
|
||||||
|
{
|
||||||
|
public override bool SendUpdatesToClient
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Host { get; set; }
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
public String Username { get; set; }
|
||||||
|
public String Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Nzbget
|
namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
{
|
{
|
||||||
public class VersionModel
|
public class VersionResponse
|
||||||
{
|
{
|
||||||
public String Version { get; set; }
|
public String Version { get; set; }
|
||||||
public String Result { get; set; }
|
public String Result { get; set; }
|
|
@ -6,12 +6,13 @@ using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Instrumentation;
|
using NzbDrone.Common.Instrumentation;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients
|
namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||||
{
|
{
|
||||||
public class PneumaticClient : IDownloadClient
|
public class Pneumatic : DownloadClientBase<FolderSettings>, IExecute<TestPneumaticCommand>
|
||||||
{
|
{
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
@ -19,7 +20,7 @@ namespace NzbDrone.Core.Download.Clients
|
||||||
|
|
||||||
private static readonly Logger logger = NzbDroneLogger.GetLogger();
|
private static readonly Logger logger = NzbDroneLogger.GetLogger();
|
||||||
|
|
||||||
public PneumaticClient(IConfigService configService, IHttpProvider httpProvider,
|
public Pneumatic(IConfigService configService, IHttpProvider httpProvider,
|
||||||
IDiskProvider diskProvider)
|
IDiskProvider diskProvider)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
|
@ -27,20 +28,20 @@ namespace NzbDrone.Core.Download.Clients
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DownloadNzb(RemoteEpisode remoteEpisode)
|
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||||
{
|
{
|
||||||
var url = remoteEpisode.Release.DownloadUrl;
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
var title = remoteEpisode.Release.Title;
|
var title = remoteEpisode.Release.Title;
|
||||||
|
|
||||||
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
|
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Full season Pneumatic releases are not supported.");
|
throw new NotImplementedException("Full season releases are not supported with Pneumatic.");
|
||||||
}
|
}
|
||||||
|
|
||||||
title = FileNameBuilder.CleanFilename(title);
|
title = FileNameBuilder.CleanFilename(title);
|
||||||
|
|
||||||
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
|
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
|
||||||
var filename = Path.Combine(_configService.PneumaticFolder, title + ".nzb");
|
var filename = Path.Combine(Settings.Folder, title + ".nzb");
|
||||||
|
|
||||||
logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
|
logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
|
||||||
_httpProvider.DownloadFile(url, filename);
|
_httpProvider.DownloadFile(url, filename);
|
||||||
|
@ -57,31 +58,33 @@ namespace NzbDrone.Core.Download.Clients
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return !string.IsNullOrWhiteSpace(_configService.PneumaticFolder);
|
return !string.IsNullOrWhiteSpace(Settings.Folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<QueueItem> GetQueue()
|
public override IEnumerable<QueueItem> GetQueue()
|
||||||
{
|
{
|
||||||
return new QueueItem[0];
|
return new QueueItem[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
||||||
{
|
{
|
||||||
return new HistoryItem[0];
|
return new HistoryItem[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFromQueue(string id)
|
public override void RemoveFromQueue(string id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFromHistory(string id)
|
public override void RemoveFromHistory(string id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsInQueue(RemoteEpisode newEpisode)
|
public void Execute(TestPneumaticCommand message)
|
||||||
{
|
{
|
||||||
return false;
|
var testPath = Path.Combine(message.Folder, "drone_test.txt");
|
||||||
|
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
|
||||||
|
_diskProvider.DeleteFile(testPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||||
|
{
|
||||||
|
public class TestPneumaticCommand : Command
|
||||||
|
{
|
||||||
|
public override bool SendUpdatesToClient
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Folder { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class ConnectionInfoModel
|
|
||||||
{
|
|
||||||
public string Address { get; set; }
|
|
||||||
public int Port { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
|
||||||
{
|
{
|
||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
var priorityType = (SabPriorityType)value;
|
var priorityType = (SabnzbdPriority)value;
|
||||||
writer.WriteValue(priorityType.ToString());
|
writer.WriteValue(priorityType.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
|
||||||
{
|
{
|
||||||
var queuePriority = reader.Value.ToString();
|
var queuePriority = reader.Value.ToString();
|
||||||
|
|
||||||
SabPriorityType output;
|
SabnzbdPriority output;
|
||||||
Enum.TryParse(queuePriority, out output);
|
Enum.TryParse(queuePriority, out output);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -23,7 +23,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
|
||||||
|
|
||||||
public override bool CanConvert(Type objectType)
|
public override bool CanConvert(Type objectType)
|
||||||
{
|
{
|
||||||
return objectType == typeof(SabPriorityType);
|
return objectType == typeof(SabnzbdPriority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
|
||||||
|
{
|
||||||
|
public class SabnzbdAddResponse
|
||||||
|
{
|
||||||
|
public SabnzbdAddResponse()
|
||||||
|
{
|
||||||
|
Ids = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Status { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "nzo_ids")]
|
||||||
|
public List<string> Ids { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
|
||||||
|
{
|
||||||
|
public class SabnzbdCategoryResponse
|
||||||
|
{
|
||||||
|
public SabnzbdCategoryResponse()
|
||||||
|
{
|
||||||
|
Categories = new List<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> Categories { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
|
||||||
|
{
|
||||||
|
public class SabnzbdVersionResponse
|
||||||
|
{
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabAddResponse
|
|
||||||
{
|
|
||||||
public SabAddResponse()
|
|
||||||
{
|
|
||||||
Ids = new List<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Status { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "nzo_ids")]
|
|
||||||
public List<String> Ids { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Instrumentation;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabAutoConfigureService
|
|
||||||
{
|
|
||||||
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
|
|
||||||
|
|
||||||
public SabModel AutoConfigureSab()
|
|
||||||
{
|
|
||||||
var info = GetConnectionList();
|
|
||||||
return FindApiKey(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ConnectionInfoModel> GetConnectionList()
|
|
||||||
{
|
|
||||||
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
|
|
||||||
var info =
|
|
||||||
ipProperties.GetActiveTcpListeners().Select(
|
|
||||||
p =>
|
|
||||||
new ConnectionInfoModel { Address = p.Address.ToString().Replace("0.0.0.0", "127.0.0.1"), Port = p.Port }).Distinct().
|
|
||||||
ToList();
|
|
||||||
|
|
||||||
info.RemoveAll(i => i.Port == 135);
|
|
||||||
info.RemoveAll(i => i.Port == 139);
|
|
||||||
info.RemoveAll(i => i.Port == 445);
|
|
||||||
info.RemoveAll(i => i.Port == 3389);
|
|
||||||
info.RemoveAll(i => i.Port == 5900);
|
|
||||||
info.RemoveAll(i => i.Address.Contains("::"));
|
|
||||||
|
|
||||||
info.Reverse();
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SabModel FindApiKey(List<ConnectionInfoModel> info)
|
|
||||||
{
|
|
||||||
foreach (var connection in info)
|
|
||||||
{
|
|
||||||
var apiKey = GetApiKey(connection.Address, connection.Port);
|
|
||||||
if (!String.IsNullOrEmpty(apiKey))
|
|
||||||
return new SabModel
|
|
||||||
{
|
|
||||||
Host = connection.Address,
|
|
||||||
Port = connection.Port,
|
|
||||||
ApiKey = apiKey
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetApiKey(string ipAddress, int port)
|
|
||||||
{
|
|
||||||
var request = String.Format("http://{0}:{1}/config/general/", ipAddress, port);
|
|
||||||
var result = DownloadString(request);
|
|
||||||
|
|
||||||
Regex regex =
|
|
||||||
new Regex("\\<input\\Wtype\\=\\\"text\\\"\\Wid\\=\\\"apikey\\\"\\Wvalue\\=\\\"(?<apikey>\\w+)\\W",
|
|
||||||
RegexOptions.IgnoreCase
|
|
||||||
| RegexOptions.Compiled);
|
|
||||||
var match = regex.Match(result);
|
|
||||||
|
|
||||||
if (match.Success)
|
|
||||||
{
|
|
||||||
return match.Groups["apikey"].Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DownloadString(string url)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var request = WebRequest.Create(url);
|
|
||||||
request.Timeout = 2000;
|
|
||||||
|
|
||||||
var response = request.GetResponse();
|
|
||||||
|
|
||||||
var reader = new StreamReader(response.GetResponseStream());
|
|
||||||
return reader.ReadToEnd();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Trace("Failed to get response from: {0}", url);
|
|
||||||
Logger.Trace(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabCategoryModel
|
|
||||||
{
|
|
||||||
public List<string> categories { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using RestSharp;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public interface ISabCommunicationProxy
|
|
||||||
{
|
|
||||||
SabAddResponse DownloadNzb(Stream nzb, string name, string category, int priority);
|
|
||||||
void RemoveFrom(string source, string id);
|
|
||||||
string ProcessRequest(IRestRequest restRequest, string action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SabCommunicationProxy : ISabCommunicationProxy
|
|
||||||
{
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public SabCommunicationProxy(IConfigService configService, Logger logger)
|
|
||||||
{
|
|
||||||
_configService = configService;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SabAddResponse DownloadNzb(Stream nzb, string title, string category, int priority)
|
|
||||||
{
|
|
||||||
var request = new RestRequest(Method.POST);
|
|
||||||
var action = String.Format("mode=addfile&cat={0}&priority={1}", category, priority);
|
|
||||||
|
|
||||||
request.AddFile("name", ReadFully(nzb), title, "application/x-nzb");
|
|
||||||
|
|
||||||
SabAddResponse response;
|
|
||||||
|
|
||||||
if (!Json.TryDeserialize<SabAddResponse>(ProcessRequest(request, action), out response))
|
|
||||||
{
|
|
||||||
response = new SabAddResponse();
|
|
||||||
response.Status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFrom(string source, string id)
|
|
||||||
{
|
|
||||||
var request = new RestRequest();
|
|
||||||
var action = String.Format("mode={0}&name=delete&del_files=1&value={1}", source, id);
|
|
||||||
|
|
||||||
ProcessRequest(request, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ProcessRequest(IRestRequest restRequest, string action)
|
|
||||||
{
|
|
||||||
var client = BuildClient(action);
|
|
||||||
var response = client.Execute(restRequest);
|
|
||||||
_logger.Trace("Response: {0}", response.Content);
|
|
||||||
|
|
||||||
CheckForError(response);
|
|
||||||
|
|
||||||
return response.Content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRestClient BuildClient(string action)
|
|
||||||
{
|
|
||||||
var protocol = _configService.SabUseSsl ? "https" : "http";
|
|
||||||
|
|
||||||
var url = string.Format(@"{0}://{1}:{2}/api?{3}&apikey={4}&ma_username={5}&ma_password={6}&output=json",
|
|
||||||
protocol,
|
|
||||||
_configService.SabHost,
|
|
||||||
_configService.SabPort,
|
|
||||||
action,
|
|
||||||
_configService.SabApiKey,
|
|
||||||
_configService.SabUsername,
|
|
||||||
_configService.SabPassword);
|
|
||||||
|
|
||||||
_logger.Trace(url);
|
|
||||||
|
|
||||||
return new RestClient(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckForError(IRestResponse response)
|
|
||||||
{
|
|
||||||
if (response.ResponseStatus != ResponseStatus.Completed)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("Unable to connect to SABnzbd, please check your settings");
|
|
||||||
}
|
|
||||||
|
|
||||||
SabJsonError result;
|
|
||||||
|
|
||||||
if (!Json.TryDeserialize<SabJsonError>(response.Content, out result))
|
|
||||||
{
|
|
||||||
//Handle plain text responses from SAB
|
|
||||||
result = new SabJsonError();
|
|
||||||
|
|
||||||
if (response.Content.StartsWith("error", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
result.Status = "false";
|
|
||||||
result.Error = response.Content.Replace("error: ", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Status = "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Error = response.Content.Replace("error: ", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Failed)
|
|
||||||
throw new ApplicationException(result.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Find a better home for this
|
|
||||||
private byte[] ReadFully(Stream input)
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[16 * 1024];
|
|
||||||
using (MemoryStream ms = new MemoryStream())
|
|
||||||
{
|
|
||||||
int read;
|
|
||||||
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
|
|
||||||
{
|
|
||||||
ms.Write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabModel
|
|
||||||
{
|
|
||||||
public string Host { get; set; }
|
|
||||||
public int Port { get; set; }
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabVersionModel
|
|
||||||
{
|
|
||||||
public string Version { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
|
{
|
||||||
|
public class Sabnzbd : DownloadClientBase<SabnzbdSettings>, IExecute<TestSabnzbdCommand>
|
||||||
|
{
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly IParsingService _parsingService;
|
||||||
|
private readonly ISabnzbdProxy _sabnzbdProxy;
|
||||||
|
private readonly ICached<IEnumerable<QueueItem>> _queueCache;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public Sabnzbd(IHttpProvider httpProvider,
|
||||||
|
ICacheManger cacheManger,
|
||||||
|
IParsingService parsingService,
|
||||||
|
ISabnzbdProxy sabnzbdProxy,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_parsingService = parsingService;
|
||||||
|
_sabnzbdProxy = sabnzbdProxy;
|
||||||
|
_queueCache = cacheManger.GetCache<IEnumerable<QueueItem>>(GetType(), "queue");
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||||
|
{
|
||||||
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
var title = remoteEpisode.Release.Title;
|
||||||
|
var category = Settings.TvCategory;
|
||||||
|
var priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
|
||||||
|
|
||||||
|
using (var nzb = _httpProvider.DownloadStream(url))
|
||||||
|
{
|
||||||
|
_logger.Info("Adding report [{0}] to the queue.", title);
|
||||||
|
var response = _sabnzbdProxy.DownloadNzb(nzb, title, category, priority, Settings);
|
||||||
|
|
||||||
|
if (response != null && response.Ids.Any())
|
||||||
|
{
|
||||||
|
return response.Ids.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<QueueItem> GetQueue()
|
||||||
|
{
|
||||||
|
return _queueCache.Get("queue", () =>
|
||||||
|
{
|
||||||
|
var sabQueue = _sabnzbdProxy.GetQueue(0, 0, Settings).Items;
|
||||||
|
|
||||||
|
var queueItems = new List<QueueItem>();
|
||||||
|
|
||||||
|
foreach (var sabQueueItem in sabQueue)
|
||||||
|
{
|
||||||
|
var queueItem = new QueueItem();
|
||||||
|
queueItem.Id = sabQueueItem.Id;
|
||||||
|
queueItem.Title = sabQueueItem.Title;
|
||||||
|
queueItem.Size = sabQueueItem.Size;
|
||||||
|
queueItem.Sizeleft = sabQueueItem.Sizeleft;
|
||||||
|
queueItem.Timeleft = sabQueueItem.Timeleft;
|
||||||
|
queueItem.Status = sabQueueItem.Status;
|
||||||
|
|
||||||
|
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title.Replace("ENCRYPTED / ", ""));
|
||||||
|
if (parsedEpisodeInfo == null) continue;
|
||||||
|
|
||||||
|
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
||||||
|
if (remoteEpisode.Series == null) continue;
|
||||||
|
|
||||||
|
queueItem.RemoteEpisode = remoteEpisode;
|
||||||
|
|
||||||
|
queueItems.Add(queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queueItems;
|
||||||
|
}, TimeSpan.FromSeconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
||||||
|
{
|
||||||
|
var items = _sabnzbdProxy.GetHistory(start, limit, Settings).Items;
|
||||||
|
var historyItems = new List<HistoryItem>();
|
||||||
|
|
||||||
|
foreach (var sabHistoryItem in items)
|
||||||
|
{
|
||||||
|
var historyItem = new HistoryItem();
|
||||||
|
historyItem.Id = sabHistoryItem.Id;
|
||||||
|
historyItem.Title = sabHistoryItem.Title;
|
||||||
|
historyItem.Size = sabHistoryItem.Size;
|
||||||
|
historyItem.DownloadTime = sabHistoryItem.DownloadTime;
|
||||||
|
historyItem.Storage = sabHistoryItem.Storage;
|
||||||
|
historyItem.Category = sabHistoryItem.Category;
|
||||||
|
historyItem.Message = sabHistoryItem.FailMessage;
|
||||||
|
historyItem.Status = sabHistoryItem.Status == "Failed" ? HistoryStatus.Failed : HistoryStatus.Completed;
|
||||||
|
|
||||||
|
historyItems.Add(historyItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return historyItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromQueue(string id)
|
||||||
|
{
|
||||||
|
_sabnzbdProxy.RemoveFrom("queue", id, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveFromHistory(string id)
|
||||||
|
{
|
||||||
|
_sabnzbdProxy.RemoveFrom("history", id, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestSabnzbdCommand message)
|
||||||
|
{
|
||||||
|
var settings = new SabnzbdSettings();
|
||||||
|
settings.InjectFrom(message);
|
||||||
|
|
||||||
|
_sabnzbdProxy.GetVersion(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,250 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Common.Cache;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Parser;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|
||||||
{
|
|
||||||
public class SabnzbdClient : IDownloadClient
|
|
||||||
{
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly IHttpProvider _httpProvider;
|
|
||||||
private readonly IParsingService _parsingService;
|
|
||||||
private readonly ISabCommunicationProxy _sabCommunicationProxy;
|
|
||||||
private readonly ICached<IEnumerable<QueueItem>> _queueCache;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public SabnzbdClient(IConfigService configService,
|
|
||||||
IHttpProvider httpProvider,
|
|
||||||
ICacheManger cacheManger,
|
|
||||||
IParsingService parsingService,
|
|
||||||
ISabCommunicationProxy sabCommunicationProxy,
|
|
||||||
Logger logger)
|
|
||||||
{
|
|
||||||
_configService = configService;
|
|
||||||
_httpProvider = httpProvider;
|
|
||||||
_parsingService = parsingService;
|
|
||||||
_sabCommunicationProxy = sabCommunicationProxy;
|
|
||||||
_queueCache = cacheManger.GetCache<IEnumerable<QueueItem>>(GetType(), "queue");
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsConfigured
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !string.IsNullOrWhiteSpace(_configService.SabHost)
|
|
||||||
&& _configService.SabPort != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DownloadNzb(RemoteEpisode remoteEpisode)
|
|
||||||
{
|
|
||||||
var url = remoteEpisode.Release.DownloadUrl;
|
|
||||||
var title = remoteEpisode.Release.Title;
|
|
||||||
var category = _configService.SabTvCategory;
|
|
||||||
var priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.SabRecentTvPriority : (int)_configService.SabOlderTvPriority;
|
|
||||||
|
|
||||||
using (var nzb = _httpProvider.DownloadStream(url))
|
|
||||||
{
|
|
||||||
_logger.Info("Adding report [{0}] to the queue.", title);
|
|
||||||
var response = _sabCommunicationProxy.DownloadNzb(nzb, title, category, priority);
|
|
||||||
|
|
||||||
if (response != null && response.Ids.Any())
|
|
||||||
{
|
|
||||||
return response.Ids.First();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<QueueItem> GetQueue()
|
|
||||||
{
|
|
||||||
return _queueCache.Get("queue", () =>
|
|
||||||
{
|
|
||||||
string action = String.Format("mode=queue&output=json&start={0}&limit={1}", 0, 0);
|
|
||||||
string request = GetSabRequest(action);
|
|
||||||
string response = _httpProvider.DownloadString(request);
|
|
||||||
|
|
||||||
CheckForError(response);
|
|
||||||
|
|
||||||
var sabQueue = Json.Deserialize<SabQueue>(JObject.Parse(response).SelectToken("queue").ToString()).Items;
|
|
||||||
|
|
||||||
var queueItems = new List<QueueItem>();
|
|
||||||
|
|
||||||
foreach (var sabQueueItem in sabQueue)
|
|
||||||
{
|
|
||||||
var queueItem = new QueueItem();
|
|
||||||
queueItem.Id = sabQueueItem.Id;
|
|
||||||
queueItem.Title = sabQueueItem.Title;
|
|
||||||
queueItem.Size = sabQueueItem.Size;
|
|
||||||
queueItem.Sizeleft = sabQueueItem.Sizeleft;
|
|
||||||
queueItem.Timeleft = sabQueueItem.Timeleft;
|
|
||||||
queueItem.Status = sabQueueItem.Status;
|
|
||||||
|
|
||||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title.Replace("ENCRYPTED / ", ""));
|
|
||||||
if (parsedEpisodeInfo == null) continue;
|
|
||||||
|
|
||||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
|
||||||
if (remoteEpisode.Series == null) continue;
|
|
||||||
|
|
||||||
queueItem.RemoteEpisode = remoteEpisode;
|
|
||||||
|
|
||||||
queueItems.Add(queueItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queueItems;
|
|
||||||
}, TimeSpan.FromSeconds(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
|
|
||||||
{
|
|
||||||
string action = String.Format("mode=history&output=json&start={0}&limit={1}", start, limit);
|
|
||||||
string request = GetSabRequest(action);
|
|
||||||
string response = _httpProvider.DownloadString(request);
|
|
||||||
|
|
||||||
CheckForError(response);
|
|
||||||
|
|
||||||
var items = Json.Deserialize<SabHistory>(JObject.Parse(response).SelectToken("history").ToString()).Items;
|
|
||||||
var historyItems = new List<HistoryItem>();
|
|
||||||
|
|
||||||
foreach (var sabHistoryItem in items)
|
|
||||||
{
|
|
||||||
var historyItem = new HistoryItem();
|
|
||||||
historyItem.Id = sabHistoryItem.Id;
|
|
||||||
historyItem.Title = sabHistoryItem.Title;
|
|
||||||
historyItem.Size = sabHistoryItem.Size;
|
|
||||||
historyItem.DownloadTime = sabHistoryItem.DownloadTime;
|
|
||||||
historyItem.Storage = sabHistoryItem.Storage;
|
|
||||||
historyItem.Category = sabHistoryItem.Category;
|
|
||||||
historyItem.Message = sabHistoryItem.FailMessage;
|
|
||||||
historyItem.Status = sabHistoryItem.Status == "Failed" ? HistoryStatus.Failed : HistoryStatus.Completed;
|
|
||||||
|
|
||||||
historyItems.Add(historyItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return historyItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromQueue(string id)
|
|
||||||
{
|
|
||||||
_sabCommunicationProxy.RemoveFrom("queue", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromHistory(string id)
|
|
||||||
{
|
|
||||||
_sabCommunicationProxy.RemoveFrom("history", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual SabCategoryModel GetCategories(string host = null, int port = 0, string apiKey = null, string username = null, string password = null)
|
|
||||||
{
|
|
||||||
//Get saved values if any of these are defaults
|
|
||||||
if (host == null)
|
|
||||||
host = _configService.SabHost;
|
|
||||||
|
|
||||||
if (port == 0)
|
|
||||||
port = _configService.SabPort;
|
|
||||||
|
|
||||||
if (apiKey == null)
|
|
||||||
apiKey = _configService.SabApiKey;
|
|
||||||
|
|
||||||
if (username == null)
|
|
||||||
username = _configService.SabUsername;
|
|
||||||
|
|
||||||
if (password == null)
|
|
||||||
password = _configService.SabPassword;
|
|
||||||
|
|
||||||
const string action = "mode=get_cats&output=json";
|
|
||||||
|
|
||||||
var command = string.Format(@"http://{0}:{1}/api?{2}&apikey={3}&ma_username={4}&ma_password={5}",
|
|
||||||
host, port, action, apiKey, username, password);
|
|
||||||
|
|
||||||
var response = _httpProvider.DownloadString(command);
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(response))
|
|
||||||
return new SabCategoryModel { categories = new List<string>() };
|
|
||||||
|
|
||||||
var categories = Json.Deserialize<SabCategoryModel>(response);
|
|
||||||
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual SabVersionModel GetVersion(string host = null, int port = 0, string apiKey = null, string username = null, string password = null)
|
|
||||||
{
|
|
||||||
//Get saved values if any of these are defaults
|
|
||||||
if (host == null)
|
|
||||||
host = _configService.SabHost;
|
|
||||||
|
|
||||||
if (port == 0)
|
|
||||||
port = _configService.SabPort;
|
|
||||||
|
|
||||||
if (apiKey == null)
|
|
||||||
apiKey = _configService.SabApiKey;
|
|
||||||
|
|
||||||
if (username == null)
|
|
||||||
username = _configService.SabUsername;
|
|
||||||
|
|
||||||
if (password == null)
|
|
||||||
password = _configService.SabPassword;
|
|
||||||
|
|
||||||
const string action = "mode=version&output=json";
|
|
||||||
|
|
||||||
var command = string.Format(@"http://{0}:{1}/api?{2}&apikey={3}&ma_username={4}&ma_password={5}",
|
|
||||||
host, port, action, apiKey, username, password);
|
|
||||||
|
|
||||||
var response = _httpProvider.DownloadString(command);
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(response))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var version = Json.Deserialize<SabVersionModel>(response);
|
|
||||||
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string Test(string host, int port, string apiKey, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var version = GetVersion(host, port, apiKey, username, password);
|
|
||||||
return version.Version;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.DebugException("Failed to Test SABnzbd", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetSabRequest(string action)
|
|
||||||
{
|
|
||||||
var protocol = _configService.SabUseSsl ? "https" : "http";
|
|
||||||
|
|
||||||
return string.Format(@"{0}://{1}:{2}/api?{3}&apikey={4}&ma_username={5}&ma_password={6}",
|
|
||||||
protocol,
|
|
||||||
_configService.SabHost,
|
|
||||||
_configService.SabPort,
|
|
||||||
action,
|
|
||||||
_configService.SabApiKey,
|
|
||||||
_configService.SabUsername,
|
|
||||||
_configService.SabPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckForError(string response)
|
|
||||||
{
|
|
||||||
var result = Json.Deserialize<SabJsonError>(response);
|
|
||||||
|
|
||||||
if (result.Failed)
|
|
||||||
throw new ApplicationException(result.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,11 +3,11 @@ using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public class SabQueue
|
public class SabnzbdHistory
|
||||||
{
|
{
|
||||||
public bool Paused { get; set; }
|
public bool Paused { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "slots")]
|
[JsonProperty(PropertyName = "slots")]
|
||||||
public List<SabQueueItem> Items { get; set; }
|
public List<SabnzbdHistoryItem> Items { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public class SabHistoryItem
|
public class SabnzbdHistoryItem
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "fail_message")]
|
[JsonProperty(PropertyName = "fail_message")]
|
||||||
public string FailMessage { get; set; }
|
public string FailMessage { get; set; }
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public class SabJsonError
|
public class SabnzbdJsonError
|
||||||
{
|
{
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string Error { get; set; }
|
public string Error { get; set; }
|
|
@ -1,6 +1,6 @@
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public enum SabPriorityType
|
public enum SabnzbdPriority
|
||||||
{
|
{
|
||||||
Default = -100,
|
Default = -100,
|
||||||
Paused = -2,
|
Paused = -2,
|
|
@ -0,0 +1,182 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
|
{
|
||||||
|
public interface ISabnzbdProxy
|
||||||
|
{
|
||||||
|
SabnzbdAddResponse DownloadNzb(Stream nzb, string name, string category, int priority, SabnzbdSettings settings);
|
||||||
|
void RemoveFrom(string source, string id, SabnzbdSettings settings);
|
||||||
|
string ProcessRequest(IRestRequest restRequest, string action, SabnzbdSettings settings);
|
||||||
|
SabnzbdVersionResponse GetVersion(SabnzbdSettings settings);
|
||||||
|
SabnzbdCategoryResponse GetCategories(SabnzbdSettings settings);
|
||||||
|
SabnzbdQueue GetQueue(int start, int limit, SabnzbdSettings settings);
|
||||||
|
SabnzbdHistory GetHistory(int start, int limit, SabnzbdSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SabnzbdProxy : ISabnzbdProxy
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public SabnzbdProxy(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SabnzbdAddResponse DownloadNzb(Stream nzb, string title, string category, int priority, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest(Method.POST);
|
||||||
|
var action = String.Format("mode=addfile&cat={0}&priority={1}", category, priority);
|
||||||
|
|
||||||
|
request.AddFile("name", ReadFully(nzb), title, "application/x-nzb");
|
||||||
|
|
||||||
|
SabnzbdAddResponse response;
|
||||||
|
|
||||||
|
if (!Json.TryDeserialize<SabnzbdAddResponse>(ProcessRequest(request, action, settings), out response))
|
||||||
|
{
|
||||||
|
response = new SabnzbdAddResponse();
|
||||||
|
response.Status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveFrom(string source, string id, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
var action = String.Format("mode={0}&name=delete&del_files=1&value={1}", source, id);
|
||||||
|
|
||||||
|
ProcessRequest(request, action, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProcessRequest(IRestRequest restRequest, string action, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var client = BuildClient(action, settings);
|
||||||
|
var response = client.Execute(restRequest);
|
||||||
|
_logger.Trace("Response: {0}", response.Content);
|
||||||
|
|
||||||
|
CheckForError(response);
|
||||||
|
|
||||||
|
return response.Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SabnzbdVersionResponse GetVersion(SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
var action = "mode=version";
|
||||||
|
|
||||||
|
SabnzbdVersionResponse response;
|
||||||
|
|
||||||
|
if (!Json.TryDeserialize<SabnzbdVersionResponse>(ProcessRequest(request, action, settings), out response))
|
||||||
|
{
|
||||||
|
response = new SabnzbdVersionResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SabnzbdCategoryResponse GetCategories(SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
var action = "mode=get_cats";
|
||||||
|
|
||||||
|
SabnzbdCategoryResponse response;
|
||||||
|
|
||||||
|
if (!Json.TryDeserialize<SabnzbdCategoryResponse>(ProcessRequest(request, action, settings), out response))
|
||||||
|
{
|
||||||
|
response = new SabnzbdCategoryResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SabnzbdQueue GetQueue(int start, int limit, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
var action = String.Format("mode=queue&start={0}&limit={1}", start, limit);
|
||||||
|
|
||||||
|
var response = ProcessRequest(request, action, settings);
|
||||||
|
return Json.Deserialize<SabnzbdQueue>(JObject.Parse(response).SelectToken("queue").ToString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SabnzbdHistory GetHistory(int start, int limit, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
var action = String.Format("mode=queue&start={0}&limit={1}", start, limit);
|
||||||
|
|
||||||
|
var response = ProcessRequest(request, action, settings);
|
||||||
|
return Json.Deserialize<SabnzbdHistory>(JObject.Parse(response).SelectToken("history").ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRestClient BuildClient(string action, SabnzbdSettings settings)
|
||||||
|
{
|
||||||
|
var protocol = settings.UseSsl ? "https" : "http";
|
||||||
|
|
||||||
|
var url = string.Format(@"{0}://{1}:{2}/api?{3}&apikey={4}&ma_username={5}&ma_password={6}&output=json",
|
||||||
|
protocol,
|
||||||
|
settings.Host,
|
||||||
|
settings.Port,
|
||||||
|
action,
|
||||||
|
settings.ApiKey,
|
||||||
|
settings.Username,
|
||||||
|
settings.Password);
|
||||||
|
|
||||||
|
_logger.Trace(url);
|
||||||
|
|
||||||
|
return new RestClient(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckForError(IRestResponse response)
|
||||||
|
{
|
||||||
|
if (response.ResponseStatus != ResponseStatus.Completed)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Unable to connect to SABnzbd, please check your settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
SabnzbdJsonError result;
|
||||||
|
|
||||||
|
if (!Json.TryDeserialize<SabnzbdJsonError>(response.Content, out result))
|
||||||
|
{
|
||||||
|
//Handle plain text responses from SAB
|
||||||
|
result = new SabnzbdJsonError();
|
||||||
|
|
||||||
|
if (response.Content.StartsWith("error", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Status = "false";
|
||||||
|
result.Error = response.Content.Replace("error: ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Status = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Error = response.Content.Replace("error: ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Failed)
|
||||||
|
throw new ApplicationException(result.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Find a better home for this
|
||||||
|
private byte[] ReadFully(Stream input)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[16 * 1024];
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
int read;
|
||||||
|
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||||
|
{
|
||||||
|
ms.Write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,11 +3,11 @@ using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public class SabHistory
|
public class SabnzbdQueue
|
||||||
{
|
{
|
||||||
public bool Paused { get; set; }
|
public bool Paused { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "slots")]
|
[JsonProperty(PropertyName = "slots")]
|
||||||
public List<SabHistoryItem> Items { get; set; }
|
public List<SabnzbdQueueItem> Items { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ using NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
{
|
{
|
||||||
public class SabQueueItem
|
public class SabnzbdQueueItem
|
||||||
{
|
{
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
@ -21,7 +21,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
|
||||||
[JsonConverter(typeof(SabnzbdPriorityTypeConverter))]
|
[JsonConverter(typeof(SabnzbdPriorityTypeConverter))]
|
||||||
public SabPriorityType Priority { get; set; }
|
public SabnzbdPriority Priority { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "cat")]
|
[JsonProperty(PropertyName = "cat")]
|
||||||
public string Category { get; set; }
|
public string Category { get; set; }
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
|
{
|
||||||
|
public class SabnzbdSettingsValidator : AbstractValidator<SabnzbdSettings>
|
||||||
|
{
|
||||||
|
public SabnzbdSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.Host).NotEmpty();
|
||||||
|
RuleFor(c => c.Port).GreaterThan(0);
|
||||||
|
|
||||||
|
//Todo: either API key or Username/Password needs to be valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SabnzbdSettings : IProviderConfig
|
||||||
|
{
|
||||||
|
private static readonly SabnzbdSettingsValidator Validator = new SabnzbdSettingsValidator();
|
||||||
|
|
||||||
|
public SabnzbdSettings()
|
||||||
|
{
|
||||||
|
Host = "localhost";
|
||||||
|
Port = 8080;
|
||||||
|
TvCategory = "tv";
|
||||||
|
RecentTvPriority = (int)SabnzbdPriority.Default;
|
||||||
|
OlderTvPriority = (int)SabnzbdPriority.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
|
||||||
|
public String Host { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)]
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox)]
|
||||||
|
public String ApiKey { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(3, Label = "Username", Type = FieldType.Textbox)]
|
||||||
|
public String Username { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
|
||||||
|
public String Password { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox)]
|
||||||
|
public String TvCategory { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority))]
|
||||||
|
public Int32 RecentTvPriority { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority))]
|
||||||
|
public Int32 OlderTvPriority { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)]
|
||||||
|
public Boolean UseSsl { get; set; }
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
return Validator.Validate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
|
{
|
||||||
|
public class TestSabnzbdCommand : Command
|
||||||
|
{
|
||||||
|
public override bool SendUpdatesToClient
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Host { get; set; }
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
public String ApiKey { get; set; }
|
||||||
|
public String Username { get; set; }
|
||||||
|
public String Password { get; set; }
|
||||||
|
public Boolean UseSsl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public abstract class DownloadClientBase<TSettings> : IDownloadClient where TSettings : IProviderConfig, new()
|
||||||
|
{
|
||||||
|
public Type ConfigContract
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return typeof(TSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new List<ProviderDefinition>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProviderDefinition Definition { get; set; }
|
||||||
|
|
||||||
|
protected TSettings Settings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (TSettings)Definition.Settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract string DownloadNzb(RemoteEpisode remoteEpisode);
|
||||||
|
public abstract IEnumerable<QueueItem> GetQueue();
|
||||||
|
public abstract IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0);
|
||||||
|
public abstract void RemoveFromQueue(string id);
|
||||||
|
public abstract void RemoveFromHistory(string id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public class DownloadClientDefinition : ProviderDefinition
|
||||||
|
{
|
||||||
|
public Boolean Enable { get; set; }
|
||||||
|
public DownloadProtocol Protocol { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Composition;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public interface IDownloadClientFactory : IProviderFactory<IDownloadClient, DownloadClientDefinition>
|
||||||
|
{
|
||||||
|
List<IDownloadClient> Enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadClientFactory : ProviderFactory<IDownloadClient, DownloadClientDefinition>, IDownloadClientFactory
|
||||||
|
{
|
||||||
|
private readonly IDownloadClientRepository _providerRepository;
|
||||||
|
|
||||||
|
public DownloadClientFactory(IDownloadClientRepository providerRepository, IEnumerable<IDownloadClient> providers, IContainer container, Logger logger)
|
||||||
|
: base(providerRepository, providers, container, logger)
|
||||||
|
{
|
||||||
|
_providerRepository = providerRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IDownloadClient> Enabled()
|
||||||
|
{
|
||||||
|
return GetAvailableProviders().Where(n => ((DownloadClientDefinition)n.Definition).Enable).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using NzbDrone.Core.Configuration;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||||
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
||||||
|
@ -12,42 +14,16 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
public class DownloadClientProvider : IProvideDownloadClient
|
public class DownloadClientProvider : IProvideDownloadClient
|
||||||
{
|
{
|
||||||
|
private readonly IDownloadClientFactory _downloadClientFactory;
|
||||||
|
|
||||||
private readonly SabnzbdClient _sabnzbdClient;
|
public DownloadClientProvider(IDownloadClientFactory downloadClientFactory)
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly BlackholeProvider _blackholeProvider;
|
|
||||||
private readonly PneumaticClient _pneumaticClient;
|
|
||||||
private readonly NzbgetClient _nzbgetClient;
|
|
||||||
|
|
||||||
|
|
||||||
public DownloadClientProvider(SabnzbdClient sabnzbdClient, IConfigService configService,
|
|
||||||
BlackholeProvider blackholeProvider,
|
|
||||||
PneumaticClient pneumaticClient,
|
|
||||||
NzbgetClient nzbgetClient)
|
|
||||||
{
|
{
|
||||||
_sabnzbdClient = sabnzbdClient;
|
_downloadClientFactory = downloadClientFactory;
|
||||||
_configService = configService;
|
|
||||||
_blackholeProvider = blackholeProvider;
|
|
||||||
_pneumaticClient = pneumaticClient;
|
|
||||||
_nzbgetClient = nzbgetClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDownloadClient GetDownloadClient()
|
public IDownloadClient GetDownloadClient()
|
||||||
{
|
{
|
||||||
switch (_configService.DownloadClient)
|
return _downloadClientFactory.Enabled().FirstOrDefault();
|
||||||
{
|
|
||||||
case DownloadClientType.Blackhole:
|
|
||||||
return _blackholeProvider;
|
|
||||||
|
|
||||||
case DownloadClientType.Pneumatic:
|
|
||||||
return _pneumaticClient;
|
|
||||||
|
|
||||||
case DownloadClientType.Nzbget:
|
|
||||||
return _nzbgetClient;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return _sabnzbdClient;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public interface IDownloadClientRepository : IProviderRepository<DownloadClientDefinition>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadClientRepository : ProviderRepository<DownloadClientDefinition>, IDownloadClientRepository
|
||||||
|
{
|
||||||
|
public DownloadClientRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,9 +36,9 @@ namespace NzbDrone.Core.Download
|
||||||
var downloadTitle = remoteEpisode.Release.Title;
|
var downloadTitle = remoteEpisode.Release.Title;
|
||||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||||
|
|
||||||
if (!downloadClient.IsConfigured)
|
if (downloadClient == null)
|
||||||
{
|
{
|
||||||
_logger.Warn("Download client {0} isn't configured yet.", downloadClient.GetType().Name);
|
_logger.Warn("Download client isn't configured yet.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Events
|
||||||
|
{
|
||||||
|
public class DownloadFailedEvent : IEvent
|
||||||
|
{
|
||||||
|
public Int32 SeriesId { get; set; }
|
||||||
|
public List<Int32> EpisodeIds { get; set; }
|
||||||
|
public QualityModel Quality { get; set; }
|
||||||
|
public String SourceTitle { get; set; }
|
||||||
|
public String DownloadClient { get; set; }
|
||||||
|
public String DownloadClientId { get; set; }
|
||||||
|
public String Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.Events
|
||||||
|
{
|
||||||
|
public class EpisodeGrabbedEvent : IEvent
|
||||||
|
{
|
||||||
|
public RemoteEpisode Episode { get; private set; }
|
||||||
|
public String DownloadClient { get; set; }
|
||||||
|
public String DownloadClientId { get; set; }
|
||||||
|
|
||||||
|
public EpisodeGrabbedEvent(RemoteEpisode episode)
|
||||||
|
{
|
||||||
|
Episode = episode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
public interface IDownloadClient
|
public interface IDownloadClient : IProvider
|
||||||
{
|
{
|
||||||
string DownloadNzb(RemoteEpisode remoteEpisode);
|
string DownloadNzb(RemoteEpisode remoteEpisode);
|
||||||
bool IsConfigured { get; }
|
|
||||||
IEnumerable<QueueItem> GetQueue();
|
IEnumerable<QueueItem> GetQueue();
|
||||||
IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0);
|
IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0);
|
||||||
void RemoveFromQueue(string id);
|
void RemoveFromQueue(string id);
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
|
|
||||||
public enum DownloadProtocol
|
public enum DownloadProtocol
|
||||||
{
|
{
|
||||||
Usenet,
|
Usenet = 1,
|
||||||
Torrent
|
Torrent = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,9 @@
|
||||||
using System.IO;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Metadata.Files;
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.Tv.Events;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata
|
namespace NzbDrone.Core.Metadata
|
||||||
{
|
{
|
||||||
|
@ -16,10 +13,10 @@ namespace NzbDrone.Core.Metadata
|
||||||
IHandle<SeriesRenamedEvent>
|
IHandle<SeriesRenamedEvent>
|
||||||
{
|
{
|
||||||
private readonly IMetadataFactory _metadataFactory;
|
private readonly IMetadataFactory _metadataFactory;
|
||||||
private readonly MetadataFileService _metadataFileService;
|
private readonly IMetadataFileService _metadataFileService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public NotificationService(IMetadataFactory metadataFactory, MetadataFileService metadataFileService, Logger logger)
|
public NotificationService(IMetadataFactory metadataFactory, IMetadataFileService metadataFileService, Logger logger)
|
||||||
{
|
{
|
||||||
_metadataFactory = metadataFactory;
|
_metadataFactory = metadataFactory;
|
||||||
_metadataFileService = metadataFileService;
|
_metadataFileService = metadataFileService;
|
||||||
|
|
|
@ -198,6 +198,8 @@
|
||||||
<Compile Include="Datastore\Migration\040_add_metadata_to_episodes_and_series.cs" />
|
<Compile Include="Datastore\Migration\040_add_metadata_to_episodes_and_series.cs" />
|
||||||
<Compile Include="Datastore\Migration\039_add_metadata_tables.cs" />
|
<Compile Include="Datastore\Migration\039_add_metadata_tables.cs" />
|
||||||
<Compile Include="Datastore\Migration\041_fix_xbmc_season_images_metadata.cs" />
|
<Compile Include="Datastore\Migration\041_fix_xbmc_season_images_metadata.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\041_add_download_clients_table.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\042_convert_config_to_download_clients.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
||||||
|
@ -240,13 +242,27 @@
|
||||||
<Compile Include="DecisionEngine\Specifications\RssSync\HistorySpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\RssSync\HistorySpecification.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpace.cs" />
|
<Compile Include="DiskSpace\DiskSpace.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpaceService.cs" />
|
<Compile Include="DiskSpace\DiskSpaceService.cs" />
|
||||||
|
<Compile Include="Download\Clients\Blackhole\Blackhole.cs" />
|
||||||
|
<Compile Include="Download\Clients\Blackhole\TestBlackholeCommand.cs" />
|
||||||
|
<Compile Include="Download\Clients\FolderSettings.cs" />
|
||||||
|
<Compile Include="Download\Clients\Nzbget\NzbgetSettings.cs" />
|
||||||
|
<Compile Include="Download\Clients\Nzbget\TestNzbgetCommand.cs" />
|
||||||
|
<Compile Include="Download\Clients\Pneumatic\Pneumatic.cs" />
|
||||||
|
<Compile Include="Download\Clients\Pneumatic\TestPneumaticCommand.cs" />
|
||||||
|
<Compile Include="Download\Clients\Sabnzbd\Responses\SabnzbdAddResponse.cs" />
|
||||||
|
<Compile Include="Download\Clients\Sabnzbd\Responses\SabnzbdCategoryResponse.cs" />
|
||||||
|
<Compile Include="Download\Clients\Sabnzbd\Responses\SabnzbdVersionResponse.cs" />
|
||||||
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdSettings.cs" />
|
||||||
|
<Compile Include="Download\Clients\Sabnzbd\TestSabnzbdCommand.cs" />
|
||||||
|
<Compile Include="Download\DownloadClientBase.cs" />
|
||||||
|
<Compile Include="Download\DownloadClientDefinition.cs" />
|
||||||
|
<Compile Include="Download\DownloadClientFactory.cs" />
|
||||||
|
<Compile Include="Download\DownloadClientRepository.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\JsonRequest.cs" />
|
<Compile Include="Download\Clients\Nzbget\JsonRequest.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\NzbGetCommunicationProxy.cs" />
|
<Compile Include="Download\Clients\Nzbget\NzbgetProxy.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\ConnectionInfoModel.cs" />
|
|
||||||
<Compile Include="Download\Clients\Sabnzbd\JsonConverters\SabnzbdPriorityTypeConverter.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\JsonConverters\SabnzbdPriorityTypeConverter.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\JsonConverters\SabnzbdQueueTimeConverter.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\JsonConverters\SabnzbdQueueTimeConverter.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabAutoConfigureService.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdProxy.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabCommunicationProxy.cs" />
|
|
||||||
<Compile Include="Download\CheckForFailedDownloadCommand.cs" />
|
<Compile Include="Download\CheckForFailedDownloadCommand.cs" />
|
||||||
<Compile Include="Download\HistoryItem.cs" />
|
<Compile Include="Download\HistoryItem.cs" />
|
||||||
<Compile Include="Download\DownloadFailedEvent.cs" />
|
<Compile Include="Download\DownloadFailedEvent.cs" />
|
||||||
|
@ -476,10 +492,10 @@
|
||||||
<Compile Include="Download\Clients\Nzbget\EnqueueResponse.cs" />
|
<Compile Include="Download\Clients\Nzbget\EnqueueResponse.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\ErrorModel.cs" />
|
<Compile Include="Download\Clients\Nzbget\ErrorModel.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\JsonError.cs" />
|
<Compile Include="Download\Clients\Nzbget\JsonError.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\NzbGetQueue.cs" />
|
<Compile Include="Download\Clients\Nzbget\NzbgetQueue.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\NzbGetQueueItem.cs" />
|
<Compile Include="Download\Clients\Nzbget\NzbgetQueueItem.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\PriorityType.cs" />
|
<Compile Include="Download\Clients\Nzbget\NzbgetPriority.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\VersionModel.cs" />
|
<Compile Include="Download\Clients\Nzbget\VersionResponse.cs" />
|
||||||
<Compile Include="Organizer\NamingConfig.cs" />
|
<Compile Include="Organizer\NamingConfig.cs" />
|
||||||
<Compile Include="Parser\Language.cs" />
|
<Compile Include="Parser\Language.cs" />
|
||||||
<Compile Include="Parser\Model\LocalEpisode.cs" />
|
<Compile Include="Parser\Model\LocalEpisode.cs" />
|
||||||
|
@ -529,18 +545,13 @@
|
||||||
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
||||||
<Compile Include="Tv\SeriesRepository.cs" />
|
<Compile Include="Tv\SeriesRepository.cs" />
|
||||||
<Compile Include="Qualities\QualityModel.cs" />
|
<Compile Include="Qualities\QualityModel.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabAddResponse.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdHistoryItem.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabHistoryItem.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdHistory.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabHistory.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdJsonError.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabJsonError.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdQueue.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabQueue.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdQueueItem.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabCategoryModel.cs" />
|
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabModel.cs" />
|
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabQueueItem.cs" />
|
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabVersionModel.cs" />
|
|
||||||
<Compile Include="MediaCover\MediaCoverService.cs" />
|
<Compile Include="MediaCover\MediaCoverService.cs" />
|
||||||
<Compile Include="Download\Clients\Nzbget\NzbgetClient.cs" />
|
<Compile Include="Download\Clients\Nzbget\Nzbget.cs" />
|
||||||
<Compile Include="Download\Clients\PneumaticClient.cs" />
|
|
||||||
<Compile Include="MediaFiles\RecycleBinProvider.cs" />
|
<Compile Include="MediaFiles\RecycleBinProvider.cs" />
|
||||||
<Compile Include="SeriesStats\SeriesStatistics.cs" />
|
<Compile Include="SeriesStats\SeriesStatistics.cs" />
|
||||||
<Compile Include="SeriesStats\SeriesStatisticsRepository.cs" />
|
<Compile Include="SeriesStats\SeriesStatisticsRepository.cs" />
|
||||||
|
@ -556,13 +567,10 @@
|
||||||
<Compile Include="MediaFiles\DiskScanService.cs">
|
<Compile Include="MediaFiles\DiskScanService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Download\Clients\BlackholeProvider.cs">
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Download\IDownloadClient.cs">
|
<Compile Include="Download\IDownloadClient.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabnzbdClient.cs">
|
<Compile Include="Download\Clients\Sabnzbd\Sabnzbd.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Download\DownloadService.cs">
|
<Compile Include="Download\DownloadService.cs">
|
||||||
|
@ -631,7 +639,7 @@
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\NotificationDefinition.cs" />
|
<Compile Include="Notifications\NotificationDefinition.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabPriorityType.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabnzbdPriority.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeFile.cs" />
|
<Compile Include="MediaFiles\EpisodeFile.cs" />
|
||||||
<Compile Include="Tv\Episode.cs" />
|
<Compile Include="Tv\Episode.cs" />
|
||||||
<Compile Include="Instrumentation\Log.cs" />
|
<Compile Include="Instrumentation\Log.cs" />
|
||||||
|
|
|
@ -23,6 +23,13 @@ namespace NzbDrone.Core.Queue
|
||||||
public List<Queue> GetQueue()
|
public List<Queue> GetQueue()
|
||||||
{
|
{
|
||||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||||
|
|
||||||
|
if (downloadClient == null)
|
||||||
|
{
|
||||||
|
_logger.Trace("Download client is not configured.");
|
||||||
|
return new List<Queue>();
|
||||||
|
}
|
||||||
|
|
||||||
var queueItems = downloadClient.GetQueue();
|
var queueItems = downloadClient.GetQueue();
|
||||||
|
|
||||||
return MapQueue(queueItems);
|
return MapQueue(queueItems);
|
||||||
|
|
|
@ -97,6 +97,8 @@ namespace NzbDrone.Core.Tv
|
||||||
return FindByTvdbId(tvdbId.Value);
|
return FindByTvdbId(tvdbId.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clean = Parser.Parser.CleanSeriesTitle(title);
|
||||||
|
|
||||||
return _seriesRepository.FindByTitle(Parser.Parser.CleanSeriesTitle(title));
|
return _seriesRepository.FindByTitle(Parser.Parser.CleanSeriesTitle(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
<option es3="false" />
|
<option es3="false" />
|
||||||
<option forin="true" />
|
<option forin="true" />
|
||||||
<option immed="true" />
|
<option immed="true" />
|
||||||
|
<option latedef="true" />
|
||||||
<option newcap="true" />
|
<option newcap="true" />
|
||||||
<option noarg="true" />
|
<option noarg="true" />
|
||||||
<option noempty="false" />
|
<option noempty="false" />
|
||||||
<option nonew="true" />
|
<option nonew="true" />
|
||||||
<option plusplus="false" />
|
<option plusplus="false" />
|
||||||
<option undef="true" />
|
<option undef="true" />
|
||||||
|
<option unused="true" />
|
||||||
<option strict="true" />
|
<option strict="true" />
|
||||||
<option trailing="false" />
|
<option trailing="false" />
|
||||||
<option latedef="true" />
|
|
||||||
<option unused="true" />
|
|
||||||
<option quotmark="single" />
|
<option quotmark="single" />
|
||||||
<option maxdepth="3" />
|
<option maxdepth="3" />
|
||||||
<option asi="false" />
|
<option asi="false" />
|
||||||
|
|
|
@ -35,6 +35,13 @@ define(
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field.type === 'path') {
|
||||||
|
return _templateRenderer.apply(field,
|
||||||
|
[
|
||||||
|
'Form/PathTemplate'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return _templateRenderer.apply(field,
|
return _templateRenderer.apply(field,
|
||||||
[
|
[
|
||||||
'Form/TextboxTemplate'
|
'Form/TextboxTemplate'
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">{{label}}</label>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="fields.{{order}}.value" validation-name="{{name}}" class="x-path"/>
|
||||||
|
{{#if helpText}}
|
||||||
|
<span class="help-inline">
|
||||||
|
<i class="icon-nd-form-info" title="{{helpText}}"/>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define([
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/Add/DownloadClientAddItemView'
|
||||||
|
], function (Marionette, AddItemView) {
|
||||||
|
|
||||||
|
return Marionette.CompositeView.extend({
|
||||||
|
itemView : AddItemView,
|
||||||
|
itemViewContainer: '.add-download-client .items',
|
||||||
|
template : 'Settings/DownloadClient/Add/DownloadClientAddCollectionViewTemplate',
|
||||||
|
|
||||||
|
itemViewOptions: function () {
|
||||||
|
return {
|
||||||
|
downloadClientCollection: this.downloadClientCollection
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
this.downloadClientCollection = options.downloadClientCollection;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h3>Add Download Client</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="add-download-client add-thingies">
|
||||||
|
<ul class="items"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn" data-dismiss="modal">close</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,38 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define([
|
||||||
|
'AppLayout',
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/Edit/DownloadClientEditView'
|
||||||
|
], function (AppLayout, Marionette, EditView) {
|
||||||
|
|
||||||
|
return Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/DownloadClient/Add/DownloadClientAddItemViewTemplate',
|
||||||
|
tagName : 'li',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click': '_add'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
this.downloadClientCollection = options.downloadClientCollection;
|
||||||
|
},
|
||||||
|
|
||||||
|
_add: function (e) {
|
||||||
|
if (this.$(e.target).hasClass('icon-info-sign')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.model.set({
|
||||||
|
id : undefined,
|
||||||
|
name : this.model.get('implementationName'),
|
||||||
|
onGrab : true,
|
||||||
|
onDownload : true,
|
||||||
|
onUpgrade : true
|
||||||
|
});
|
||||||
|
|
||||||
|
var editView = new EditView({ model: this.model, downloadClientCollection: this.downloadClientCollection });
|
||||||
|
AppLayout.modalRegion.show(editView);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="add-thingy span3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span3">
|
||||||
|
{{implementation}}
|
||||||
|
{{#if link}}
|
||||||
|
<a href="{{link}}"><i class="icon-info-sign"/></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use strict';
|
||||||
|
define([
|
||||||
|
'AppLayout',
|
||||||
|
'Settings/DownloadClient/DownloadClientCollection',
|
||||||
|
'Settings/DownloadClient/Add/DownloadClientAddCollectionView'
|
||||||
|
], function (AppLayout, DownloadClientCollection, DownloadClientAddCollectionView) {
|
||||||
|
return ({
|
||||||
|
|
||||||
|
open: function (collection) {
|
||||||
|
var schemaCollection = new DownloadClientCollection();
|
||||||
|
var originalUrl = schemaCollection.url;
|
||||||
|
schemaCollection.url = schemaCollection.url + '/schema';
|
||||||
|
schemaCollection.fetch();
|
||||||
|
schemaCollection.url = originalUrl;
|
||||||
|
|
||||||
|
var view = new DownloadClientAddCollectionView({ collection: schemaCollection, downloadClientCollection: collection});
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,24 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'marionette',
|
|
||||||
'Mixins/AsModelBoundView',
|
|
||||||
'Mixins/AutoComplete',
|
|
||||||
'bootstrap'
|
|
||||||
], function (Marionette, AsModelBoundView) {
|
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
|
||||||
template : 'Settings/DownloadClient/BlackholeViewTemplate',
|
|
||||||
|
|
||||||
ui: {
|
|
||||||
'blackholeFolder': '.x-path'
|
|
||||||
},
|
|
||||||
|
|
||||||
onShow: function () {
|
|
||||||
this.ui.blackholeFolder.autoComplete('/directories');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return AsModelBoundView.call(view);
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
<fieldset>
|
|
||||||
<legend>Blackhole</legend>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Blackhole Folder</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" name="blackholeFolder" class="x-path"/>
|
|
||||||
<span class="help-inline">
|
|
||||||
<i class="icon-nd-form-info" title="The folder where your download client will pickup .nzb files"/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'vent',
|
||||||
|
'marionette'
|
||||||
|
], function (vent, Marionette) {
|
||||||
|
return Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/DownloadClient/Delete/DownloadClientDeleteViewTemplate',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-confirm-delete': '_delete'
|
||||||
|
},
|
||||||
|
|
||||||
|
_delete: function () {
|
||||||
|
this.model.destroy({
|
||||||
|
wait : true,
|
||||||
|
success: function () {
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h3>Delete Download Client</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Are you sure you want to delete '{{name}}'?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn" data-dismiss="modal">cancel</button>
|
||||||
|
<button class="btn btn-danger x-confirm-delete">delete</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,12 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone',
|
||||||
|
'Settings/DownloadClient/DownloadClientModel'
|
||||||
|
], function (Backbone, DownloadClientModel) {
|
||||||
|
|
||||||
|
return Backbone.Collection.extend({
|
||||||
|
model: DownloadClientModel,
|
||||||
|
url : window.NzbDrone.ApiRoot + '/downloadclient'
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,31 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'underscore',
|
||||||
|
'AppLayout',
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/DownloadClientItemView',
|
||||||
|
'Settings/DownloadClient/Add/SchemaModal'
|
||||||
|
], function (_, AppLayout, Marionette, DownloadClientItemView, SchemaModal) {
|
||||||
|
return Marionette.CompositeView.extend({
|
||||||
|
itemView : DownloadClientItemView,
|
||||||
|
itemViewContainer: '#x-download-clients',
|
||||||
|
template : 'Settings/DownloadClient/DownloadClientCollectionViewTemplate',
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
'addCard': '.x-add-card'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-add-card': '_openSchemaModal'
|
||||||
|
},
|
||||||
|
|
||||||
|
appendHtml: function (collectionView, itemView, index) {
|
||||||
|
collectionView.ui.addCard.parent('li').before(itemView.el);
|
||||||
|
},
|
||||||
|
|
||||||
|
_openSchemaModal: function () {
|
||||||
|
SchemaModal.open(this.collection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
<fieldset>
|
||||||
|
<legend>Download Clients</legend>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span12">
|
||||||
|
<ul id="x-download-clients" class="download-client-list">
|
||||||
|
<li>
|
||||||
|
<div class="download-client-item thingy add-card x-add-card">
|
||||||
|
<span class="center well">
|
||||||
|
<i class="icon-plus" title="Add Download Client"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
|
@ -0,0 +1,34 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'AppLayout',
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/Edit/DownloadClientEditView',
|
||||||
|
'Settings/DownloadClient/Delete/DownloadClientDeleteView'
|
||||||
|
], function (AppLayout, Marionette, EditView, DeleteView) {
|
||||||
|
|
||||||
|
return Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/DownloadClient/DownloadClientItemViewTemplate',
|
||||||
|
tagName : 'li',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-edit' : '_edit',
|
||||||
|
'click .x-delete' : '_delete'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
|
this.listenTo(this.model, 'sync', this.render);
|
||||||
|
},
|
||||||
|
|
||||||
|
_edit: function () {
|
||||||
|
var view = new EditView({ model: this.model});
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
},
|
||||||
|
|
||||||
|
_delete: function () {
|
||||||
|
var view = new DeleteView({ model: this.model});
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="download-client-item thingy">
|
||||||
|
<div>
|
||||||
|
<h3>{{name}}</h3>
|
||||||
|
<span class="btn-group pull-right">
|
||||||
|
<button class="btn btn-mini btn-icon-only x-edit"><i class="icon-nd-edit"/></button>
|
||||||
|
<button class="btn btn-mini btn-icon-only x-delete"><i class="icon-nd-delete"/></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings">
|
||||||
|
{{#if enable}}
|
||||||
|
<span class="label label-success">Enabled</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="label">Not Enabled</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,40 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/DownloadClientCollection',
|
||||||
|
'Settings/DownloadClient/DownloadClientCollectionView',
|
||||||
|
'Mixins/AsModelBoundView',
|
||||||
|
'Mixins/AutoComplete',
|
||||||
|
'bootstrap'
|
||||||
|
], function (Marionette, DownloadClientCollection, DownloadClientCollectionView, AsModelBoundView) {
|
||||||
|
|
||||||
|
var view = Marionette.Layout.extend({
|
||||||
|
template : 'Settings/DownloadClient/DownloadClientLayoutTemplate',
|
||||||
|
|
||||||
|
regions: {
|
||||||
|
downloadClients: '#x-download-clients-region'
|
||||||
|
},
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
droneFactory: '.x-path'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'change .x-download-client': 'downloadClientChanged'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
|
this.downloadClientCollection = new DownloadClientCollection();
|
||||||
|
this.downloadClientCollection.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow: function () {
|
||||||
|
this.downloadClients.show(new DownloadClientCollectionView({ collection: this.downloadClientCollection }));
|
||||||
|
this.ui.droneFactory.autoComplete('/directories');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return AsModelBoundView.call(view);
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div id="x-download-clients-region"></div>
|
||||||
|
|
||||||
|
<fieldset class="form-horizontal">
|
||||||
|
<legend>Options</legend>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Drone Factory</label>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="downloadedEpisodesFolder" class="x-path"/>
|
||||||
|
<span class="help-inline">
|
||||||
|
<i class="icon-nd-form-info" title="The folder where your download client downloads TV shows to (Completed Download Directory)"/>
|
||||||
|
<i class="icon-nd-form-warning" title="Do not use the folder that contains some or all of your sorted and named TV shows - doing so could cause data loss"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
|
@ -0,0 +1,10 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone.deepmodel'
|
||||||
|
], function (DeepModel) {
|
||||||
|
return DeepModel.DeepModel.extend({
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'vent',
|
||||||
|
'AppLayout',
|
||||||
|
'marionette',
|
||||||
|
'Settings/DownloadClient/Delete/DownloadClientDeleteView',
|
||||||
|
'Commands/CommandController',
|
||||||
|
'Mixins/AsModelBoundView',
|
||||||
|
'underscore',
|
||||||
|
'Form/FormBuilder',
|
||||||
|
'Mixins/AutoComplete',
|
||||||
|
'bootstrap'
|
||||||
|
], function (vent, AppLayout, Marionette, DeleteView, CommandController, AsModelBoundView, _) {
|
||||||
|
|
||||||
|
var model = Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/DownloadClient/Edit/DownloadClientEditViewTemplate',
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
path : '.x-path',
|
||||||
|
modalBody : '.modal-body'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-save' : '_save',
|
||||||
|
'click .x-save-and-add': '_saveAndAdd',
|
||||||
|
'click .x-delete' : '_delete',
|
||||||
|
'click .x-back' : '_back',
|
||||||
|
'click .x-test' : '_test'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
this.downloadClientCollection = options.downloadClientCollection;
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow: function () {
|
||||||
|
//Hack to deal with modals not overflowing
|
||||||
|
if (this.ui.path.length > 0) {
|
||||||
|
this.ui.modalBody.addClass('modal-overflow');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.path.autoComplete('/directories');
|
||||||
|
},
|
||||||
|
|
||||||
|
_save: function () {
|
||||||
|
var self = this;
|
||||||
|
var promise = this.model.save();
|
||||||
|
|
||||||
|
if (promise) {
|
||||||
|
promise.done(function () {
|
||||||
|
self.downloadClientCollection.add(self.model, { merge: true });
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_saveAndAdd: function () {
|
||||||
|
var self = this;
|
||||||
|
var promise = this.model.save();
|
||||||
|
|
||||||
|
if (promise) {
|
||||||
|
promise.done(function () {
|
||||||
|
self.notificationCollection.add(self.model, { merge: true });
|
||||||
|
|
||||||
|
require('Settings/DownloadClient/Add/SchemaModal').open(self.downloadClientCollection);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_delete: function () {
|
||||||
|
var view = new DeleteView({ model: this.model });
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
},
|
||||||
|
|
||||||
|
_back: function () {
|
||||||
|
require('Settings/DownloadClient/Add/SchemaModal').open(this.downloadClientCollection);
|
||||||
|
},
|
||||||
|
|
||||||
|
_test: function () {
|
||||||
|
var testCommand = 'test{0}'.format(this.model.get('implementation'));
|
||||||
|
var properties = {};
|
||||||
|
|
||||||
|
_.each(this.model.get('fields'), function (field) {
|
||||||
|
properties[field.name] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
CommandController.Execute(testCommand, properties);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return AsModelBoundView.call(model);
|
||||||
|
});
|
|
@ -0,0 +1,59 @@
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
{{#if id}}
|
||||||
|
<h3>Edit - {{implementation}}</h3>
|
||||||
|
{{else}}
|
||||||
|
<h3>Add - {{implementation}}</h3>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="modal-body download-client-modal">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Name</label>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="name"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Enable</label>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<label class="checkbox toggle well">
|
||||||
|
<input type="checkbox" name="enable"/>
|
||||||
|
<p>
|
||||||
|
<span>Yes</span>
|
||||||
|
<span>No</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="btn btn-primary slide-button"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{formBuilder}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{#if id}}
|
||||||
|
<button class="btn btn-danger pull-left x-delete">delete</button>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn pull-left x-back">back</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<button class="btn x-test">test <i class="x-test-icon icon-nd-test"/></button>
|
||||||
|
<button class="btn" data-dismiss="modal">cancel</button>
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-primary x-save">save</button>
|
||||||
|
<button class="btn btn-icon-only btn-primary dropdown-toggle" data-toggle="dropdown">
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li class="save-and-add x-save-and-add">
|
||||||
|
save and add
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,78 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'marionette',
|
|
||||||
'Settings/DownloadClient/SabView',
|
|
||||||
'Settings/DownloadClient/BlackholeView',
|
|
||||||
'Settings/DownloadClient/PneumaticView',
|
|
||||||
'Settings/DownloadClient/NzbgetView',
|
|
||||||
'Mixins/AsModelBoundView',
|
|
||||||
'Mixins/AutoComplete',
|
|
||||||
'bootstrap'
|
|
||||||
], function (Marionette, SabView, BlackholeView, PneumaticView, NzbgetView, AsModelBoundView) {
|
|
||||||
|
|
||||||
var view = Marionette.Layout.extend({
|
|
||||||
template : 'Settings/DownloadClient/LayoutTemplate',
|
|
||||||
|
|
||||||
regions: {
|
|
||||||
downloadClient: '#download-client-settings-region'
|
|
||||||
},
|
|
||||||
|
|
||||||
ui: {
|
|
||||||
downloadClientSelect: '.x-download-client',
|
|
||||||
downloadedEpisodesFolder: '.x-path'
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'change .x-download-client': 'downloadClientChanged'
|
|
||||||
},
|
|
||||||
|
|
||||||
onShow: function () {
|
|
||||||
this.sabView = new SabView({ model: this.model});
|
|
||||||
this.blackholeView = new BlackholeView({ model: this.model});
|
|
||||||
this.pneumaticView = new PneumaticView({ model: this.model});
|
|
||||||
this.nzbgetView = new NzbgetView({ model: this.model});
|
|
||||||
|
|
||||||
this.ui.downloadedEpisodesFolder.autoComplete('/directories');
|
|
||||||
|
|
||||||
var client = this.model.get('downloadClient');
|
|
||||||
this.refreshUIVisibility(client);
|
|
||||||
},
|
|
||||||
|
|
||||||
downloadClientChanged: function () {
|
|
||||||
var clientId = this.ui.downloadClientSelect.val();
|
|
||||||
this.refreshUIVisibility(clientId);
|
|
||||||
},
|
|
||||||
|
|
||||||
refreshUIVisibility: function (clientId) {
|
|
||||||
|
|
||||||
if (!clientId) {
|
|
||||||
clientId = 'sabnzbd';
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (clientId.toString()) {
|
|
||||||
case 'sabnzbd':
|
|
||||||
this.downloadClient.show(this.sabView);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'blackhole':
|
|
||||||
this.downloadClient.show(this.blackholeView);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'pneumatic':
|
|
||||||
this.downloadClient.show(this.pneumaticView);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'nzbget':
|
|
||||||
this.downloadClient.show(this.nzbgetView);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default :
|
|
||||||
throw 'unknown download client id' + clientId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return AsModelBoundView.call(view);
|
|
||||||
});
|
|
|
@ -1,29 +0,0 @@
|
||||||
<fieldset class="form-horizontal">
|
|
||||||
<legend>General</legend>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Download Client</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<select class="inputClass x-download-client" name="downloadClient">
|
|
||||||
<option value="sabnzbd">SABnzbd</option>
|
|
||||||
<option value="blackhole">Blackhole</option>
|
|
||||||
<option value="pneumatic">Pneumatic</option>
|
|
||||||
<option value="nzbget">NZBGet</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Drone Factory</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" name="downloadedEpisodesFolder" class="x-path"/>
|
|
||||||
<span class="help-inline">
|
|
||||||
<i class="icon-nd-form-info" title="The folder where your download client downloads TV shows to (Completed Download Directory)"/>
|
|
||||||
<i class="icon-nd-form-warning" title="Do not use the folder that contains some or all of your sorted and named TV shows - doing so could cause data loss"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div id="download-client-settings-region" class="form-horizontal"></div>
|
|
|
@ -1,15 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'marionette',
|
|
||||||
'Mixins/AsModelBoundView',
|
|
||||||
'bootstrap'
|
|
||||||
], function (Marionette, AsModelBoundView) {
|
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
|
||||||
template : 'Settings/DownloadClient/NzbgetViewTemplate'
|
|
||||||
});
|
|
||||||
|
|
||||||
return AsModelBoundView.call(view);
|
|
||||||
});
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue