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>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="EventClientProviderTest.cs" />
|
||||||
|
<Compile Include="XbmcProviderTest.cs" />
|
||||||
<Compile Include="DiskScanProviderTest.cs" />
|
<Compile Include="DiskScanProviderTest.cs" />
|
||||||
<Compile Include="EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
<Compile Include="EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
||||||
<Compile Include="DiskScanProviderTest_ImportFile.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\LanguageType.cs" />
|
||||||
<Compile Include="Model\Quality.cs" />
|
<Compile Include="Model\Quality.cs" />
|
||||||
<Compile Include="Model\SabnzbdInfoModel.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\DiskScanProvider.cs" />
|
||||||
<Compile Include="Providers\DownloadProvider.cs" />
|
<Compile Include="Providers\DownloadProvider.cs" />
|
||||||
<Compile Include="Providers\ExternalNotification\ExternalNotificationProviderBase.cs" />
|
<Compile Include="Providers\ExternalNotification\ExternalNotificationProviderBase.cs" />
|
||||||
|
@ -213,6 +225,7 @@
|
||||||
<Compile Include="Providers\Jobs\RssSyncJob.cs" />
|
<Compile Include="Providers\Jobs\RssSyncJob.cs" />
|
||||||
<Compile Include="Providers\Jobs\UpdateInfoJob.cs" />
|
<Compile Include="Providers\Jobs\UpdateInfoJob.cs" />
|
||||||
<Compile Include="Providers\SceneMappingProvider.cs" />
|
<Compile Include="Providers\SceneMappingProvider.cs" />
|
||||||
|
<Compile Include="Providers\Xbmc\EventClientProvider.cs" />
|
||||||
<Compile Include="Repository\ExternalNotificationSetting.cs" />
|
<Compile Include="Repository\ExternalNotificationSetting.cs" />
|
||||||
<Compile Include="Repository\JobSetting.cs" />
|
<Compile Include="Repository\JobSetting.cs" />
|
||||||
<Compile Include="Repository\IndexerSetting.cs" />
|
<Compile Include="Repository\IndexerSetting.cs" />
|
||||||
|
@ -292,6 +305,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="NzbDrone.jpg" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<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); }
|
set { SetValue("DownloadPropers", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Int32 Retention
|
|
||||||
{
|
|
||||||
get { return GetValueInt("Retention"); }
|
|
||||||
|
|
||||||
set { SetValue("Retention", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual String SabHost
|
public virtual String SabHost
|
||||||
{
|
{
|
||||||
get { return GetValue("SabHost", "localhost"); }
|
get { return GetValue("SabHost", "localhost"); }
|
||||||
|
@ -259,6 +252,59 @@ namespace NzbDrone.Core.Providers.Core
|
||||||
set { SetValue("DefaultQualityProfile", value); }
|
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)
|
private string GetValue(string key)
|
||||||
{
|
{
|
||||||
return GetValue(key, String.Empty);
|
return GetValue(key, String.Empty);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Providers.Core
|
namespace NzbDrone.Core.Providers.Core
|
||||||
|
@ -64,5 +65,33 @@ namespace NzbDrone.Core.Providers.Core
|
||||||
return false;
|
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.Model;
|
||||||
using NzbDrone.Core.Providers.Core;
|
using NzbDrone.Core.Providers.Core;
|
||||||
using NzbDrone.Core.Repository;
|
using NzbDrone.Core.Repository;
|
||||||
|
@ -37,10 +38,19 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
OnGrab(message);
|
OnGrab(message);
|
||||||
|
|
||||||
else if (type == ExternalNotificationType.Download)
|
else if (type == ExternalNotificationType.Download)
|
||||||
OnDownload(message, seriesId);
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
var series = new Series();
|
||||||
|
OnDownload(message, series);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
else if (type == ExternalNotificationType.Rename)
|
else if (type == ExternalNotificationType.Rename)
|
||||||
OnRename(message, seriesId);
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
var series = new Series();
|
||||||
|
OnRename(message, series);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -53,14 +63,14 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
/// Performs the on download action
|
/// Performs the on download action
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name = "message">The message to send to the receiver</param>
|
/// <param name = "message">The message to send to the receiver</param>
|
||||||
/// <param name = "seriesId">The Series ID for the new download</param>
|
/// <param name = "series">The Series for the new download</param>
|
||||||
public abstract void OnDownload(string message, int seriesId);
|
public abstract void OnDownload(string message, Series series);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs the on rename action
|
/// Performs the on rename action
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name = "message">The message to send to the receiver</param>
|
/// <param name = "message">The message to send to the receiver</param>
|
||||||
/// <param name = "seriesId">The Series ID for the new download</param>
|
/// <param name = "series">The Series for the new download</param>
|
||||||
public abstract void OnRename(string message, int seriesId);
|
public abstract void OnRename(string message, Series series);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using NzbDrone.Core.Providers.Core;
|
using NzbDrone.Core.Providers.Core;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Providers.ExternalNotification
|
namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
{
|
{
|
||||||
|
@ -37,7 +38,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
_logger.Trace("XBMC Notifier is not enabled");
|
_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";
|
const string header = "NzbDrone [TV] - Downloaded";
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload", false)))
|
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload", false)))
|
||||||
{
|
{
|
||||||
_logger.Trace("Sending Update Request to XBMC");
|
_logger.Trace("Sending Update Request to XBMC");
|
||||||
_xbmcProvider.Update(seriesId);
|
_xbmcProvider.Update(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnDownload", false)))
|
if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnDownload", false)))
|
||||||
|
@ -65,7 +66,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
_logger.Trace("XBMC Notifier is not enabled");
|
_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";
|
const string header = "NzbDrone [TV] - Renamed";
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ namespace NzbDrone.Core.Providers.ExternalNotification
|
||||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false)))
|
if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false)))
|
||||||
{
|
{
|
||||||
_logger.Trace("Sending Update Request to XBMC");
|
_logger.Trace("Sending Update Request to XBMC");
|
||||||
_xbmcProvider.Update(seriesId);
|
_xbmcProvider.Update(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnRename", false)))
|
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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Web.Script.Serialization;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
using NzbDrone.Core.Providers.Core;
|
using NzbDrone.Core.Providers.Core;
|
||||||
|
using NzbDrone.Core.Providers.Xbmc;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Providers
|
namespace NzbDrone.Core.Providers
|
||||||
{
|
{
|
||||||
|
@ -13,72 +18,134 @@ namespace NzbDrone.Core.Providers
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
private readonly ConfigProvider _configProvider;
|
private readonly ConfigProvider _configProvider;
|
||||||
private readonly HttpProvider _httpProvider;
|
private readonly HttpProvider _httpProvider;
|
||||||
|
private readonly EventClientProvider _eventClientProvider;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public XbmcProvider(ConfigProvider configProvider, HttpProvider httpProvider)
|
public XbmcProvider(ConfigProvider configProvider, HttpProvider httpProvider, EventClientProvider eventClientProvider)
|
||||||
{
|
{
|
||||||
_configProvider = configProvider;
|
_configProvider = configProvider;
|
||||||
_httpProvider = httpProvider;
|
_httpProvider = httpProvider;
|
||||||
|
_eventClientProvider = eventClientProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Notify(string header, string message)
|
public virtual void Notify(string header, string message)
|
||||||
{
|
{
|
||||||
//Get time in seconds and convert to ms
|
//Always use EventServer, until Json has real support for it
|
||||||
var time = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", "3")) * 1000;
|
foreach (var host in _configProvider.XbmcHosts.Split(','))
|
||||||
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(','))
|
|
||||||
{
|
{
|
||||||
Logger.Trace("Sending Notifcation to XBMC Host: {0}", host);
|
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(','))
|
|
||||||
{
|
}
|
||||||
Logger.Trace("Sending Update DB Request to XBMC Host: {0}", host);
|
|
||||||
var xbmcSeriesPath = GetXbmcSeriesPath(host, seriesId);
|
|
||||||
|
|
||||||
//If the path is not found & the user wants to update the entire library, do it now.
|
public virtual void Update(Series series)
|
||||||
if (String.IsNullOrEmpty(xbmcSeriesPath) &&
|
{
|
||||||
Convert.ToBoolean(_configProvider.GetValue("XbmcFullUpdate", false)))
|
//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)
|
||||||
{
|
{
|
||||||
//Update the entire library
|
Logger.Trace("Updating series [{0}] on XBMC host: {1}", series.Title, host);
|
||||||
Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", seriesId, host);
|
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path.File);
|
||||||
SendCommand(host, "ExecBuiltIn(UpdateLibrary(video))");
|
_eventClientProvider.SendAction(hostOnly, ActionType.ExecBuiltin, command);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", xbmcSeriesPath);
|
else
|
||||||
SendCommand(host, command);
|
{
|
||||||
|
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, series.SeriesId, username, password);
|
||||||
|
|
||||||
|
//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", series.Title, host);
|
||||||
|
SendCommand(host, "ExecBuiltIn(UpdateLibrary(video))", username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.DebugException(ex.Message, ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Clean()
|
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);
|
Logger.Trace("Sending DB Clean Request to XBMC Host: {0}", host);
|
||||||
var command = String.Format("ExecBuiltIn(CleanLibrary(video))");
|
var command = "ExecBuiltIn(CleanLibrary(video))";
|
||||||
SendCommand(host, command);
|
_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);
|
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(username))
|
if (!String.IsNullOrEmpty(username))
|
||||||
|
@ -89,7 +156,7 @@ namespace NzbDrone.Core.Providers
|
||||||
return _httpProvider.DownloadString(url);
|
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 =
|
var query =
|
||||||
String.Format(
|
String.Format(
|
||||||
|
@ -97,13 +164,13 @@ namespace NzbDrone.Core.Providers
|
||||||
seriesId);
|
seriesId);
|
||||||
var command = String.Format("QueryVideoDatabase({0})", query);
|
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)";
|
"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);
|
SendCommand(host, setResponseCommand, username, password);
|
||||||
var response = SendCommand(host, command);
|
var response = SendCommand(host, command, username, password);
|
||||||
SendCommand(host, resetResponseCommand);
|
SendCommand(host, resetResponseCommand, username, password);
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(response))
|
if (String.IsNullOrEmpty(response))
|
||||||
return String.Empty;
|
return String.Empty;
|
||||||
|
@ -121,5 +188,109 @@ namespace NzbDrone.Core.Providers
|
||||||
|
|
||||||
return field.Value;
|
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
|
var model = new NotificationSettingsModel
|
||||||
{
|
{
|
||||||
XbmcEnabled = Convert.ToBoolean(_configProvider.GetValue("XbmcEnabled", false)),
|
XbmcEnabled = _configProvider.XbmcEnabled,
|
||||||
XbmcNotifyOnGrab = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnGrab", false)),
|
XbmcNotifyOnGrab = _configProvider.XbmcNotifyOnGrab,
|
||||||
XbmcNotifyOnDownload = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnDownload", false)),
|
XbmcNotifyOnDownload = _configProvider.XbmcNotifyOnDownload,
|
||||||
XbmcNotifyOnRename = Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnRename", false)),
|
XbmcUpdateLibrary = _configProvider.XbmcUpdateLibrary,
|
||||||
XbmcNotificationImage = Convert.ToBoolean(_configProvider.GetValue("XbmcNotificationImage", false)),
|
XbmcCleanLibrary = _configProvider.XbmcCleanLibrary,
|
||||||
XbmcDisplayTime = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", 3)),
|
XbmcHosts = _configProvider.XbmcHosts,
|
||||||
XbmcUpdateOnDownload = Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload ", false)),
|
XbmcUsername = _configProvider.XbmcUsername,
|
||||||
XbmcUpdateOnRename = Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false)),
|
XbmcPassword = _configProvider.XbmcPassword
|
||||||
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)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(model);
|
return View(model);
|
||||||
|
@ -401,20 +395,14 @@ namespace NzbDrone.Web.Controllers
|
||||||
|
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
_configProvider.SetValue("XbmcEnabled", data.XbmcEnabled.ToString());
|
_configProvider.XbmcEnabled = data.XbmcEnabled;
|
||||||
_configProvider.SetValue("XbmcNotifyOnGrab", data.XbmcNotifyOnGrab.ToString());
|
_configProvider.XbmcNotifyOnGrab = data.XbmcNotifyOnGrab;
|
||||||
_configProvider.SetValue("XbmcNotifyOnDownload", data.XbmcNotifyOnDownload.ToString());
|
_configProvider.XbmcNotifyOnDownload = data.XbmcNotifyOnDownload;
|
||||||
_configProvider.SetValue("XbmcNotifyOnRename", data.XbmcNotifyOnRename.ToString());
|
_configProvider.XbmcUpdateLibrary = data.XbmcUpdateLibrary;
|
||||||
_configProvider.SetValue("XbmcNotificationImage", data.XbmcNotificationImage.ToString());
|
_configProvider.XbmcCleanLibrary = data.XbmcCleanLibrary;
|
||||||
_configProvider.SetValue("XbmcDisplayTime", data.XbmcDisplayTime.ToString());
|
_configProvider.XbmcHosts = data.XbmcHosts;
|
||||||
_configProvider.SetValue("XbmcUpdateOnDownload", data.XbmcUpdateOnDownload.ToString());
|
_configProvider.XbmcUsername = data.XbmcUsername;
|
||||||
_configProvider.SetValue("XbmcUpdateOnRename", data.XbmcUpdateOnRename.ToString());
|
_configProvider.XbmcPassword = data.XbmcPassword;
|
||||||
_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);
|
|
||||||
|
|
||||||
basicNotification.Title = SETTINGS_SAVED;
|
basicNotification.Title = SETTINGS_SAVED;
|
||||||
_notificationProvider.Register(basicNotification);
|
_notificationProvider.Register(basicNotification);
|
||||||
|
|
|
@ -17,43 +17,17 @@ namespace NzbDrone.Web.Models
|
||||||
[Description("Send notification when episode is downloaded?")]
|
[Description("Send notification when episode is downloaded?")]
|
||||||
public bool XbmcNotifyOnDownload { get; set; }
|
public bool XbmcNotifyOnDownload { get; set; }
|
||||||
|
|
||||||
[DisplayName("Notify on Rename")]
|
[DisplayName("Update on Download and Rename")]
|
||||||
[Description("Send notification when episode is renamed?")]
|
[Description("Update XBMC library after episode is downloaded or renamed?")]
|
||||||
public bool XbmcNotifyOnRename { get; set; }
|
public bool XbmcUpdateLibrary { get; set; }
|
||||||
|
|
||||||
[DisplayName("Image with Notification")]
|
[DisplayName("Clean on Download/Rename")]
|
||||||
[Description("Display NzbDrone image on notifications?")]
|
[Description("Clean XBMC library after an episode is downloaded or renamed?")]
|
||||||
public bool XbmcNotificationImage { get; set; }
|
public bool XbmcCleanLibrary { 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; }
|
|
||||||
|
|
||||||
[DataType(DataType.Text)]
|
[DataType(DataType.Text)]
|
||||||
[DisplayName("Hosts")]
|
[DisplayName("Hosts")]
|
||||||
[Description("XBMC hosts with port, comma separ")]
|
[Description("XBMC hosts with port, comma separated")]
|
||||||
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
||||||
public string XbmcHosts { get; set; }
|
public string XbmcHosts { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -66,45 +66,15 @@
|
||||||
</label>
|
</label>
|
||||||
@Html.CheckBoxFor(m => m.XbmcNotifyOnDownload, new { @class = "inputClass checkClass" })
|
@Html.CheckBoxFor(m => m.XbmcNotifyOnDownload, new { @class = "inputClass checkClass" })
|
||||||
|
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcNotifyOnRename)
|
<label class="labelClass">@Html.LabelFor(m => m.XbmcUpdateLibrary)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.XbmcNotifyOnRename)</span>
|
<span class="small">@Html.DescriptionFor(m => m.XbmcUpdateLibrary)</span>
|
||||||
</label>
|
</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)
|
<label class="labelClass">@Html.LabelFor(m => m.XbmcCleanLibrary)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.XbmcNotificationImage)</span>
|
<span class="small">@Html.DescriptionFor(m => m.XbmcCleanLibrary)</span>
|
||||||
</label>
|
</label>
|
||||||
@Html.CheckBoxFor(m => m.XbmcNotificationImage, new { @class = "inputClass checkClass" })
|
@Html.CheckBoxFor(m => m.XbmcCleanLibrary, 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" })
|
|
||||||
|
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcHosts)
|
<label class="labelClass">@Html.LabelFor(m => m.XbmcHosts)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.XbmcHosts)</span>
|
<span class="small">@Html.DescriptionFor(m => m.XbmcHosts)</span>
|
||||||
|
|
|
@ -42,7 +42,6 @@ Settings
|
||||||
<br />
|
<br />
|
||||||
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
|
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div id="result" class="hiddenResult">
|
<div id="result" class="hiddenResult">
|
||||||
|
|
Loading…
Reference in New Issue