XbmcProvider updated to include new Json API methods.
EventClient is used for sending CleanLibrary and Notifications (With NzbDrone Logo - Internal Resource). Support for Dharma's HTTP Server (Deprecated), since Dharma doesn't support Json as well.
This commit is contained in:
parent
5bbc9a6f59
commit
348ff5a386
|
@ -0,0 +1,103 @@
|
|||
// ReSharper disable RedundantUsingDirective
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AutoMoq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Model.Xbmc;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Providers.Xbmc;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test
|
||||
{
|
||||
[TestFixture]
|
||||
// ReSharper disable InconsistentNaming
|
||||
public class EventClientProviderTest : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void SendNotification_true()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var header = "NzbDrone Test";
|
||||
var message = "Test Message!";
|
||||
var address = "localhost";
|
||||
|
||||
var fakeUdp = mocker.GetMock<UdpProvider>();
|
||||
fakeUdp.Setup(s => s.Send(address, UdpProvider.PacketType.Notification, It.IsAny<byte[]>())).Returns(true);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<EventClientProvider>().SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", address);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(true, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendNotification_false()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var header = "NzbDrone Test";
|
||||
var message = "Test Message!";
|
||||
var address = "localhost";
|
||||
|
||||
var fakeUdp = mocker.GetMock<UdpProvider>();
|
||||
fakeUdp.Setup(s => s.Send(address, UdpProvider.PacketType.Notification, It.IsAny<byte[]>())).Returns(false);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<EventClientProvider>().SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", address);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(false, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendAction_Update_true()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var path = @"C:\Test\TV\30 Rock";
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path);
|
||||
var address = "localhost";
|
||||
|
||||
var fakeUdp = mocker.GetMock<UdpProvider>();
|
||||
fakeUdp.Setup(s => s.Send(address, UdpProvider.PacketType.Action, It.IsAny<byte[]>())).Returns(true);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<EventClientProvider>().SendAction(address, ActionType.ExecBuiltin, command);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(true, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendAction_Update_false()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var path = @"C:\Test\TV\30 Rock";
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path);
|
||||
var address = "localhost";
|
||||
|
||||
var fakeUdp = mocker.GetMock<UdpProvider>();
|
||||
fakeUdp.Setup(s => s.Send(address, UdpProvider.PacketType.Action, It.IsAny<byte[]>())).Returns(false);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<EventClientProvider>().SendAction(address, ActionType.ExecBuiltin, command);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(false, result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,6 +85,8 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="EventClientProviderTest.cs" />
|
||||
<Compile Include="XbmcProviderTest.cs" />
|
||||
<Compile Include="DiskScanProviderTest.cs" />
|
||||
<Compile Include="EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
||||
<Compile Include="DiskScanProviderTest_ImportFile.cs" />
|
||||
|
|
|
@ -0,0 +1,399 @@
|
|||
// ReSharper disable RedundantUsingDirective
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AutoMoq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Model.Xbmc;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Providers.Xbmc;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test
|
||||
{
|
||||
[TestFixture]
|
||||
// ReSharper disable InconsistentNaming
|
||||
public class XbmcProviderTest : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void JsonEror_true()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
var response = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().CheckForJsonError(response);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(true, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JsonEror_false()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
var reposnse = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":3}}";
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().CheckForJsonError(reposnse);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(false, result);
|
||||
}
|
||||
|
||||
[TestCase(3)]
|
||||
[TestCase(2)]
|
||||
[TestCase(0)]
|
||||
public void GetJsonVersion(int number)
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":" + number + "}}";
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||
.Returns(message);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetJsonVersion("localhost:8080", "xbmc", "xbmc");
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(number, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetJsonVersion_error()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var message = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||
.Returns(message);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetJsonVersion("localhost:8080", "xbmc", "xbmc");
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(0, result);
|
||||
}
|
||||
|
||||
[TestCase(false, false, false)]
|
||||
[TestCase(true, true, true)]
|
||||
[TestCase(true, false, false)]
|
||||
[TestCase(true, true, false)]
|
||||
[TestCase(false, true, false)]
|
||||
[TestCase(false, true, true)]
|
||||
[TestCase(false, false, true)]
|
||||
[TestCase(true, false, true)]
|
||||
public void GetActivePlayers(bool audio, bool picture, bool video)
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"audio\":"
|
||||
+ audio.ToString().ToLower()
|
||||
+ ",\"picture\":"
|
||||
+ picture.ToString().ToLower()
|
||||
+ ",\"video\":"
|
||||
+ video.ToString().ToLower()
|
||||
+ "}}";
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||
.Returns(message);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetActivePlayers("localhost:8080", "xbmc", "xbmc");
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(audio, result["audio"]);
|
||||
Assert.AreEqual(picture, result["picture"]);
|
||||
Assert.AreEqual(video, result["video"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetTvShowsJson()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"limits\":{\"end\":5,\"start\":0,\"total\":5},\"tvshows\":[{\"file\":\"smb://HOMESERVER/TV/7th Heaven/\",\"imdbnumber\":\"73928\",\"label\":\"7th Heaven\",\"tvshowid\":3},{\"file\":\"smb://HOMESERVER/TV/8 Simple Rules/\",\"imdbnumber\":\"78461\",\"label\":\"8 Simple Rules\",\"tvshowid\":4},{\"file\":\"smb://HOMESERVER/TV/24-7 Penguins-Capitals- Road to the NHL Winter Classic/\",\"imdbnumber\":\"213041\",\"label\":\"24/7 Penguins/Capitals: Road to the NHL Winter Classic\",\"tvshowid\":1},{\"file\":\"smb://HOMESERVER/TV/30 Rock/\",\"imdbnumber\":\"79488\",\"label\":\"30 Rock\",\"tvshowid\":2},{\"file\":\"smb://HOMESERVER/TV/90210/\",\"imdbnumber\":\"82716\",\"label\":\"90210\",\"tvshowid\":5}]}}";
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||
.Returns(message);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetTvShowsJson("localhost:8080", "xbmc", "xbmc");
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(5, result.Count);
|
||||
result.Should().Contain(s => s.ImdbNumber == 79488);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Notify_true()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var header = "NzbDrone Test";
|
||||
var message = "Test Message!";
|
||||
|
||||
var fakeConfig = mocker.GetMock<ConfigProvider>();
|
||||
fakeConfig.SetupGet(s => s.XbmcHosts).Returns("localhost:8080");
|
||||
|
||||
//var fakeUdpProvider = mocker.GetMock<EventClient>();
|
||||
var fakeEventClient = mocker.GetMock<EventClientProvider>();
|
||||
fakeEventClient.Setup(s => s.SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", "localhost")).Returns(true);
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().Notify(header, message);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendCommand()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var host = "localhost:8080";
|
||||
var command = "ExecBuiltIn(CleanLibrary(video))";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
|
||||
var url = String.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(CleanLibrary(video))");
|
||||
|
||||
//var fakeUdpProvider = mocker.GetMock<EventClient>();
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.DownloadString(url, username, password)).Returns("Ok\n");
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().SendCommand(host, command, username, username);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
Assert.AreEqual("Ok\n", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetXbmcSeriesPath_true()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>";
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
|
||||
var setResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
||||
var resetResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat()";
|
||||
var query = String.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)");
|
||||
|
||||
|
||||
//var fakeUdpProvider = mocker.GetMock<EventClient>();
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.DownloadString(setResponseUrl, username, password)).Returns("<xml><tag>OK</xml>");
|
||||
fakeHttp.Setup(s => s.DownloadString(resetResponseUrl, username, password)).Returns(@"<html>
|
||||
<li>OK
|
||||
</html>");
|
||||
fakeHttp.Setup(s => s.DownloadString(query, username, password)).Returns(queryResult);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetXbmcSeriesPath(host, 79488, username, username);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
Assert.AreEqual("smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetXbmcSeriesPath_false()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var queryResult = @"<xml></xml>";
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
|
||||
var setResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
||||
var resetResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat()";
|
||||
var query = String.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)");
|
||||
|
||||
|
||||
//var fakeUdpProvider = mocker.GetMock<EventClient>();
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.DownloadString(setResponseUrl, username, password)).Returns("<xml><tag>OK</xml>");
|
||||
fakeHttp.Setup(s => s.DownloadString(resetResponseUrl, username, password)).Returns(@"<html>
|
||||
<li>OK
|
||||
</html>");
|
||||
fakeHttp.Setup(s => s.DownloadString(query, username, password)).Returns(queryResult);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<XbmcProvider>().GetXbmcSeriesPath(host, 79488, username, username);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
Assert.AreEqual("", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Clean()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var fakeConfig = mocker.GetMock<ConfigProvider>();
|
||||
fakeConfig.SetupGet(s => s.XbmcHosts).Returns("localhost:8080");
|
||||
|
||||
var fakeEventClient = mocker.GetMock<EventClientProvider>();
|
||||
fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(CleanLibrary(video))")).Returns(true);
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().Clean();
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateWithHttp_Single()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Default);
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
var queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>";
|
||||
var queryUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)";
|
||||
var url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video,smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/))";
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.SeriesId = 79488)
|
||||
.With(s => s.Title = "30 Rock")
|
||||
.Build();
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.DownloadString(queryUrl, username, password)).Returns(queryResult);
|
||||
fakeHttp.Setup(s => s.DownloadString(url, username, password));
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().UpdateWithHttp(fakeSeries, host, username, password);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateWithHttp_All()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer(MockBehavior.Default);
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
var queryResult = @"<xml></xml>";
|
||||
var queryUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)";
|
||||
var url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video))";
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.SeriesId = 79488)
|
||||
.With(s => s.Title = "30 Rock")
|
||||
.Build();
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.DownloadString(queryUrl, username, password)).Returns(queryResult);
|
||||
fakeHttp.Setup(s => s.DownloadString(url, username, password));
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().UpdateWithHttp(fakeSeries, host, username, password);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateWithJson_Single()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
var serializedQuery = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"fields\":[\"file\",\"imdbnumber\"]},\"id\":10}";
|
||||
var tvshows = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"limits\":{\"end\":5,\"start\":0,\"total\":5},\"tvshows\":[{\"file\":\"smb://HOMESERVER/TV/7th Heaven/\",\"imdbnumber\":\"73928\",\"label\":\"7th Heaven\",\"tvshowid\":3},{\"file\":\"smb://HOMESERVER/TV/8 Simple Rules/\",\"imdbnumber\":\"78461\",\"label\":\"8 Simple Rules\",\"tvshowid\":4},{\"file\":\"smb://HOMESERVER/TV/24-7 Penguins-Capitals- Road to the NHL Winter Classic/\",\"imdbnumber\":\"213041\",\"label\":\"24/7 Penguins/Capitals: Road to the NHL Winter Classic\",\"tvshowid\":1},{\"file\":\"smb://HOMESERVER/TV/30 Rock/\",\"imdbnumber\":\"79488\",\"label\":\"30 Rock\",\"tvshowid\":2},{\"file\":\"smb://HOMESERVER/TV/90210/\",\"imdbnumber\":\"82716\",\"label\":\"90210\",\"tvshowid\":5}]}}";
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.SeriesId = 79488)
|
||||
.With(s => s.Title = "30 Rock")
|
||||
.Build();
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, serializedQuery))
|
||||
.Returns(tvshows);
|
||||
|
||||
var fakeEventClient = mocker.GetMock<EventClientProvider>();
|
||||
fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(UpdateLibrary(video,smb://HOMESERVER/TV/30 Rock/))"));
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().UpdateWithJson(fakeSeries, host, username, password);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateWithJson_All()
|
||||
{
|
||||
//Setup
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var host = "localhost:8080";
|
||||
var username = "xbmc";
|
||||
var password = "xbmc";
|
||||
var serializedQuery = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"fields\":[\"file\",\"imdbnumber\"]},\"id\":10}";
|
||||
var tvshows = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"limits\":{\"end\":5,\"start\":0,\"total\":5},\"tvshows\":[{\"file\":\"smb://HOMESERVER/TV/7th Heaven/\",\"imdbnumber\":\"73928\",\"label\":\"7th Heaven\",\"tvshowid\":3},{\"file\":\"smb://HOMESERVER/TV/8 Simple Rules/\",\"imdbnumber\":\"78461\",\"label\":\"8 Simple Rules\",\"tvshowid\":4},{\"file\":\"smb://HOMESERVER/TV/24-7 Penguins-Capitals- Road to the NHL Winter Classic/\",\"imdbnumber\":\"213041\",\"label\":\"24/7 Penguins/Capitals: Road to the NHL Winter Classic\",\"tvshowid\":1},{\"file\":\"smb://HOMESERVER/TV/90210/\",\"imdbnumber\":\"82716\",\"label\":\"90210\",\"tvshowid\":5}]}}";
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.SeriesId = 79488)
|
||||
.With(s => s.Title = "30 Rock")
|
||||
.Build();
|
||||
|
||||
var fakeHttp = mocker.GetMock<HttpProvider>();
|
||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, serializedQuery))
|
||||
.Returns(tvshows);
|
||||
|
||||
var fakeEventClient = mocker.GetMock<EventClientProvider>();
|
||||
fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(UpdateLibrary(video))"));
|
||||
|
||||
//Act
|
||||
mocker.Resolve<XbmcProvider>().UpdateWithJson(fakeSeries, host, username, password);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public enum ActionType
|
||||
{
|
||||
ExecBuiltin = 0x01,
|
||||
Button = 0x02
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class ActivePlayersResult
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string JsonRpc { get; set; }
|
||||
public Dictionary<string, bool> Result { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class Command
|
||||
{
|
||||
public string jsonrpc
|
||||
{
|
||||
get { return "2.0"; }
|
||||
}
|
||||
|
||||
public string method { get; set; }
|
||||
public Params @params { get; set; }
|
||||
public long id { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class ErrorResult
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string JsonRpc { get; set; }
|
||||
public Dictionary<string, string> Error { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public enum IconType
|
||||
{
|
||||
None = 0x00,
|
||||
Jpeg = 0x01,
|
||||
Png = 0x02,
|
||||
Gif = 0x03
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class Params
|
||||
{
|
||||
public string[] fields { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class TvShow
|
||||
{
|
||||
public int TvShowId { get; set; }
|
||||
public string Label { get; set; }
|
||||
public int ImdbNumber { get; set; }
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class TvShowResult
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string JsonRpc { get; set; }
|
||||
public Dictionary<string, List<TvShow>> Result { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Model.Xbmc
|
||||
{
|
||||
public class VersionResult
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string JsonRpc { get; set; }
|
||||
public Dictionary<string, int> Result { get; set; }
|
||||
}
|
||||
}
|
|
@ -191,6 +191,18 @@
|
|||
<Compile Include="Model\LanguageType.cs" />
|
||||
<Compile Include="Model\Quality.cs" />
|
||||
<Compile Include="Model\SabnzbdInfoModel.cs" />
|
||||
<Compile Include="Model\Xbmc\ActionType.cs" />
|
||||
<Compile Include="Model\Xbmc\ActivePlayersResult.cs" />
|
||||
<Compile Include="Model\Xbmc\ErrorResult.cs" />
|
||||
<Compile Include="Model\Xbmc\IconType.cs" />
|
||||
<Compile Include="Providers\Core\UdpProvider.cs" />
|
||||
<None Include="Providers\Xbmc\EventClient_old.cs" />
|
||||
<Compile Include="Providers\Xbmc\ResourceManager.cs" />
|
||||
<Compile Include="Model\Xbmc\TvShowResult.cs" />
|
||||
<Compile Include="Model\Xbmc\Params.cs" />
|
||||
<Compile Include="Model\Xbmc\Command.cs" />
|
||||
<Compile Include="Model\Xbmc\TvShow.cs" />
|
||||
<Compile Include="Model\Xbmc\VersionResult.cs" />
|
||||
<Compile Include="Providers\DiskScanProvider.cs" />
|
||||
<Compile Include="Providers\DownloadProvider.cs" />
|
||||
<Compile Include="Providers\ExternalNotification\ExternalNotificationProviderBase.cs" />
|
||||
|
@ -213,6 +225,7 @@
|
|||
<Compile Include="Providers\Jobs\RssSyncJob.cs" />
|
||||
<Compile Include="Providers\Jobs\UpdateInfoJob.cs" />
|
||||
<Compile Include="Providers\SceneMappingProvider.cs" />
|
||||
<Compile Include="Providers\Xbmc\EventClientProvider.cs" />
|
||||
<Compile Include="Repository\ExternalNotificationSetting.cs" />
|
||||
<Compile Include="Repository\JobSetting.cs" />
|
||||
<Compile Include="Repository\IndexerSetting.cs" />
|
||||
|
@ -292,6 +305,9 @@
|
|||
<ItemGroup>
|
||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="NzbDrone.jpg" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -120,13 +120,6 @@ namespace NzbDrone.Core.Providers.Core
|
|||
set { SetValue("DownloadPropers", value); }
|
||||
}
|
||||
|
||||
public virtual Int32 Retention
|
||||
{
|
||||
get { return GetValueInt("Retention"); }
|
||||
|
||||
set { SetValue("Retention", value); }
|
||||
}
|
||||
|
||||
public virtual String SabHost
|
||||
{
|
||||
get { return GetValue("SabHost", "localhost"); }
|
||||
|
@ -259,6 +252,59 @@ namespace NzbDrone.Core.Providers.Core
|
|||
set { SetValue("DefaultQualityProfile", value); }
|
||||
}
|
||||
|
||||
public virtual Boolean XbmcEnabled
|
||||
{
|
||||
get { return GetValueBoolean("XbmcEnabled"); }
|
||||
|
||||
set { SetValue("XbmcEnabled", value); }
|
||||
}
|
||||
|
||||
public virtual Boolean XbmcNotifyOnGrab
|
||||
{
|
||||
get { return GetValueBoolean("XbmcNotifyOnGrab"); }
|
||||
|
||||
set { SetValue("XbmcNotifyOnGrab", value); }
|
||||
}
|
||||
|
||||
public virtual Boolean XbmcNotifyOnDownload
|
||||
{
|
||||
get { return GetValueBoolean("XbmcNotifyOnDownload"); }
|
||||
|
||||
set { SetValue("XbmcNotifyOnDownload", value); }
|
||||
}
|
||||
|
||||
public virtual Boolean XbmcUpdateLibrary
|
||||
{
|
||||
get { return GetValueBoolean("XbmcUpdateLibrary"); }
|
||||
|
||||
set { SetValue("XbmcUpdateLibrary", value); }
|
||||
}
|
||||
|
||||
public virtual Boolean XbmcCleanLibrary
|
||||
{
|
||||
get { return GetValueBoolean("XbmcCleanLibrary"); }
|
||||
|
||||
set { SetValue("XbmcCleanLibrary", value); }
|
||||
}
|
||||
|
||||
public virtual string XbmcHosts
|
||||
{
|
||||
get { return GetValue("XbmcHosts", "localhost:8080"); }
|
||||
set { SetValue("XbmcHosts", value); }
|
||||
}
|
||||
|
||||
public virtual string XbmcUsername
|
||||
{
|
||||
get { return GetValue("XbmcUsername", "xbmc"); }
|
||||
set { SetValue("XbmcUsername", value); }
|
||||
}
|
||||
|
||||
public virtual string XbmcPassword
|
||||
{
|
||||
get { return GetValue("XbmcPassword", String.Empty); }
|
||||
set { SetValue("XbmcPassword", value); }
|
||||
}
|
||||
|
||||
private string GetValue(string key)
|
||||
{
|
||||
return GetValue(key, String.Empty);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Core.Providers.Core
|
||||
|
@ -64,5 +65,33 @@ namespace NzbDrone.Core.Providers.Core
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string PostCommand(string address, string username, string password, string command)
|
||||
{
|
||||
address += "/jsonrpc";
|
||||
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes(command);
|
||||
|
||||
var request = WebRequest.Create(address);
|
||||
request.Method = "POST";
|
||||
request.Credentials = new NetworkCredential(username, password);
|
||||
request.ContentLength = byteArray.Length;
|
||||
request.ContentType = "application/x-www-form-urlencoded";
|
||||
var dataStream = request.GetRequestStream();
|
||||
dataStream.Write(byteArray, 0, byteArray.Length);
|
||||
dataStream.Close();
|
||||
|
||||
var response = request.GetResponse();
|
||||
dataStream = response.GetResponseStream();
|
||||
var reader = new StreamReader(dataStream);
|
||||
// Read the content.
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
|
||||
reader.Close();
|
||||
dataStream.Close();
|
||||
response.Close();
|
||||
|
||||
return responseFromServer.Replace(" ", " ");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using Ninject;
|
||||
|
||||
namespace NzbDrone.Core.Providers.Core
|
||||
{
|
||||
public class UdpProvider
|
||||
{
|
||||
[Inject]
|
||||
public UdpProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private const int StandardPort = 9777;
|
||||
private const int MaxPacketSize = 1024;
|
||||
private const int HeaderSize = 32;
|
||||
private const int MaxPayloadSize = MaxPacketSize - HeaderSize;
|
||||
private const byte MajorVersion = 2;
|
||||
private const byte MinorVersion = 0;
|
||||
|
||||
public enum PacketType
|
||||
{
|
||||
Helo = 0x01,
|
||||
Bye = 0x02,
|
||||
Button = 0x03,
|
||||
Mouse = 0x04,
|
||||
Ping = 0x05,
|
||||
Broadcast = 0x06, //Currently not implemented
|
||||
Notification = 0x07,
|
||||
Blob = 0x08,
|
||||
Log = 0x09,
|
||||
Action = 0x0A,
|
||||
Debug = 0xFF //Currently not implemented
|
||||
}
|
||||
|
||||
private byte[] Header(PacketType packetType, int numberOfPackets, int currentPacket, int payloadSize, uint uniqueToken)
|
||||
{
|
||||
byte[] header = new byte[HeaderSize];
|
||||
|
||||
header[0] = (byte)'X';
|
||||
header[1] = (byte)'B';
|
||||
header[2] = (byte)'M';
|
||||
header[3] = (byte)'C';
|
||||
|
||||
header[4] = MajorVersion;
|
||||
header[5] = MinorVersion;
|
||||
|
||||
if (currentPacket == 1)
|
||||
{
|
||||
header[6] = (byte)(((ushort)packetType & 0xff00) >> 8);
|
||||
header[7] = (byte)((ushort)packetType & 0x00ff);
|
||||
}
|
||||
else
|
||||
{
|
||||
header[6] = (byte)(((ushort)PacketType.Blob & 0xff00) >> 8);
|
||||
header[7] = (byte)((ushort)PacketType.Blob & 0x00ff);
|
||||
}
|
||||
|
||||
header[8] = (byte)((currentPacket & 0xff000000) >> 24);
|
||||
header[9] = (byte)((currentPacket & 0x00ff0000) >> 16);
|
||||
header[10] = (byte)((currentPacket & 0x0000ff00) >> 8);
|
||||
header[11] = (byte)(currentPacket & 0x000000ff);
|
||||
|
||||
header[12] = (byte)((numberOfPackets & 0xff000000) >> 24);
|
||||
header[13] = (byte)((numberOfPackets & 0x00ff0000) >> 16);
|
||||
header[14] = (byte)((numberOfPackets & 0x0000ff00) >> 8);
|
||||
header[15] = (byte)(numberOfPackets & 0x000000ff);
|
||||
|
||||
header[16] = (byte)((payloadSize & 0xff00) >> 8);
|
||||
header[17] = (byte)(payloadSize & 0x00ff);
|
||||
|
||||
header[18] = (byte)((uniqueToken & 0xff000000) >> 24);
|
||||
header[19] = (byte)((uniqueToken & 0x00ff0000) >> 16);
|
||||
header[20] = (byte)((uniqueToken & 0x0000ff00) >> 8);
|
||||
header[21] = (byte)(uniqueToken & 0x000000ff);
|
||||
|
||||
return header;
|
||||
|
||||
}
|
||||
|
||||
public virtual bool Send(string address, PacketType packetType, byte[] payload)
|
||||
{
|
||||
var uniqueToken = (uint)DateTime.Now.TimeOfDay.Milliseconds;
|
||||
|
||||
var socket = Connect(address, StandardPort);
|
||||
|
||||
if (socket == null || !socket.Connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool successfull = true;
|
||||
int packetCount = (payload.Length / MaxPayloadSize) + 1;
|
||||
int bytesToSend = 0;
|
||||
int bytesSent = 0;
|
||||
int bytesLeft = payload.Length;
|
||||
|
||||
for (int Package = 1; Package <= packetCount; Package++)
|
||||
{
|
||||
|
||||
if (bytesLeft > MaxPayloadSize)
|
||||
{
|
||||
bytesToSend = MaxPayloadSize;
|
||||
bytesLeft -= bytesToSend;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesToSend = bytesLeft;
|
||||
bytesLeft = 0;
|
||||
}
|
||||
|
||||
byte[] header = Header(packetType, packetCount, Package, bytesToSend, uniqueToken);
|
||||
byte[] packet = new byte[MaxPacketSize];
|
||||
|
||||
Array.Copy(header, 0, packet, 0, header.Length);
|
||||
Array.Copy(payload, bytesSent, packet, header.Length, bytesToSend);
|
||||
|
||||
int sendSize = socket.Send(packet, header.Length + bytesToSend, SocketFlags.None);
|
||||
|
||||
if (sendSize != (header.Length + bytesToSend))
|
||||
{
|
||||
successfull = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bytesSent += bytesToSend;
|
||||
}
|
||||
Disconnect(socket);
|
||||
return successfull;
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
Disconnect(socket);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Socket Connect(string address, int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
|
||||
IPAddress ip;
|
||||
if (!IPAddress.TryParse(address, out ip))
|
||||
{
|
||||
IPHostEntry ipHostEntry = Dns.GetHostEntry(address);
|
||||
foreach (IPAddress ipAddress in ipHostEntry.AddressList)
|
||||
{
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
ip = ipAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
socket.Connect(new IPEndPoint(ip, port));
|
||||
return socket;
|
||||
}
|
||||
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.WriteLine(exc);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Disconnect(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
socket.Close();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using NLog;
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Repository;
|
||||
|
@ -37,10 +38,19 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
OnGrab(message);
|
||||
|
||||
else if (type == ExternalNotificationType.Download)
|
||||
OnDownload(message, seriesId);
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var series = new Series();
|
||||
OnDownload(message, series);
|
||||
}
|
||||
|
||||
|
||||
else if (type == ExternalNotificationType.Rename)
|
||||
OnRename(message, seriesId);
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var series = new Series();
|
||||
OnRename(message, series);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -53,14 +63,14 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
/// Performs the on download action
|
||||
/// </summary>
|
||||
/// <param name = "message">The message to send to the receiver</param>
|
||||
/// <param name = "seriesId">The Series ID for the new download</param>
|
||||
public abstract void OnDownload(string message, int seriesId);
|
||||
/// <param name = "series">The Series for the new download</param>
|
||||
public abstract void OnDownload(string message, Series series);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the on rename action
|
||||
/// </summary>
|
||||
/// <param name = "message">The message to send to the receiver</param>
|
||||
/// <param name = "seriesId">The Series ID for the new download</param>
|
||||
public abstract void OnRename(string message, int seriesId);
|
||||
/// <param name = "series">The Series for the new download</param>
|
||||
public abstract void OnRename(string message, Series series);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Repository;
|
||||
|
||||
namespace NzbDrone.Core.Providers.ExternalNotification
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
_logger.Trace("XBMC Notifier is not enabled");
|
||||
}
|
||||
|
||||
public override void OnDownload(string message, int seriesId)
|
||||
public override void OnDownload(string message, Series series)
|
||||
{
|
||||
const string header = "NzbDrone [TV] - Downloaded";
|
||||
|
||||
|
@ -52,7 +53,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload", false)))
|
||||
{
|
||||
_logger.Trace("Sending Update Request to XBMC");
|
||||
_xbmcProvider.Update(seriesId);
|
||||
_xbmcProvider.Update(series);
|
||||
}
|
||||
|
||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnDownload", false)))
|
||||
|
@ -65,7 +66,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
_logger.Trace("XBMC Notifier is not enabled");
|
||||
}
|
||||
|
||||
public override void OnRename(string message, int seriesId)
|
||||
public override void OnRename(string message, Series series)
|
||||
{
|
||||
const string header = "NzbDrone [TV] - Renamed";
|
||||
|
||||
|
@ -78,7 +79,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
|||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false)))
|
||||
{
|
||||
_logger.Trace("Sending Update Request to XBMC");
|
||||
_xbmcProvider.Update(seriesId);
|
||||
_xbmcProvider.Update(series);
|
||||
}
|
||||
|
||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnRename", false)))
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Ninject;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Model.Xbmc;
|
||||
|
||||
namespace NzbDrone.Core.Providers.Xbmc
|
||||
{
|
||||
public class EventClientProvider
|
||||
{
|
||||
private readonly UdpProvider _udpProvider;
|
||||
|
||||
[Inject]
|
||||
public EventClientProvider(UdpProvider udpProvider)
|
||||
{
|
||||
_udpProvider = udpProvider;
|
||||
}
|
||||
|
||||
public EventClientProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool SendNotification(string caption, string message, IconType iconType, string iconFile, string address)
|
||||
{
|
||||
byte[] icon = new byte[0];
|
||||
if (iconType != IconType.None)
|
||||
{
|
||||
icon = ResourceManager.GetRawLogo(iconFile);
|
||||
}
|
||||
|
||||
byte[] payload = new byte[caption.Length + message.Length + 7 + icon.Length];
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < caption.Length; i++)
|
||||
payload[offset++] = (byte)caption[i];
|
||||
payload[offset++] = (byte)'\0';
|
||||
|
||||
for (int i = 0; i < message.Length; i++)
|
||||
payload[offset++] = (byte)message[i];
|
||||
payload[offset++] = (byte)'\0';
|
||||
|
||||
payload[offset++] = (byte)iconType;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
payload[offset++] = (byte)0;
|
||||
|
||||
Array.Copy(icon, 0, payload, caption.Length + message.Length + 7, icon.Length);
|
||||
|
||||
return _udpProvider.Send(address, UdpProvider.PacketType.Notification, payload);
|
||||
}
|
||||
|
||||
public virtual bool SendAction(string address, ActionType action, string messages)
|
||||
{
|
||||
var payload = new byte[messages.Length + 2];
|
||||
int offset = 0;
|
||||
payload[offset++] = (byte)action;
|
||||
|
||||
for (int i = 0; i < messages.Length; i++)
|
||||
payload[offset++] = (byte)messages[i];
|
||||
|
||||
payload[offset++] = (byte)'\0';
|
||||
|
||||
return _udpProvider.Send(address, UdpProvider.PacketType.Action, payload);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
namespace NzbDrone.Core.Providers.Xbmc
|
||||
{
|
||||
public class ResourceManager
|
||||
{
|
||||
public static System.Drawing.Icon GetIcon(string Name)
|
||||
{
|
||||
System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("NzbDrone.Core.{0}.ico", Name));
|
||||
if (stm == null) return null;
|
||||
return new System.Drawing.Icon(stm);
|
||||
}
|
||||
|
||||
public static byte[] GetRawData(string Name)
|
||||
{
|
||||
byte[] data;
|
||||
using (System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("NzbDrone.Core.{0}.ico", Name)))
|
||||
{
|
||||
if (stm == null) return null;
|
||||
data = new byte[stm.Length];
|
||||
stm.Read(data, 0, data.Length);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte[] GetRawLogo(string Name)
|
||||
{
|
||||
byte[] data;
|
||||
using (System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("NzbDrone.Core.{0}", Name)))
|
||||
{
|
||||
if (stm == null) return null;
|
||||
data = new byte[stm.Length];
|
||||
stm.Read(data, 0, data.Length);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static System.Drawing.Bitmap GetIconAsImage(string Name)
|
||||
{
|
||||
System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("{0}.Icons.{1}.ico", typeof(ResourceManager).Namespace, Name));
|
||||
if (stm == null) return null;
|
||||
System.Drawing.Bitmap bmp;
|
||||
using (System.Drawing.Icon ico = new System.Drawing.Icon(stm))
|
||||
{
|
||||
bmp = new System.Drawing.Bitmap(ico.Width, ico.Height);
|
||||
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
|
||||
{
|
||||
g.DrawIcon(ico, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Xml.Linq;
|
||||
using Ninject;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Model.Xbmc;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
using NzbDrone.Core.Providers.Xbmc;
|
||||
using NzbDrone.Core.Repository;
|
||||
|
||||
namespace NzbDrone.Core.Providers
|
||||
{
|
||||
|
@ -13,72 +18,134 @@ namespace NzbDrone.Core.Providers
|
|||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly ConfigProvider _configProvider;
|
||||
private readonly HttpProvider _httpProvider;
|
||||
private readonly EventClientProvider _eventClientProvider;
|
||||
|
||||
[Inject]
|
||||
public XbmcProvider(ConfigProvider configProvider, HttpProvider httpProvider)
|
||||
public XbmcProvider(ConfigProvider configProvider, HttpProvider httpProvider, EventClientProvider eventClientProvider)
|
||||
{
|
||||
_configProvider = configProvider;
|
||||
_httpProvider = httpProvider;
|
||||
_eventClientProvider = eventClientProvider;
|
||||
}
|
||||
|
||||
public virtual void Notify(string header, string message)
|
||||
{
|
||||
//Get time in seconds and convert to ms
|
||||
var time = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", "3")) * 1000;
|
||||
var command = String.Format("ExecBuiltIn(Notification({0},{1},{2}))", header, message, time);
|
||||
|
||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcNotificationImage", false)))
|
||||
{
|
||||
//Todo: Get the actual port that NzbDrone is running on...
|
||||
var serverInfo = String.Format("http://{0}:{1}", Environment.MachineName, "8989");
|
||||
|
||||
var imageUrl = String.Format("{0}/Content/XbmcNotification.png", serverInfo);
|
||||
command = String.Format("ExecBuiltIn(Notification({0},{1},{2}, {3}))", header, message, time, imageUrl);
|
||||
}
|
||||
|
||||
foreach (var host in _configProvider.GetValue("XbmcHosts", "localhost:80").Split(','))
|
||||
//Always use EventServer, until Json has real support for it
|
||||
foreach (var host in _configProvider.XbmcHosts.Split(','))
|
||||
{
|
||||
Logger.Trace("Sending Notifcation to XBMC Host: {0}", host);
|
||||
SendCommand(host, command);
|
||||
_eventClientProvider.SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", GetHostWithoutPort(host));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Update(int seriesId)
|
||||
public XbmcProvider()
|
||||
{
|
||||
foreach (var host in _configProvider.GetValue("XbmcHosts", "localhost:80").Split(','))
|
||||
|
||||
}
|
||||
|
||||
public virtual void Update(Series series)
|
||||
{
|
||||
//Use Json for Eden/Nightly or depricated HTTP for 10.x (Dharma) to get the proper path
|
||||
//Perform update with EventServer (Json currently doesn't support updating a specific path only - July 2011)
|
||||
|
||||
var username = _configProvider.XbmcUsername;
|
||||
var password = _configProvider.XbmcPassword;
|
||||
|
||||
foreach (var host in _configProvider.XbmcHosts.Split(','))
|
||||
{
|
||||
Logger.Trace("Determining version of XBMC Host: {0}", host);
|
||||
var version = GetJsonVersion(host, username, password);
|
||||
|
||||
//If Dharma
|
||||
if (version == 2)
|
||||
UpdateWithHttp(series, host, username, password);
|
||||
|
||||
//If Eden or newer (attempting to make it future compatible)
|
||||
else if (version >= 3)
|
||||
UpdateWithJson(series, password, host, username);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool UpdateWithJson(Series series, string host, string username, string password)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Use Json!
|
||||
var xbmcShows = GetTvShowsJson(host, username, password);
|
||||
var path = xbmcShows.Where(s => s.ImdbNumber == series.SeriesId || s.Label == series.Title).FirstOrDefault();
|
||||
|
||||
var hostOnly = GetHostWithoutPort(host);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
Logger.Trace("Updating series [{0}] on XBMC host: {1}", series.Title, host);
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path.File);
|
||||
_eventClientProvider.SendAction(hostOnly, ActionType.ExecBuiltin, command);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title, host);
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video))");
|
||||
_eventClientProvider.SendAction(hostOnly, ActionType.ExecBuiltin, command);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.DebugException(ex.Message, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool UpdateWithHttp(Series series, string host, string username, string password)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Trace("Sending Update DB Request to XBMC Host: {0}", host);
|
||||
var xbmcSeriesPath = GetXbmcSeriesPath(host, seriesId);
|
||||
var xbmcSeriesPath = GetXbmcSeriesPath(host, series.SeriesId, username, password);
|
||||
|
||||
//If the path is not found & the user wants to update the entire library, do it now.
|
||||
if (String.IsNullOrEmpty(xbmcSeriesPath) &&
|
||||
Convert.ToBoolean(_configProvider.GetValue("XbmcFullUpdate", false)))
|
||||
//If the path is found update it, else update the whole library
|
||||
if (!String.IsNullOrEmpty(xbmcSeriesPath))
|
||||
{
|
||||
Logger.Trace("Updating series [{0}] on XBMC host: {1}", series.Title, host);
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", xbmcSeriesPath);
|
||||
SendCommand(host, command, username, password);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//Update the entire library
|
||||
Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", seriesId, host);
|
||||
SendCommand(host, "ExecBuiltIn(UpdateLibrary(video))");
|
||||
return;
|
||||
Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title, host);
|
||||
SendCommand(host, "ExecBuiltIn(UpdateLibrary(video))", username, password);
|
||||
}
|
||||
}
|
||||
|
||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", xbmcSeriesPath);
|
||||
SendCommand(host, command);
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.DebugException(ex.Message, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Clean()
|
||||
{
|
||||
foreach (var host in _configProvider.GetValue("XbmcHosts", "localhost:80").Split(','))
|
||||
//Use EventServer, once Dharma is extinct use Json?
|
||||
|
||||
foreach (var host in _configProvider.XbmcHosts.Split(','))
|
||||
{
|
||||
Logger.Trace("Sending DB Clean Request to XBMC Host: {0}", host);
|
||||
var command = String.Format("ExecBuiltIn(CleanLibrary(video))");
|
||||
SendCommand(host, command);
|
||||
var command = "ExecBuiltIn(CleanLibrary(video))";
|
||||
_eventClientProvider.SendAction(GetHostWithoutPort(host), ActionType.ExecBuiltin, command);
|
||||
}
|
||||
}
|
||||
|
||||
private string SendCommand(string host, string command)
|
||||
public virtual string SendCommand(string host, string command, string username, string password)
|
||||
{
|
||||
var username = _configProvider.GetValue("XbmcUsername", String.Empty);
|
||||
var password = _configProvider.GetValue("XbmcPassword", String.Empty);
|
||||
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
|
||||
|
||||
if (!String.IsNullOrEmpty(username))
|
||||
|
@ -89,7 +156,7 @@ namespace NzbDrone.Core.Providers
|
|||
return _httpProvider.DownloadString(url);
|
||||
}
|
||||
|
||||
private string GetXbmcSeriesPath(string host, int seriesId)
|
||||
public virtual string GetXbmcSeriesPath(string host, int seriesId, string username, string password)
|
||||
{
|
||||
var query =
|
||||
String.Format(
|
||||
|
@ -97,13 +164,13 @@ namespace NzbDrone.Core.Providers
|
|||
seriesId);
|
||||
var command = String.Format("QueryVideoDatabase({0})", query);
|
||||
|
||||
var setResponseCommand =
|
||||
const string setResponseCommand =
|
||||
"SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
||||
var resetResponseCommand = "SetResponseFormat()";
|
||||
const string resetResponseCommand = "SetResponseFormat()";
|
||||
|
||||
SendCommand(host, setResponseCommand);
|
||||
var response = SendCommand(host, command);
|
||||
SendCommand(host, resetResponseCommand);
|
||||
SendCommand(host, setResponseCommand, username, password);
|
||||
var response = SendCommand(host, command, username, password);
|
||||
SendCommand(host, resetResponseCommand, username, password);
|
||||
|
||||
if (String.IsNullOrEmpty(response))
|
||||
return String.Empty;
|
||||
|
@ -121,5 +188,109 @@ namespace NzbDrone.Core.Providers
|
|||
|
||||
return field.Value;
|
||||
}
|
||||
|
||||
public virtual int GetJsonVersion(string host, string username, string password)
|
||||
{
|
||||
//2 = Dharma
|
||||
//3 = Eden/Nightly (as of July 2011)
|
||||
|
||||
var version = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var command = new Command { id = 10, method = "JSONRPC.Version" };
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var serialized = serializer.Serialize(command);
|
||||
var response = _httpProvider.PostCommand(host, username, password, serialized);
|
||||
|
||||
if (CheckForJsonError(response))
|
||||
return version;
|
||||
|
||||
var result = serializer.Deserialize<VersionResult>(response);
|
||||
result.Result.TryGetValue("version", out version);
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.DebugException(ex.Message, ex);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, bool> GetActivePlayers(string host, string username, string password)
|
||||
{
|
||||
//2 = Dharma
|
||||
//3 = Eden/Nightly (as of July 2011)
|
||||
|
||||
try
|
||||
{
|
||||
var command = new Command { id = 10, method = "Player.GetActivePlayers" };
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var serialized = serializer.Serialize(command);
|
||||
var response = _httpProvider.PostCommand(host, username, password, serialized);
|
||||
|
||||
if (CheckForJsonError(response))
|
||||
return null;
|
||||
|
||||
var result = serializer.Deserialize<ActivePlayersResult>(response);
|
||||
|
||||
return result.Result;
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.DebugException(ex.Message, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual List<TvShow> GetTvShowsJson(string host, string username, string password)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fields = new string[] { "file", "imdbnumber" };
|
||||
var xbmcParams = new Params { fields = fields };
|
||||
var command = new Command { id = 10, method = "VideoLibrary.GetTvShows", @params = xbmcParams };
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var serialized = serializer.Serialize(command);
|
||||
var response = _httpProvider.PostCommand(host, username, password, serialized);
|
||||
|
||||
if (CheckForJsonError(response))
|
||||
return null;
|
||||
|
||||
var result = serializer.Deserialize<TvShowResult>(response);
|
||||
var shows = result.Result["tvshows"];
|
||||
|
||||
return shows;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.DebugException(ex.Message, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual bool CheckForJsonError(string response)
|
||||
{
|
||||
if (response.StartsWith("{\"error\""))
|
||||
{
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var error = serializer.Deserialize<ErrorResult>(response);
|
||||
var code = error.Error["code"];
|
||||
var message = error.Error["message"];
|
||||
|
||||
Logger.Debug("XBMC Json Error. Code = {0}, Message: {1}", code, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetHostWithoutPort(string address)
|
||||
{
|
||||
return address.Split(':')[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -140,20 +140,14 @@ namespace NzbDrone.Web.Controllers
|
|||
{
|
||||
var model = new NotificationSettingsModel
|
||||
{
|
||||
XbmcEnabled = Convert.ToBoolean(_configProvider.GetValue("XbmcEnabled", false)),
|
||||
XbmcNotifyOnGrab = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnGrab", false)),
|
||||
XbmcNotifyOnDownload = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnDownload", false)),
|
||||
XbmcNotifyOnRename = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnRename", false)),
|
||||
XbmcNotificationImage = Convert.ToBoolean(_configProvider.GetValue("XbmcNotificationImage", false)),
|
||||
XbmcDisplayTime = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", 3)),
|
||||
XbmcUpdateOnDownload = Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload ", false)),
|
||||
XbmcUpdateOnRename = Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false)),
|
||||
XbmcFullUpdate = Convert.ToBoolean(_configProvider.GetValue("XbmcFullUpdate", false)),
|
||||
XbmcCleanOnDownload = Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnDownload", false)),
|
||||
XbmcCleanOnRename = Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnRename", false)),
|
||||
XbmcHosts = _configProvider.GetValue("XbmcHosts", "localhost:80"),
|
||||
XbmcUsername = _configProvider.GetValue("XbmcUsername", String.Empty),
|
||||
XbmcPassword = _configProvider.GetValue("XbmcPassword", String.Empty)
|
||||
XbmcEnabled = _configProvider.XbmcEnabled,
|
||||
XbmcNotifyOnGrab = _configProvider.XbmcNotifyOnGrab,
|
||||
XbmcNotifyOnDownload = _configProvider.XbmcNotifyOnDownload,
|
||||
XbmcUpdateLibrary = _configProvider.XbmcUpdateLibrary,
|
||||
XbmcCleanLibrary = _configProvider.XbmcCleanLibrary,
|
||||
XbmcHosts = _configProvider.XbmcHosts,
|
||||
XbmcUsername = _configProvider.XbmcUsername,
|
||||
XbmcPassword = _configProvider.XbmcPassword
|
||||
};
|
||||
|
||||
return View(model);
|
||||
|
@ -401,20 +395,14 @@ namespace NzbDrone.Web.Controllers
|
|||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
_configProvider.SetValue("XbmcEnabled", data.XbmcEnabled.ToString());
|
||||
_configProvider.SetValue("XbmcNotifyOnGrab", data.XbmcNotifyOnGrab.ToString());
|
||||
_configProvider.SetValue("XbmcNotifyOnDownload", data.XbmcNotifyOnDownload.ToString());
|
||||
_configProvider.SetValue("XbmcNotifyOnRename", data.XbmcNotifyOnRename.ToString());
|
||||
_configProvider.SetValue("XbmcNotificationImage", data.XbmcNotificationImage.ToString());
|
||||
_configProvider.SetValue("XbmcDisplayTime", data.XbmcDisplayTime.ToString());
|
||||
_configProvider.SetValue("XbmcUpdateOnDownload", data.XbmcUpdateOnDownload.ToString());
|
||||
_configProvider.SetValue("XbmcUpdateOnRename", data.XbmcUpdateOnRename.ToString());
|
||||
_configProvider.SetValue("XbmcFullUpdate", data.XbmcFullUpdate.ToString());
|
||||
_configProvider.SetValue("XbmcCleanOnDownload", data.XbmcCleanOnDownload.ToString());
|
||||
_configProvider.SetValue("XbmcCleanOnRename", data.XbmcCleanOnRename.ToString());
|
||||
_configProvider.SetValue("XbmcHosts", data.XbmcHosts);
|
||||
_configProvider.SetValue("XbmcUsername", data.XbmcUsername);
|
||||
_configProvider.SetValue("XbmcPassword", data.XbmcPassword);
|
||||
_configProvider.XbmcEnabled = data.XbmcEnabled;
|
||||
_configProvider.XbmcNotifyOnGrab = data.XbmcNotifyOnGrab;
|
||||
_configProvider.XbmcNotifyOnDownload = data.XbmcNotifyOnDownload;
|
||||
_configProvider.XbmcUpdateLibrary = data.XbmcUpdateLibrary;
|
||||
_configProvider.XbmcCleanLibrary = data.XbmcCleanLibrary;
|
||||
_configProvider.XbmcHosts = data.XbmcHosts;
|
||||
_configProvider.XbmcUsername = data.XbmcUsername;
|
||||
_configProvider.XbmcPassword = data.XbmcPassword;
|
||||
|
||||
basicNotification.Title = SETTINGS_SAVED;
|
||||
_notificationProvider.Register(basicNotification);
|
||||
|
|
|
@ -17,43 +17,17 @@ namespace NzbDrone.Web.Models
|
|||
[Description("Send notification when episode is downloaded?")]
|
||||
public bool XbmcNotifyOnDownload { get; set; }
|
||||
|
||||
[DisplayName("Notify on Rename")]
|
||||
[Description("Send notification when episode is renamed?")]
|
||||
public bool XbmcNotifyOnRename { get; set; }
|
||||
[DisplayName("Update on Download and Rename")]
|
||||
[Description("Update XBMC library after episode is downloaded or renamed?")]
|
||||
public bool XbmcUpdateLibrary { get; set; }
|
||||
|
||||
[DisplayName("Image with Notification")]
|
||||
[Description("Display NzbDrone image on notifications?")]
|
||||
public bool XbmcNotificationImage { get; set; }
|
||||
|
||||
[Required]
|
||||
[Range(3, 10, ErrorMessage = "Must be between 3 and 10 seconds")]
|
||||
[DisplayName("Display Time")]
|
||||
[Description("How long the notification should be displayed")]
|
||||
public int XbmcDisplayTime { get; set; }
|
||||
|
||||
[DisplayName("Update on Download")]
|
||||
[Description("Update XBMC library after episode download?")]
|
||||
public bool XbmcUpdateOnDownload { get; set; }
|
||||
|
||||
[DisplayName("Update on Rename")]
|
||||
[Description("Update XBMC library after episode is renamed?")]
|
||||
public bool XbmcUpdateOnRename { get; set; }
|
||||
|
||||
[DisplayName("Full Update")]
|
||||
[Description("Perform a full update is series update fails?")]
|
||||
public bool XbmcFullUpdate { get; set; }
|
||||
|
||||
[DisplayName("Clean on Download")]
|
||||
[Description("Clean XBMC library after episode download?")]
|
||||
public bool XbmcCleanOnDownload { get; set; }
|
||||
|
||||
[DisplayName("Clean on Rename")]
|
||||
[Description("Clean XBMC library after episode is renamed?")]
|
||||
public bool XbmcCleanOnRename { get; set; }
|
||||
[DisplayName("Clean on Download/Rename")]
|
||||
[Description("Clean XBMC library after an episode is downloaded or renamed?")]
|
||||
public bool XbmcCleanLibrary { get; set; }
|
||||
|
||||
[DataType(DataType.Text)]
|
||||
[DisplayName("Hosts")]
|
||||
[Description("XBMC hosts with port, comma separ")]
|
||||
[Description("XBMC hosts with port, comma separated")]
|
||||
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
||||
public string XbmcHosts { get; set; }
|
||||
|
||||
|
|
|
@ -66,45 +66,15 @@
|
|||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcNotifyOnDownload, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcNotifyOnRename)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcNotifyOnRename)</span>
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcUpdateLibrary)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcUpdateLibrary)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcNotifyOnRename, new { @class = "inputClass checkClass" })
|
||||
@Html.CheckBoxFor(m => m.XbmcUpdateLibrary, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcNotificationImage)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcNotificationImage)</span>
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcCleanLibrary)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcCleanLibrary)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcNotificationImage, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcDisplayTime)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcDisplayTime)</span>
|
||||
</label>
|
||||
@Html.TextBoxFor(m => m.XbmcDisplayTime, new { @class = "inputClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcUpdateOnDownload)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcUpdateOnDownload)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcUpdateOnDownload, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcUpdateOnRename)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcUpdateOnRename)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcUpdateOnRename, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcFullUpdate)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcFullUpdate)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcFullUpdate, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcCleanOnDownload)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcCleanOnDownload)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcCleanOnDownload, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcCleanOnRename)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcCleanOnRename)</span>
|
||||
</label>
|
||||
@Html.CheckBoxFor(m => m.XbmcCleanOnRename, new { @class = "inputClass checkClass" })
|
||||
@Html.CheckBoxFor(m => m.XbmcCleanLibrary, new { @class = "inputClass checkClass" })
|
||||
|
||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcHosts)
|
||||
<span class="small">@Html.DescriptionFor(m => m.XbmcHosts)</span>
|
||||
|
|
|
@ -42,7 +42,6 @@ Settings
|
|||
<br />
|
||||
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
<div id="result" class="hiddenResult">
|
||||
|
|
Loading…
Reference in New Issue