Xbmc Refactored
This commit is contained in:
parent
76fb548ccd
commit
b99e62c5ba
|
@ -138,7 +138,7 @@
|
||||||
<Compile Include="Messaging\TestCommandExecutor.cs" />
|
<Compile Include="Messaging\TestCommandExecutor.cs" />
|
||||||
<Compile Include="Reflection\ReflectionExtensions.cs" />
|
<Compile Include="Reflection\ReflectionExtensions.cs" />
|
||||||
<Compile Include="ServiceFactory.cs" />
|
<Compile Include="ServiceFactory.cs" />
|
||||||
<Compile Include="StringExtention.cs" />
|
<Compile Include="StringExtension.cs" />
|
||||||
<Compile Include="HttpProvider.cs" />
|
<Compile Include="HttpProvider.cs" />
|
||||||
<Compile Include="ConsoleService.cs" />
|
<Compile Include="ConsoleService.cs" />
|
||||||
<Compile Include="Contract\ReportBase.cs" />
|
<Compile Include="Contract\ReportBase.cs" />
|
||||||
|
@ -155,7 +155,6 @@
|
||||||
<Compile Include="IServiceProvider.cs" />
|
<Compile Include="IServiceProvider.cs" />
|
||||||
<Compile Include="TinyIoC.cs" />
|
<Compile Include="TinyIoC.cs" />
|
||||||
<Compile Include="TryParseExtension.cs" />
|
<Compile Include="TryParseExtension.cs" />
|
||||||
<Compile Include="UdpProvider.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config">
|
<None Include="packages.config">
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
using System.Linq;
|
|
||||||
using System;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace NzbDrone.Common
|
|
||||||
{
|
|
||||||
public class UdpProvider
|
|
||||||
{
|
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
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] = ((ushort)PacketType.Blob & 0xff00) >> 8;
|
|
||||||
header[7] = (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)
|
|
||||||
{
|
|
||||||
Logger.TraceException(exc.Message, exc);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Disconnect(Socket socket)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (socket != null)
|
|
||||||
{
|
|
||||||
socket.Shutdown(SocketShutdown.Both);
|
|
||||||
socket.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
{
|
{
|
||||||
_notifications = new List<INotification>();
|
_notifications = new List<INotification>();
|
||||||
|
|
||||||
_notifications.Add(new Xbmc(null, null));
|
_notifications.Add(new Notifications.Xbmc.Xbmc(null, null));
|
||||||
_notifications.Add(new PlexClient(null));
|
_notifications.Add(new PlexClient(null));
|
||||||
_notifications.Add(new PlexServer(null));
|
_notifications.Add(new PlexServer(null));
|
||||||
_notifications.Add(new Email(null));
|
_notifications.Add(new Email(null));
|
||||||
|
@ -49,8 +49,8 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
{
|
{
|
||||||
Mocker.SetConstant<INotificationRepository>(Mocker.Resolve<NotificationRepository>());
|
Mocker.SetConstant<INotificationRepository>(Mocker.Resolve<NotificationRepository>());
|
||||||
|
|
||||||
Mocker.GetMock<IContainer>().Setup(s => s.Resolve(typeof (Xbmc)))
|
Mocker.GetMock<IContainer>().Setup(s => s.Resolve(typeof(Notifications.Xbmc.Xbmc)))
|
||||||
.Returns(new Xbmc(null, null));
|
.Returns(new Notifications.Xbmc.Xbmc(null, null));
|
||||||
|
|
||||||
Mocker.GetMock<IContainer>().Setup(s => s.Resolve(typeof(PlexClient)))
|
Mocker.GetMock<IContainer>().Setup(s => s.Resolve(typeof(PlexClient)))
|
||||||
.Returns(new PlexClient(null));
|
.Returns(new PlexClient(null));
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
using NzbDrone.Core.Providers;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Test.Common.AutoMoq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class GetJsonVersionFixture : CoreTest<XbmcService>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(3)]
|
||||||
|
[TestCase(2)]
|
||||||
|
[TestCase(0)]
|
||||||
|
public void should_get_version_from_major_only(int number)
|
||||||
|
{
|
||||||
|
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":" + number + "}}";
|
||||||
|
|
||||||
|
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
||||||
|
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||||
|
.Returns(message);
|
||||||
|
|
||||||
|
Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(5, 0, 0)]
|
||||||
|
[TestCase(6, 0, 0)]
|
||||||
|
[TestCase(6, 1, 0)]
|
||||||
|
[TestCase(6, 0, 23)]
|
||||||
|
[TestCase(0, 0, 0)]
|
||||||
|
public void should_get_version_from_semantic_version(int major, int minor, int patch)
|
||||||
|
{
|
||||||
|
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":{\"major\":" + major + ",\"minor\":" + minor + ",\"patch\":" + patch + "}}}";
|
||||||
|
|
||||||
|
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
||||||
|
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||||
|
.Returns(message);
|
||||||
|
|
||||||
|
Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(major, minor, patch));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_get_version_zero_when_an_error_is_received()
|
||||||
|
{
|
||||||
|
var message = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
||||||
|
|
||||||
|
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
||||||
|
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
||||||
|
.Returns(message);
|
||||||
|
|
||||||
|
Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ActivePlayersFixture : CoreTest<HttpApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
private string _expectedUrl;
|
||||||
|
|
||||||
|
private void WithNoActivePlayers()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns("<html><li>Filename:[Nothing Playing]</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithVideoPlayerActive()
|
||||||
|
{
|
||||||
|
var activePlayers = @"<html><li>Filename:C:\Test\TV\2 Broke Girls\Season 01\2 Broke Girls - S01E01 - Pilot [SDTV].avi" +
|
||||||
|
"<li>PlayStatus:Playing<li>VideoNo:0<li>Type:Video<li>Thumb:special://masterprofile/Thumbnails/Video/a/auto-a664d5a2.tbn" +
|
||||||
|
"<li>Time:00:06<li>Duration:21:35<li>Percentage:0<li>File size:183182590<li>Changed:True</html>";
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns(activePlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_expectedUrl = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", _settings.Address, "getcurrentlyplaying");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void _should_be_empty_when_no_active_players()
|
||||||
|
{
|
||||||
|
WithNoActivePlayers();
|
||||||
|
|
||||||
|
Subject.GetActivePlayers(_settings).Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_active_video_player()
|
||||||
|
{
|
||||||
|
WithVideoPlayerActive();
|
||||||
|
|
||||||
|
var result = Subject.GetActivePlayers(_settings);
|
||||||
|
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
result.First().Type.Should().Be("video");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CheckForErrorFixture : CoreTest<HttpApiProvider>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_be_true_when_the_response_contains_an_error()
|
||||||
|
{
|
||||||
|
const string response = "html><li>Error:Unknown command</html>";
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void JsonError_true_empty_response()
|
||||||
|
{
|
||||||
|
var response = String.Empty;
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void JsonError_false()
|
||||||
|
{
|
||||||
|
const string response = "html><li>Filename:[Nothing Playing]</html>";
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class GetSeriesPathFixture : CoreTest<HttpApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
private Series _series;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_series = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 79488,
|
||||||
|
Title = "30 Rock"
|
||||||
|
};
|
||||||
|
|
||||||
|
const string setResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
||||||
|
const string resetResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat()";
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(setResponseUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns("<xml><tag>OK</xml>");
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(resetResponseUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns(@"<html>
|
||||||
|
<li>OK
|
||||||
|
</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_get_series_path()
|
||||||
|
{
|
||||||
|
const string queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>";
|
||||||
|
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)");
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
|
||||||
|
.Returns(queryResult);
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series)
|
||||||
|
.Should().Be("smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_get_null_for_series_path()
|
||||||
|
{
|
||||||
|
const string queryResult = @"<xml></xml>";
|
||||||
|
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)");
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
|
||||||
|
.Returns(queryResult);
|
||||||
|
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series)
|
||||||
|
.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_get_series_path_with_special_characters_in_it()
|
||||||
|
{
|
||||||
|
const string queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/</field></record></xml>";
|
||||||
|
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)");
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
|
||||||
|
.Returns(queryResult);
|
||||||
|
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series)
|
||||||
|
.Should().Be("smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UpdateFixture : CoreTest<HttpApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
private string _seriesQueryUrl = "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)";
|
||||||
|
private Series _fakeSeries;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_fakeSeries = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 79488)
|
||||||
|
.With(s => s.Title = "30 Rock")
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithSeriesPath()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(_seriesQueryUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns("<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithoutSeriesPath()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.DownloadString(_seriesQueryUrl, _settings.Username, _settings.Password))
|
||||||
|
.Returns("<xml></xml>");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_using_series_path()
|
||||||
|
{
|
||||||
|
WithSeriesPath();
|
||||||
|
const string url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video,smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/))";
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString(url, _settings.Username, _settings.Password));
|
||||||
|
|
||||||
|
Subject.Update(_settings, _fakeSeries);
|
||||||
|
Mocker.VerifyAllMocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_all_paths_when_series_path_not_found()
|
||||||
|
{
|
||||||
|
WithoutSeriesPath();
|
||||||
|
const string url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video))";
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString(url, _settings.Username, _settings.Password));
|
||||||
|
|
||||||
|
Subject.Update(_settings, _fakeSeries);
|
||||||
|
Mocker.VerifyAllMocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class HttpApiProviderFixture : CoreTest<HttpApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ActivePlayersFixture : CoreTest<JsonApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
|
||||||
|
private void WithNoActivePlayers()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns("{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithVideoPlayerActive()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns("{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"video\"}]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithAudioPlayerActive()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns("{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"audio\"}]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithPicturePlayerActive()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns("{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"picture\"}]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithAllPlayersActive()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns("{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"audio\"},{\"playerid\":2,\"type\":\"picture\"},{\"playerid\":3,\"type\":\"video\"}]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void _should_be_empty_when_no_active_players()
|
||||||
|
{
|
||||||
|
WithNoActivePlayers();
|
||||||
|
|
||||||
|
Subject.GetActivePlayers(_settings).Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_active_video_player()
|
||||||
|
{
|
||||||
|
WithVideoPlayerActive();
|
||||||
|
|
||||||
|
var result = Subject.GetActivePlayers(_settings);
|
||||||
|
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
result.First().Type.Should().Be("video");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_active_audio_player()
|
||||||
|
{
|
||||||
|
WithAudioPlayerActive();
|
||||||
|
|
||||||
|
var result = Subject.GetActivePlayers(_settings);
|
||||||
|
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
result.First().Type.Should().Be("audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_active_picture_player()
|
||||||
|
{
|
||||||
|
WithPicturePlayerActive();
|
||||||
|
|
||||||
|
var result = Subject.GetActivePlayers(_settings);
|
||||||
|
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
result.First().Type.Should().Be("picture");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_all_players_active()
|
||||||
|
{
|
||||||
|
WithAllPlayersActive();
|
||||||
|
|
||||||
|
var result = Subject.GetActivePlayers(_settings);
|
||||||
|
|
||||||
|
result.Should().HaveCount(3);
|
||||||
|
result.Select(a => a.PlayerId).Distinct().Should().HaveCount(3);
|
||||||
|
result.Select(a => a.Type).Distinct().Should().HaveCount(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CheckForErrorFixture : CoreTest<JsonApiProvider>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_be_true_when_the_response_contains_an_error()
|
||||||
|
{
|
||||||
|
const string response = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void JsonError_true_empty_response()
|
||||||
|
{
|
||||||
|
var response = String.Empty;
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void JsonError_false()
|
||||||
|
{
|
||||||
|
const string response = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":3}}";
|
||||||
|
|
||||||
|
Subject.CheckForError(response).Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class GetSeriesPathFixture : CoreTest<JsonApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
private Series _series;
|
||||||
|
private string _response;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_response = "{\"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}]}}";
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(
|
||||||
|
s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.IsAny<string>()))
|
||||||
|
.Returns(_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithMatchingTvdbId()
|
||||||
|
{
|
||||||
|
_series = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 78461,
|
||||||
|
Title = "TV Show"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithMatchingTitle()
|
||||||
|
{
|
||||||
|
_series = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
Title = "30 Rock"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithoutMatchingSeries()
|
||||||
|
{
|
||||||
|
_series = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
Title = "Does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_null_when_series_is_not_found()
|
||||||
|
{
|
||||||
|
WithoutMatchingSeries();
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series).Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_path_when_tvdbId_matches()
|
||||||
|
{
|
||||||
|
WithMatchingTvdbId();
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series).Should().Be("smb://HOMESERVER/TV/8 Simple Rules/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_path_when_title_matches()
|
||||||
|
{
|
||||||
|
WithMatchingTitle();
|
||||||
|
|
||||||
|
Subject.GetSeriesPath(_settings, _series).Should().Be("smb://HOMESERVER/TV/30 Rock/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UpdateFixture : CoreTest<JsonApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
const string _expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"properties\":[\"file\",\"imdbnumber\"]},\"id\":10}";
|
||||||
|
|
||||||
|
private const string _tvshowsResponse = "{\"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}]}}";
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password,
|
||||||
|
It.Is<string>(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == _expectedJson.Replace(" ", ""))))
|
||||||
|
.Returns(_tvshowsResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_using_series_path()
|
||||||
|
{
|
||||||
|
var fakeSeries = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 79488)
|
||||||
|
.With(s => s.Title = "30 Rock")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.Is<String>(
|
||||||
|
e => e.Replace(" ", "")
|
||||||
|
.Replace("\r\n", "")
|
||||||
|
.Replace("\t", "")
|
||||||
|
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))))
|
||||||
|
.Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}");
|
||||||
|
|
||||||
|
Subject.Update(_settings, fakeSeries);
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Verify(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.Is<String>(
|
||||||
|
e => e.Replace(" ", "")
|
||||||
|
.Replace("\r\n", "")
|
||||||
|
.Replace("\t", "")
|
||||||
|
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_all_paths_when_series_path_not_found()
|
||||||
|
{
|
||||||
|
var fakeSeries = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 1)
|
||||||
|
.With(s => s.Title = "Not 30 Rock")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Setup(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.Is<String>(
|
||||||
|
e => !e.Replace(" ", "")
|
||||||
|
.Replace("\r\n", "")
|
||||||
|
.Replace("\t", "")
|
||||||
|
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))))
|
||||||
|
.Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}");
|
||||||
|
|
||||||
|
Subject.Update(_settings, fakeSeries);
|
||||||
|
|
||||||
|
Mocker.GetMock<IHttpProvider>()
|
||||||
|
.Verify(s => s.PostCommand(_settings.Address, _settings.Username, _settings.Password, It.Is<String>(
|
||||||
|
e => e.Replace(" ", "")
|
||||||
|
.Replace("\r\n", "")
|
||||||
|
.Replace("\t", "")
|
||||||
|
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))), Times.Never());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class JsonApiProviderFixture : CoreTest<JsonApiProvider>
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Notifications.Xbmc;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
using NzbDrone.Core.Providers;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Test.Common.AutoMoq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.NotificationTests.Xbmc
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class XbmcProviderTest : CoreTest
|
||||||
|
{
|
||||||
|
private XbmcSettings _settings;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8080,
|
||||||
|
Username = "xbmc",
|
||||||
|
Password = "xbmc",
|
||||||
|
AlwaysUpdate = false,
|
||||||
|
CleanLibrary = false,
|
||||||
|
UpdateLibrary = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -149,6 +149,17 @@
|
||||||
<Compile Include="MediaFileTests\EpisodeFileMoverFixture.cs" />
|
<Compile Include="MediaFileTests\EpisodeFileMoverFixture.cs" />
|
||||||
<Compile Include="MetadataSourceTests\TracktProxyFixture.cs" />
|
<Compile Include="MetadataSourceTests\TracktProxyFixture.cs" />
|
||||||
<Compile Include="NotificationTests\NotificationServiceFixture.cs" />
|
<Compile Include="NotificationTests\NotificationServiceFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\GetJsonVersionFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\HttpApiProviderFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Http\ActivePlayersFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Http\CheckForErrorFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Http\GetSeriesPathFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Http\UpdateFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\JsonApiProviderFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Json\ActivePlayersFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Json\CheckForErrorFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Json\GetSeriesPathFixture.cs" />
|
||||||
|
<Compile Include="NotificationTests\Xbmc\Json\UpdateFixture.cs" />
|
||||||
<Compile Include="Qualities\QualitySizeRepositoryFixture.cs" />
|
<Compile Include="Qualities\QualitySizeRepositoryFixture.cs" />
|
||||||
<Compile Include="Qualities\QualityProfileRepositoryFixture.cs" />
|
<Compile Include="Qualities\QualityProfileRepositoryFixture.cs" />
|
||||||
<Compile Include="RootFolderTests\FreeSpaceOnDrivesFixture.cs" />
|
<Compile Include="RootFolderTests\FreeSpaceOnDrivesFixture.cs" />
|
||||||
|
@ -163,7 +174,7 @@
|
||||||
<Compile Include="ProviderTests\RecycleBinProviderTests\EmptyFixture.cs" />
|
<Compile Include="ProviderTests\RecycleBinProviderTests\EmptyFixture.cs" />
|
||||||
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteFileFixture.cs" />
|
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteFileFixture.cs" />
|
||||||
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" />
|
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" />
|
||||||
<Compile Include="ProviderTests\PlexProviderTest.cs" />
|
<Compile Include="NotificationTests\PlexProviderTest.cs" />
|
||||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesRepositoryReadFixture.cs" />
|
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesRepositoryReadFixture.cs" />
|
||||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" />
|
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" />
|
||||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesBetweenDatesFixture.cs" />
|
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesBetweenDatesFixture.cs" />
|
||||||
|
@ -175,8 +186,8 @@
|
||||||
<Compile Include="DecisionEngineTests\QualityUpgradeSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\QualityUpgradeSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\QualityUpgradableSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\QualityUpgradableSpecificationFixture.cs" />
|
||||||
<Compile Include="ProviderTests\DiskProviderTests\FreeDiskSpaceTest.cs" />
|
<Compile Include="ProviderTests\DiskProviderTests\FreeDiskSpaceTest.cs" />
|
||||||
<Compile Include="ProviderTests\ProwlProviderTest.cs" />
|
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
|
||||||
<Compile Include="ProviderTests\GrowlProviderTest.cs" />
|
<Compile Include="NotificationTests\GrowlProviderTest.cs" />
|
||||||
<Compile Include="ProviderTests\DiskProviderTests\ExtractArchiveFixture.cs" />
|
<Compile Include="ProviderTests\DiskProviderTests\ExtractArchiveFixture.cs" />
|
||||||
<Compile Include="ProviderTests\PostDownloadProviderTests\DropFolderImportServiceFixture.cs" />
|
<Compile Include="ProviderTests\PostDownloadProviderTests\DropFolderImportServiceFixture.cs" />
|
||||||
<Compile Include="SeriesStatsTests\SeriesStatisticsFixture.cs" />
|
<Compile Include="SeriesStatsTests\SeriesStatisticsFixture.cs" />
|
||||||
|
@ -187,8 +198,7 @@
|
||||||
<Compile Include="HelperTests\SortHelperTest.cs" />
|
<Compile Include="HelperTests\SortHelperTest.cs" />
|
||||||
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
|
||||||
<Compile Include="Qualities\QualitySizeServiceFixture.cs" />
|
<Compile Include="Qualities\QualitySizeServiceFixture.cs" />
|
||||||
<Compile Include="ProviderTests\EventClientProviderTest.cs" />
|
<Compile Include="NotificationTests\Xbmc\XbmcServiceFixture.cs" />
|
||||||
<Compile Include="ProviderTests\XbmcProviderTest.cs" />
|
|
||||||
<Compile Include="TvTests\EpisodeProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
<Compile Include="TvTests\EpisodeProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
||||||
<Compile Include="ProviderTests\DiskScanProviderTests\ImportFileFixture.cs" />
|
<Compile Include="ProviderTests\DiskScanProviderTests\ImportFileFixture.cs" />
|
||||||
<Compile Include="FluentTest.cs" />
|
<Compile Include="FluentTest.cs" />
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Model.Xbmc;
|
|
||||||
using NzbDrone.Core.Notifications.Xbmc;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
using NzbDrone.Test.Common.AutoMoq;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.ProviderTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
|
|
||||||
public class EventClientProviderTest : CoreTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_true()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<EventClientProvider>().SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", address);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(true, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_false()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<EventClientProvider>().SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", address);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(false, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendAction_Update_true()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<EventClientProvider>().SendAction(address, ActionType.ExecBuiltin, command);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(true, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendAction_Update_false()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<EventClientProvider>().SendAction(address, ActionType.ExecBuiltin, command);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(false, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,637 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using FizzWare.NBuilder;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Notifications.Xbmc;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
using NzbDrone.Core.Model.Xbmc;
|
|
||||||
using NzbDrone.Core.Providers;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
using NzbDrone.Test.Common.AutoMoq;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.ProviderTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
|
|
||||||
public class XbmcProviderTest : CoreTest
|
|
||||||
{
|
|
||||||
private XbmcSettings _settings;
|
|
||||||
private string EdenActivePlayers;
|
|
||||||
|
|
||||||
private void WithNoActivePlayers()
|
|
||||||
{
|
|
||||||
EdenActivePlayers = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WithVideoPlayerActive()
|
|
||||||
{
|
|
||||||
EdenActivePlayers = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"video\"}]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WithAudioPlayerActive()
|
|
||||||
{
|
|
||||||
EdenActivePlayers = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"audio\"}]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WithPicturePlayerActive()
|
|
||||||
{
|
|
||||||
EdenActivePlayers = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"picture\"}]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WithAllPlayersActive()
|
|
||||||
{
|
|
||||||
EdenActivePlayers = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"playerid\":1,\"type\":\"audio\"},{\"playerid\":2,\"type\":\"picture\"},{\"playerid\":3,\"type\":\"video\"}]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_settings = new XbmcSettings
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 8080,
|
|
||||||
AlwaysUpdate = false,
|
|
||||||
CleanLibrary = false,
|
|
||||||
UpdateLibrary = true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void JsonError_true()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var response = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().CheckForJsonError(response);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(true, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void JsonError_true_empty_response()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var response = String.Empty;
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().CheckForJsonError(response);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(true, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void JsonError_false()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var reposnse = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":3}}";
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().CheckForJsonError(reposnse);
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(false, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(3)]
|
|
||||||
[TestCase(2)]
|
|
||||||
[TestCase(0)]
|
|
||||||
public void GetJsonVersionIntOnly(int number)
|
|
||||||
{
|
|
||||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":" + number + "}}";
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(message);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetJsonVersion("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().Be(new XbmcVersion(number));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(5, 0, 0)]
|
|
||||||
[TestCase(6, 0, 0)]
|
|
||||||
[TestCase(6, 1, 0)]
|
|
||||||
[TestCase(6, 0, 23)]
|
|
||||||
[TestCase(0, 0, 0)]
|
|
||||||
public void GetJsonVersionFrodo(int major, int minor, int patch)
|
|
||||||
{
|
|
||||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":{\"major\":" + major + ",\"minor\":" + minor + ",\"patch\":" + patch + "}}}";
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(message);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetJsonVersion("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().Be(new XbmcVersion(major, minor, patch));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetJsonVersion_error()
|
|
||||||
{
|
|
||||||
var message = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(message);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetJsonVersion("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().Be(new XbmcVersion(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[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 GetActivePlayersDharma(bool audio, bool picture, bool video)
|
|
||||||
{
|
|
||||||
|
|
||||||
var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"audio\":"
|
|
||||||
+ audio.ToString().ToLower()
|
|
||||||
+ ",\"picture\":"
|
|
||||||
+ picture.ToString().ToLower()
|
|
||||||
+ ",\"video\":"
|
|
||||||
+ video.ToString().ToLower()
|
|
||||||
+ "}}";
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(message);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersDharma("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(audio, result["audio"]);
|
|
||||||
Assert.AreEqual(picture, result["picture"]);
|
|
||||||
Assert.AreEqual(video, result["video"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetActivePlayersEden_should_be_empty_when_no_active_players()
|
|
||||||
{
|
|
||||||
|
|
||||||
WithNoActivePlayers();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(EdenActivePlayers);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersEden("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetActivePlayersEden_should_have_active_video_player()
|
|
||||||
{
|
|
||||||
|
|
||||||
WithVideoPlayerActive();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(EdenActivePlayers);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersEden("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
result.First().Type.Should().Be("video");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetActivePlayersEden_should_have_active_audio_player()
|
|
||||||
{
|
|
||||||
|
|
||||||
WithAudioPlayerActive();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(EdenActivePlayers);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersEden("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
result.First().Type.Should().Be("audio");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetActivePlayersEden_should_have_active_picture_player()
|
|
||||||
{
|
|
||||||
|
|
||||||
WithPicturePlayerActive();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(EdenActivePlayers);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersEden("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
result.First().Type.Should().Be("picture");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetActivePlayersEden_should_have_all_players_active()
|
|
||||||
{
|
|
||||||
|
|
||||||
WithAllPlayersActive();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(EdenActivePlayers);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetActivePlayersEden("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(3);
|
|
||||||
result.Select(a => a.PlayerId).Distinct().Should().HaveCount(3);
|
|
||||||
result.Select(a => a.Type).Distinct().Should().HaveCount(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetTvShowsJson()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny<string>()))
|
|
||||||
.Returns(message);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetTvShowsJson("localhost:8080", "xbmc", "xbmc");
|
|
||||||
|
|
||||||
|
|
||||||
Assert.AreEqual(5, result.Count);
|
|
||||||
result.Should().Contain(s => s.ImdbNumber == 79488);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Notify_true()
|
|
||||||
{
|
|
||||||
var header = "NzbDrone Test";
|
|
||||||
var message = "Test Message!";
|
|
||||||
|
|
||||||
var fakeEventClient = Mocker.GetMock<EventClientProvider>();
|
|
||||||
fakeEventClient.Setup(s => s.SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", "localhost")).Returns(true);
|
|
||||||
|
|
||||||
Mocker.Resolve<XbmcProvider>().Notify(_settings, header, message);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendCommand()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(url, username, password)).Returns("Ok\n");
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().SendCommand(host, command, username, username);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
Assert.AreEqual("Ok\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetXbmcSeriesPath_true()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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<IHttpProvider>();
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetXbmcSeriesPath(host, 79488, username, username);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
Assert.AreEqual("smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetXbmcSeriesPath_false()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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<IHttpProvider>();
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetXbmcSeriesPath(host, 79488, username, username);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
Assert.AreEqual("", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetXbmcSeriesPath_special_characters()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/</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<IHttpProvider>();
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().GetXbmcSeriesPath(host, 79488, username, username);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
result.Should().Be("smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Clean()
|
|
||||||
{
|
|
||||||
var fakeEventClient = Mocker.GetMock<EventClientProvider>();
|
|
||||||
fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(CleanLibrary(video))")).Returns(true);
|
|
||||||
|
|
||||||
Mocker.Resolve<XbmcProvider>().Clean(_settings);
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithHttp_Single()
|
|
||||||
{
|
|
||||||
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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(queryUrl, username, password)).Returns(queryResult);
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(url, username, password));
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<XbmcProvider>().UpdateWithHttp(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithHttp_All()
|
|
||||||
{
|
|
||||||
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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(queryUrl, username, password)).Returns(queryResult);
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(url, username, password));
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<XbmcProvider>().UpdateWithHttp(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.VerifyAllMocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithJsonBuiltIn_Single()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var host = "localhost:8080";
|
|
||||||
var username = "xbmc";
|
|
||||||
var password = "xbmc";
|
|
||||||
var expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"properties\":[\"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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<string>(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", ""))))
|
|
||||||
.Returns(tvshows);
|
|
||||||
|
|
||||||
var command = "ExecBuiltIn(UpdateLibrary(video,smb://HOMESERVER/TV/30 Rock/))";
|
|
||||||
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
|
|
||||||
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(url, username, password)).Returns("<html><li>OK</html>");
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().UpdateWithJsonExecBuiltIn(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithJsonBuiltIn_All()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var host = "localhost:8080";
|
|
||||||
var username = "xbmc";
|
|
||||||
var password = "xbmc";
|
|
||||||
var expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"properties\":[\"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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<string>(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", ""))))
|
|
||||||
.Returns(tvshows);
|
|
||||||
|
|
||||||
var command = "ExecBuiltIn(UpdateLibrary(video))";
|
|
||||||
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
|
|
||||||
|
|
||||||
fakeHttp.Setup(s => s.DownloadString(url, username, password)).Returns("<html><li>OK</html>");
|
|
||||||
|
|
||||||
//var fakeEventClient = Mocker.GetMock<EventClientProvider>();
|
|
||||||
//fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(UpdateLibrary(video))"));
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().UpdateWithJsonExecBuiltIn(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithJsonVideoLibraryScan_Single()
|
|
||||||
{
|
|
||||||
var host = "localhost:8080";
|
|
||||||
var username = "xbmc";
|
|
||||||
var password = "xbmc";
|
|
||||||
var expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"properties\":[\"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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<string>(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", ""))))
|
|
||||||
.Returns(tvshows);
|
|
||||||
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<String>(
|
|
||||||
e => e.Replace(" ", "")
|
|
||||||
.Replace("\r\n", "")
|
|
||||||
.Replace("\t", "")
|
|
||||||
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))))
|
|
||||||
.Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}");
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().UpdateWithJsonVideoLibraryScan(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateWithJsonVideoLibraryScan_All()
|
|
||||||
{
|
|
||||||
var host = "localhost:8080";
|
|
||||||
var username = "xbmc";
|
|
||||||
var password = "xbmc";
|
|
||||||
var expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.GetTvShows\",\"params\":{\"properties\":[\"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.Id = 79488)
|
|
||||||
.With(s => s.Title = "30 Rock")
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var fakeHttp = Mocker.GetMock<IHttpProvider>();
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<string>(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", ""))))
|
|
||||||
.Returns(tvshows);
|
|
||||||
|
|
||||||
fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is<String>(
|
|
||||||
e => !e.Replace(" ", "")
|
|
||||||
.Replace("\r\n", "")
|
|
||||||
.Replace("\t", "")
|
|
||||||
.Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}"))))
|
|
||||||
.Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}");
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<XbmcProvider>().UpdateWithJsonVideoLibraryScan(fakeSeries, host, username, password);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Model.Xbmc
|
|
||||||
{
|
|
||||||
public enum ActionType
|
|
||||||
{
|
|
||||||
ExecBuiltin = 0x01,
|
|
||||||
Button = 0x02
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,5 +15,11 @@ namespace NzbDrone.Core.Model.Xbmc
|
||||||
{
|
{
|
||||||
public int PlayerId { get; set; }
|
public int PlayerId { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
public ActivePlayer(int playerId, string type)
|
||||||
|
{
|
||||||
|
PlayerId = playerId;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Model.Xbmc
|
|
||||||
{
|
|
||||||
public enum IconType
|
|
||||||
{
|
|
||||||
None = 0x00,
|
|
||||||
Jpeg = 0x01,
|
|
||||||
Png = 0x02,
|
|
||||||
Gif = 0x03
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
using System;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Model.Xbmc;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Xbmc
|
|
||||||
{
|
|
||||||
public class EventClientProvider
|
|
||||||
{
|
|
||||||
private readonly UdpProvider _udpProvider;
|
|
||||||
|
|
||||||
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++] = 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,190 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using NLog;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public class HttpApiProvider : IApiProvider
|
||||||
|
{
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public HttpApiProvider(IHttpProvider httpProvider, Logger logger)
|
||||||
|
{
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify(XbmcSettings settings, string title, string message)
|
||||||
|
{
|
||||||
|
var notification = String.Format("Notification({0},{1},{2},{3})", title, message, 5000, "https://raw.github.com/NzbDrone/NzbDrone/vnext/NzbDrone.Core/NzbDrone.jpg");
|
||||||
|
var command = BuildExecBuiltInCommand(notification);
|
||||||
|
|
||||||
|
SendCommand(settings, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
if (!settings.AlwaysUpdate)
|
||||||
|
{
|
||||||
|
_logger.Trace("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||||
|
var activePlayers = GetActivePlayers(settings);
|
||||||
|
|
||||||
|
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||||
|
{
|
||||||
|
_logger.Debug("Video is currently playing, skipping library update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateLibrary(settings, series);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
const string cleanVideoLibrary = "CleanLibrary(video)";
|
||||||
|
var command = BuildExecBuiltInCommand(cleanVideoLibrary);
|
||||||
|
|
||||||
|
SendCommand(settings, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ActivePlayer> GetActivePlayers(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = new List<ActivePlayer>();
|
||||||
|
var response = SendCommand(settings, "getcurrentlyplaying");
|
||||||
|
|
||||||
|
if (response.Contains("<li>Filename:[Nothing Playing]")) return new List<ActivePlayer>();
|
||||||
|
if (response.Contains("<li>Type:Video")) result.Add(new ActivePlayer(1, "video"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ActivePlayer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CheckForError(string response)
|
||||||
|
{
|
||||||
|
_logger.Trace("Looking for error in response: {0}", response);
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(response))
|
||||||
|
{
|
||||||
|
_logger.Debug("Invalid response from XBMC, the response is not valid JSON");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorIndex = response.IndexOf("Error", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
|
if (errorIndex > -1)
|
||||||
|
{
|
||||||
|
var errorMessage = response.Substring(errorIndex + 6);
|
||||||
|
errorMessage = errorMessage.Substring(0, errorMessage.IndexOfAny(new char[] { '<', ';' }));
|
||||||
|
|
||||||
|
_logger.Trace("Error found in response: {0}", errorMessage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSeriesPath(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
var query =
|
||||||
|
String.Format(
|
||||||
|
"select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = {0} and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath",
|
||||||
|
series.TvdbId);
|
||||||
|
var command = String.Format("QueryVideoDatabase({0})", query);
|
||||||
|
|
||||||
|
const string setResponseCommand =
|
||||||
|
"SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
||||||
|
const string resetResponseCommand = "SetResponseFormat()";
|
||||||
|
|
||||||
|
SendCommand(settings, setResponseCommand);
|
||||||
|
var response = SendCommand(settings, command);
|
||||||
|
SendCommand(settings, resetResponseCommand);
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(response))
|
||||||
|
return String.Empty;
|
||||||
|
|
||||||
|
var xDoc = XDocument.Load(new StringReader(response.Replace("&", "&")));
|
||||||
|
var xml = (from x in xDoc.Descendants("xml") select x).FirstOrDefault();
|
||||||
|
|
||||||
|
if (xml == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var field = xml.Descendants("field").FirstOrDefault();
|
||||||
|
|
||||||
|
if (field == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return field.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(XbmcVersion version)
|
||||||
|
{
|
||||||
|
return version < new XbmcVersion(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLibrary(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Trace("Sending Update DB Request to XBMC Host: {0}", settings.Address);
|
||||||
|
var xbmcSeriesPath = GetSeriesPath(settings, series);
|
||||||
|
|
||||||
|
//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, settings.Address);
|
||||||
|
var command = BuildExecBuiltInCommand(String.Format("UpdateLibrary(video,{0})", xbmcSeriesPath));
|
||||||
|
SendCommand(settings, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Update the entire library
|
||||||
|
_logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title, settings.Address);
|
||||||
|
var command = BuildExecBuiltInCommand("UpdateLibrary(video)");
|
||||||
|
SendCommand(settings, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SendCommand(XbmcSettings settings, string command)
|
||||||
|
{
|
||||||
|
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", settings.Address, command);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(settings.Username))
|
||||||
|
{
|
||||||
|
return _httpProvider.DownloadString(url, settings.Username, settings.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _httpProvider.DownloadString(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildExecBuiltInCommand(string command)
|
||||||
|
{
|
||||||
|
return String.Format("ExecBuiltIn({0})", command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public interface IApiProvider
|
||||||
|
{
|
||||||
|
void Notify(XbmcSettings settings, string title, string message);
|
||||||
|
void Update(XbmcSettings settings, Series series);
|
||||||
|
void Clean(XbmcSettings settings);
|
||||||
|
List<ActivePlayer> GetActivePlayers(XbmcSettings settings);
|
||||||
|
bool CheckForError(string response);
|
||||||
|
string GetSeriesPath(XbmcSettings settings, Series series);
|
||||||
|
bool CanHandle(XbmcVersion version);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public class InvalidXbmcVersionException : Exception
|
||||||
|
{
|
||||||
|
public InvalidXbmcVersionException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidXbmcVersionException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NLog;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public class JsonApiProvider : IApiProvider
|
||||||
|
{
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public JsonApiProvider(IHttpProvider httpProvider, Logger logger)
|
||||||
|
{
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify(XbmcSettings settings, string title, string message)
|
||||||
|
{
|
||||||
|
var parameters = new JObject(
|
||||||
|
new JProperty("title", title),
|
||||||
|
new JProperty("message", message),
|
||||||
|
new JProperty("image", "https://raw.github.com/NzbDrone/NzbDrone/vnext/NzbDrone.Core/NzbDrone.jpg"));
|
||||||
|
|
||||||
|
var postJson = BuildJsonRequest("GUI.ShowNotification", parameters);
|
||||||
|
|
||||||
|
_httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
if (!settings.AlwaysUpdate)
|
||||||
|
{
|
||||||
|
_logger.Trace("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||||
|
var activePlayers = GetActivePlayers(settings);
|
||||||
|
|
||||||
|
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||||
|
{
|
||||||
|
_logger.Debug("Video is currently playing, skipping library update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateLibrary(settings, series);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
var postJson = BuildJsonRequest("VideoLibrary.Clean");
|
||||||
|
|
||||||
|
_httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ActivePlayer> GetActivePlayers(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var postJson = new JObject();
|
||||||
|
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
||||||
|
postJson.Add(new JProperty("method", "Player.GetActivePlayers"));
|
||||||
|
postJson.Add(new JProperty("id", 10));
|
||||||
|
|
||||||
|
var response = _httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
|
||||||
|
if (CheckForError(response))
|
||||||
|
return new List<ActivePlayer>();
|
||||||
|
|
||||||
|
var result = JsonConvert.DeserializeObject<ActivePlayersEdenResult>(response);
|
||||||
|
|
||||||
|
return result.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ActivePlayer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CheckForError(string response)
|
||||||
|
{
|
||||||
|
_logger.Trace("Looking for error in response: {0}", response);
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(response))
|
||||||
|
{
|
||||||
|
_logger.Debug("Invalid response from XBMC, the response is not valid JSON");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.StartsWith("{\"error\""))
|
||||||
|
{
|
||||||
|
var error = JsonConvert.DeserializeObject<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSeriesPath(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
var allSeries = GetSeries(settings);
|
||||||
|
|
||||||
|
if (!allSeries.Any())
|
||||||
|
{
|
||||||
|
_logger.Trace("No TV shows returned from XBMC");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var matchingSeries = allSeries.FirstOrDefault(s => s.ImdbNumber == series.TvdbId || s.Label == series.Title);
|
||||||
|
|
||||||
|
if (matchingSeries != null) return matchingSeries.File;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(XbmcVersion version)
|
||||||
|
{
|
||||||
|
return version >= new XbmcVersion(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLibrary(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var seriesPath = GetSeriesPath(settings, series);
|
||||||
|
|
||||||
|
JObject postJson;
|
||||||
|
|
||||||
|
if (seriesPath != null)
|
||||||
|
{
|
||||||
|
_logger.Trace("Updating series [{0}] (Path: {1}) on XBMC host: {2}", series.Title, seriesPath, settings.Address);
|
||||||
|
|
||||||
|
var parameters = new JObject(new JObject(new JProperty("directory", seriesPath)));
|
||||||
|
postJson = BuildJsonRequest("VideoLibrary.Scan", parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title,
|
||||||
|
settings.Address);
|
||||||
|
|
||||||
|
postJson = BuildJsonRequest("VideoLibrary.Scan");
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = _httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
|
||||||
|
if (CheckForError(response)) return;
|
||||||
|
|
||||||
|
_logger.Trace(" from response");
|
||||||
|
var result = JsonConvert.DeserializeObject<XbmcJsonResult<String>>(response);
|
||||||
|
|
||||||
|
if (!result.Result.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.Trace("Failed to update library for: {0}", settings.Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TvShow> GetSeries(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var properties = new JObject { new JProperty("properties", new[] { "file", "imdbnumber" }) };
|
||||||
|
var postJson = BuildJsonRequest("VideoLibrary.GetTvShows", properties);
|
||||||
|
|
||||||
|
var response = _httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
|
||||||
|
if (CheckForError(response))
|
||||||
|
return new List<TvShow>();
|
||||||
|
|
||||||
|
var result = JsonConvert.DeserializeObject<TvShowResponse>(response);
|
||||||
|
var shows = result.Result.TvShows;
|
||||||
|
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<TvShow>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JObject BuildJsonRequest(string method)
|
||||||
|
{
|
||||||
|
return BuildJsonRequest(method, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JObject BuildJsonRequest(string method, JObject parameters)
|
||||||
|
{
|
||||||
|
var postJson = new JObject();
|
||||||
|
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
||||||
|
postJson.Add(new JProperty("method", method));
|
||||||
|
|
||||||
|
if (parameters != null)
|
||||||
|
{
|
||||||
|
postJson.Add(new JProperty("params", parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
postJson.Add(new JProperty("id", 10));
|
||||||
|
|
||||||
|
return postJson;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public class TestXbmcCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
{
|
{
|
||||||
public class Xbmc : NotificationBase<XbmcSettings>
|
public class Xbmc : NotificationBase<XbmcSettings>
|
||||||
{
|
{
|
||||||
private readonly XbmcProvider _xbmcProvider;
|
private readonly IXbmcService _xbmcProvider;
|
||||||
|
|
||||||
public Xbmc(XbmcProvider xbmcProvider, Logger logger)
|
public Xbmc(IXbmcService xbmcProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_xbmcProvider = xbmcProvider;
|
_xbmcProvider = xbmcProvider;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,455 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
using NzbDrone.Core.Model.Xbmc;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Xbmc
|
|
||||||
{
|
|
||||||
public class XbmcProvider
|
|
||||||
{
|
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
||||||
private readonly IHttpProvider _httpProvider;
|
|
||||||
private readonly EventClientProvider _eventClientProvider;
|
|
||||||
|
|
||||||
public XbmcProvider(IHttpProvider httpProvider, EventClientProvider eventClientProvider)
|
|
||||||
{
|
|
||||||
_httpProvider = httpProvider;
|
|
||||||
_eventClientProvider = eventClientProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Notify(XbmcSettings settings, string header, string message)
|
|
||||||
{
|
|
||||||
//Always use EventServer, until Json has real support for it
|
|
||||||
var host = settings.Host;
|
|
||||||
Logger.Trace("Sending Notifcation to XBMC Host: {0}", host);
|
|
||||||
_eventClientProvider.SendNotification(header, message, IconType.Jpeg, "NzbDrone.jpg", host);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Update(XbmcSettings settings, 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 = settings.Username;
|
|
||||||
var password = settings.Password;
|
|
||||||
var address = String.Format("{0}:{1}", settings.Host, settings.Port);
|
|
||||||
|
|
||||||
Logger.Trace("Determining version of XBMC Host: {0}", address);
|
|
||||||
var version = GetJsonVersion(address, username, password);
|
|
||||||
|
|
||||||
//Dharma
|
|
||||||
if (version == new XbmcVersion(2))
|
|
||||||
{
|
|
||||||
//Check for active player only when we should skip updates when playing
|
|
||||||
if (!settings.AlwaysUpdate)
|
|
||||||
{
|
|
||||||
Logger.Trace("Determining if there are any active players on XBMC host: {0}", address);
|
|
||||||
var activePlayers = GetActivePlayersDharma(address, username, password);
|
|
||||||
|
|
||||||
//If video is currently playing, then skip update
|
|
||||||
if (activePlayers["video"])
|
|
||||||
{
|
|
||||||
Logger.Debug("Video is currently playing, skipping library update");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateWithHttp(series, address, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Eden
|
|
||||||
else if (version == new XbmcVersion(3) || version == new XbmcVersion(4))
|
|
||||||
{
|
|
||||||
//Check for active player only when we should skip updates when playing
|
|
||||||
if (!settings.AlwaysUpdate)
|
|
||||||
{
|
|
||||||
Logger.Trace("Determining if there are any active players on XBMC host: {0}", address);
|
|
||||||
var activePlayers = GetActivePlayersEden(address, username, password);
|
|
||||||
|
|
||||||
//If video is currently playing, then skip update
|
|
||||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
|
||||||
{
|
|
||||||
Logger.Debug("Video is currently playing, skipping library update");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateWithJsonExecBuiltIn(series, address, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Frodo or newer (attempting to make it future compatible)
|
|
||||||
else if (version >= new XbmcVersion(5))
|
|
||||||
{
|
|
||||||
//Check for active player only when we should skip updates when playing
|
|
||||||
if (!settings.AlwaysUpdate)
|
|
||||||
{
|
|
||||||
Logger.Trace("Determining if there are any active players on XBMC host: {0}", address);
|
|
||||||
var activePlayers = GetActivePlayersEden(address, username, password);
|
|
||||||
|
|
||||||
//If video is currently playing, then skip update
|
|
||||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
|
||||||
{
|
|
||||||
Logger.Debug("Video is currently playing, skipping library update");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateWithJsonVideoLibraryScan(series, address, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log Version zero if check failed
|
|
||||||
else
|
|
||||||
Logger.Trace("Unknown version: [{0}], skipping.", version);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool UpdateWithJsonExecBuiltIn(Series series, string host, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Use Json!
|
|
||||||
var xbmcShows = GetTvShowsJson(host, username, password);
|
|
||||||
|
|
||||||
TvShow path = null;
|
|
||||||
|
|
||||||
//Log if response is null, otherwise try to find XBMC's path for series
|
|
||||||
if (xbmcShows == null)
|
|
||||||
Logger.Trace("Failed to get TV Shows from XBMC");
|
|
||||||
|
|
||||||
else
|
|
||||||
path = xbmcShows.FirstOrDefault(s => s.ImdbNumber == series.Id || s.Label == series.Title);
|
|
||||||
|
|
||||||
//var hostOnly = GetHostWithoutPort(host);
|
|
||||||
|
|
||||||
if (path != null)
|
|
||||||
{
|
|
||||||
Logger.Trace("Updating series [{0}] (Path: {1}) on XBMC host: {2}", series.Title, path.File, host);
|
|
||||||
var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path.File);
|
|
||||||
SendCommand(host, command, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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 bool UpdateWithJsonVideoLibraryScan(Series series, string host, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Use Json!
|
|
||||||
var xbmcShows = GetTvShowsJson(host, username, password);
|
|
||||||
|
|
||||||
TvShow path = null;
|
|
||||||
|
|
||||||
//Log if response is null, otherwise try to find XBMC's path for series
|
|
||||||
if (xbmcShows == null)
|
|
||||||
Logger.Trace("Failed to get TV Shows from XBMC");
|
|
||||||
|
|
||||||
else
|
|
||||||
path = xbmcShows.FirstOrDefault(s => s.ImdbNumber == series.TvdbId || s.Label == series.Title);
|
|
||||||
|
|
||||||
var postJson = new JObject();
|
|
||||||
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
|
||||||
postJson.Add(new JProperty("method", "VideoLibrary.Scan"));
|
|
||||||
postJson.Add(new JProperty("id", 55));
|
|
||||||
|
|
||||||
if (path != null)
|
|
||||||
{
|
|
||||||
Logger.Trace("Updating series [{0}] (Path: {1}) on XBMC host: {2}", series.Title, path.File, host);
|
|
||||||
postJson.Add(new JProperty("params", new JObject(new JObject(new JProperty("directory", path.File)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title, host);
|
|
||||||
|
|
||||||
var response = _httpProvider.PostCommand(host, username, password, postJson.ToString());
|
|
||||||
|
|
||||||
if (CheckForJsonError(response))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Logger.Trace(" from response");
|
|
||||||
var result = JsonConvert.DeserializeObject<XbmcJsonResult<String>>(response);
|
|
||||||
|
|
||||||
if (!result.Result.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Id, 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(XbmcSettings settings)
|
|
||||||
{
|
|
||||||
//Use EventServer, once Dharma is extinct use Json?
|
|
||||||
|
|
||||||
var host = settings.Host;
|
|
||||||
Logger.Trace("Sending DB Clean Request to XBMC Host: {0}", host);
|
|
||||||
var command = "ExecBuiltIn(CleanLibrary(video))";
|
|
||||||
_eventClientProvider.SendAction(host, ActionType.ExecBuiltin, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string SendCommand(string host, string command, string username, string password)
|
|
||||||
{
|
|
||||||
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(username))
|
|
||||||
{
|
|
||||||
return _httpProvider.DownloadString(url, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _httpProvider.DownloadString(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string GetXbmcSeriesPath(string host, int seriesId, string username, string password)
|
|
||||||
{
|
|
||||||
var query =
|
|
||||||
String.Format(
|
|
||||||
"select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = {0} and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath",
|
|
||||||
seriesId);
|
|
||||||
var command = String.Format("QueryVideoDatabase({0})", query);
|
|
||||||
|
|
||||||
const string setResponseCommand =
|
|
||||||
"SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
|
|
||||||
const string resetResponseCommand = "SetResponseFormat()";
|
|
||||||
|
|
||||||
SendCommand(host, setResponseCommand, username, password);
|
|
||||||
var response = SendCommand(host, command, username, password);
|
|
||||||
SendCommand(host, resetResponseCommand, username, password);
|
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(response))
|
|
||||||
return String.Empty;
|
|
||||||
|
|
||||||
var xDoc = XDocument.Load(new StringReader(response.Replace("&", "&")));
|
|
||||||
var xml = (from x in xDoc.Descendants("xml") select x).FirstOrDefault();
|
|
||||||
|
|
||||||
if (xml == null)
|
|
||||||
return String.Empty;
|
|
||||||
|
|
||||||
var field = xml.Descendants("field").FirstOrDefault();
|
|
||||||
|
|
||||||
if (field == null)
|
|
||||||
return String.Empty;
|
|
||||||
|
|
||||||
return field.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual XbmcVersion GetJsonVersion(string host, string username, string password)
|
|
||||||
{
|
|
||||||
//2 = Dharma
|
|
||||||
//3 & 4 = Eden
|
|
||||||
//5 & 6 = Frodo
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var postJson = new JObject();
|
|
||||||
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
|
||||||
postJson.Add(new JProperty("method", "JSONRPC.Version"));
|
|
||||||
postJson.Add(new JProperty("id", 10));
|
|
||||||
|
|
||||||
var response = _httpProvider.PostCommand(host, username, password, postJson.ToString());
|
|
||||||
|
|
||||||
if (CheckForJsonError(response))
|
|
||||||
return new XbmcVersion();
|
|
||||||
|
|
||||||
Logger.Trace("Getting version from response");
|
|
||||||
var result = JsonConvert.DeserializeObject<XbmcJsonResult<JObject>>(response);
|
|
||||||
|
|
||||||
var versionObject = result.Result.Property("version");
|
|
||||||
|
|
||||||
if (versionObject.Value.Type == JTokenType.Integer)
|
|
||||||
return new XbmcVersion((int)versionObject.Value);
|
|
||||||
|
|
||||||
if (versionObject.Value.Type == JTokenType.Object)
|
|
||||||
return JsonConvert.DeserializeObject<XbmcVersion>(versionObject.Value.ToString());
|
|
||||||
|
|
||||||
throw new InvalidCastException("Unknown Version structure!: " + versionObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.DebugException(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new XbmcVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Dictionary<string, bool> GetActivePlayersDharma(string host, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var postJson = new JObject();
|
|
||||||
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
|
||||||
postJson.Add(new JProperty("method", "Player.GetActivePlayers"));
|
|
||||||
postJson.Add(new JProperty("id", 10));
|
|
||||||
|
|
||||||
var response = _httpProvider.PostCommand(host, username, password, postJson.ToString());
|
|
||||||
|
|
||||||
if (CheckForJsonError(response))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var result = JsonConvert.DeserializeObject<ActivePlayersDharmaResult>(response);
|
|
||||||
|
|
||||||
return result.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.DebugException(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual List<ActivePlayer> GetActivePlayersEden(string host, string username, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var postJson = new JObject();
|
|
||||||
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
|
||||||
postJson.Add(new JProperty("method", "Player.GetActivePlayers"));
|
|
||||||
postJson.Add(new JProperty("id", 10));
|
|
||||||
|
|
||||||
var response = _httpProvider.PostCommand(host, username, password, postJson.ToString());
|
|
||||||
|
|
||||||
if (CheckForJsonError(response))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var result = JsonConvert.DeserializeObject<ActivePlayersEdenResult>(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 postJson = new JObject();
|
|
||||||
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
|
||||||
postJson.Add(new JProperty("method", "VideoLibrary.GetTvShows"));
|
|
||||||
postJson.Add(new JProperty("params", new JObject { new JProperty("properties", new string[] { "file", "imdbnumber" }) }));
|
|
||||||
postJson.Add(new JProperty("id", 10));
|
|
||||||
|
|
||||||
var response = _httpProvider.PostCommand(host, username, password, postJson.ToString());
|
|
||||||
|
|
||||||
if (CheckForJsonError(response))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var result = JsonConvert.DeserializeObject<TvShowResponse>(response);
|
|
||||||
var shows = result.Result.TvShows;
|
|
||||||
|
|
||||||
return shows;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.DebugException(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool CheckForJsonError(string response)
|
|
||||||
{
|
|
||||||
Logger.Trace("Looking for error in response: {0}", response);
|
|
||||||
|
|
||||||
if (response.StartsWith("{\"error\""))
|
|
||||||
{
|
|
||||||
var error = JsonConvert.DeserializeObject<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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(response))
|
|
||||||
{
|
|
||||||
Logger.Debug("Invalid response from XBMC, the response is not valid JSON");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void TestNotification(string hosts)
|
|
||||||
{
|
|
||||||
foreach (var host in hosts.Split(','))
|
|
||||||
{
|
|
||||||
Logger.Trace("Sending Test Notifcation to XBMC Host: {0}", host);
|
|
||||||
_eventClientProvider.SendNotification("Test Notification", "Success! Notifications are setup correctly", IconType.Jpeg, "NzbDrone.jpg", host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void TestJsonApi(string hosts, string username, string password)
|
|
||||||
{
|
|
||||||
foreach (var host in hosts.Split(','))
|
|
||||||
{
|
|
||||||
Logger.Trace("Sending Test Notifcation to XBMC Host: {0}", host);
|
|
||||||
var version = GetJsonVersion(host, username, password);
|
|
||||||
if (version == new XbmcVersion())
|
|
||||||
throw new Exception("Failed to get JSON version in test");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Model.Xbmc;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
{
|
||||||
|
public interface IXbmcService
|
||||||
|
{
|
||||||
|
void Notify(XbmcSettings settings, string title, string message);
|
||||||
|
void Update(XbmcSettings settings, Series series);
|
||||||
|
void Clean(XbmcSettings settings);
|
||||||
|
XbmcVersion GetJsonVersion(XbmcSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class XbmcService : IXbmcService, IExecute<TestXbmcCommand>
|
||||||
|
{
|
||||||
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly IEnumerable<IApiProvider> _apiProviders;
|
||||||
|
|
||||||
|
public XbmcService(IHttpProvider httpProvider, IEnumerable<IApiProvider> apiProviders)
|
||||||
|
{
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_apiProviders = apiProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify(XbmcSettings settings, string title, string message)
|
||||||
|
{
|
||||||
|
var provider = GetApiProvider(settings);
|
||||||
|
provider.Notify(settings, title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(XbmcSettings settings, Series series)
|
||||||
|
{
|
||||||
|
var provider = GetApiProvider(settings);
|
||||||
|
provider.Update(settings, series);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
var provider = GetApiProvider(settings);
|
||||||
|
provider.Clean(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XbmcVersion GetJsonVersion(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var postJson = new JObject();
|
||||||
|
postJson.Add(new JProperty("jsonrpc", "2.0"));
|
||||||
|
postJson.Add(new JProperty("method", "JSONRPC.Version"));
|
||||||
|
postJson.Add(new JProperty("id", 10));
|
||||||
|
|
||||||
|
var response = _httpProvider.PostCommand(settings.Address, settings.Username, settings.Password, postJson.ToString());
|
||||||
|
|
||||||
|
Logger.Trace("Getting version from response");
|
||||||
|
var result = JsonConvert.DeserializeObject<XbmcJsonResult<JObject>>(response);
|
||||||
|
|
||||||
|
var versionObject = result.Result.Property("version");
|
||||||
|
|
||||||
|
if (versionObject.Value.Type == JTokenType.Integer)
|
||||||
|
return new XbmcVersion((int)versionObject.Value);
|
||||||
|
|
||||||
|
if (versionObject.Value.Type == JTokenType.Object)
|
||||||
|
return JsonConvert.DeserializeObject<XbmcVersion>(versionObject.Value.ToString());
|
||||||
|
|
||||||
|
throw new InvalidCastException("Unknown Version structure!: " + versionObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new XbmcVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IApiProvider GetApiProvider(XbmcSettings settings)
|
||||||
|
{
|
||||||
|
var version = GetJsonVersion(settings);
|
||||||
|
var apiProvider = _apiProviders.SingleOrDefault(a => a.CanHandle(version));
|
||||||
|
|
||||||
|
if (apiProvider == null)
|
||||||
|
{
|
||||||
|
var message = String.Format("Invalid API Version: {0} for {1}", version, settings.Address);
|
||||||
|
throw new InvalidXbmcVersionException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestXbmcCommand message)
|
||||||
|
{
|
||||||
|
var settings = new XbmcSettings
|
||||||
|
{
|
||||||
|
Host = message.Host,
|
||||||
|
Port = message.Port,
|
||||||
|
Username = message.Username,
|
||||||
|
Password = message.Password
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger.Trace("Determining version of XBMC Host: {0}", settings.Address);
|
||||||
|
var version = GetJsonVersion(settings);
|
||||||
|
Logger.Trace("Version is: {0}", version);
|
||||||
|
|
||||||
|
Notify(settings, "Test Notification", "Success! XBMC has been successfully configured!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Xbmc
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
|
@ -32,6 +33,9 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
[FieldDefinition(7, Label = "Always Update", HelpText = "Update Library even when a video is playing?", Type = FieldType.Checkbox)]
|
[FieldDefinition(7, Label = "Always Update", HelpText = "Update Library even when a video is playing?", Type = FieldType.Checkbox)]
|
||||||
public Boolean AlwaysUpdate { get; set; }
|
public Boolean AlwaysUpdate { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public String Address { get { return String.Format("{0}:{1}", Host, Port); } }
|
||||||
|
|
||||||
public bool IsValid
|
public bool IsValid
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -329,6 +329,11 @@
|
||||||
<Compile Include="Notifications\Plex\PlexServerSettings.cs" />
|
<Compile Include="Notifications\Plex\PlexServerSettings.cs" />
|
||||||
<Compile Include="Notifications\Prowl\ProwlSettings.cs" />
|
<Compile Include="Notifications\Prowl\ProwlSettings.cs" />
|
||||||
<Compile Include="Notifications\Email\EmailSettings.cs" />
|
<Compile Include="Notifications\Email\EmailSettings.cs" />
|
||||||
|
<Compile Include="Notifications\Xbmc\HttpApiProvider.cs" />
|
||||||
|
<Compile Include="Notifications\Xbmc\IApiProvider.cs" />
|
||||||
|
<Compile Include="Notifications\Xbmc\InvalidXbmcVersionException.cs" />
|
||||||
|
<Compile Include="Notifications\Xbmc\JsonApiProvider.cs" />
|
||||||
|
<Compile Include="Notifications\Xbmc\TestXbmcCommand.cs" />
|
||||||
<Compile Include="Notifications\Xbmc\XbmcSettings.cs" />
|
<Compile Include="Notifications\Xbmc\XbmcSettings.cs" />
|
||||||
<Compile Include="Organizer\EpisodeSortingType.cs" />
|
<Compile Include="Organizer\EpisodeSortingType.cs" />
|
||||||
<Compile Include="Organizer\FileNameBuilder.cs" />
|
<Compile Include="Organizer\FileNameBuilder.cs" />
|
||||||
|
@ -379,12 +384,10 @@
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabModel.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabModel.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabQueueItem.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabQueueItem.cs" />
|
||||||
<Compile Include="Download\Clients\Sabnzbd\SabVersionModel.cs" />
|
<Compile Include="Download\Clients\Sabnzbd\SabVersionModel.cs" />
|
||||||
<Compile Include="Model\Xbmc\ActionType.cs" />
|
|
||||||
<Compile Include="Model\Xbmc\ActivePlayersDharmaResult.cs" />
|
<Compile Include="Model\Xbmc\ActivePlayersDharmaResult.cs" />
|
||||||
<Compile Include="Model\Xbmc\ActivePlayersEdenResult.cs" />
|
<Compile Include="Model\Xbmc\ActivePlayersEdenResult.cs" />
|
||||||
<Compile Include="Model\Xbmc\TvShowResult.cs" />
|
<Compile Include="Model\Xbmc\TvShowResult.cs" />
|
||||||
<Compile Include="Model\Xbmc\ErrorResult.cs" />
|
<Compile Include="Model\Xbmc\ErrorResult.cs" />
|
||||||
<Compile Include="Model\Xbmc\IconType.cs" />
|
|
||||||
<Compile Include="Model\Xbmc\XbmcJsonResult.cs" />
|
<Compile Include="Model\Xbmc\XbmcJsonResult.cs" />
|
||||||
<Compile Include="Model\Xbmc\XbmcVersion.cs" />
|
<Compile Include="Model\Xbmc\XbmcVersion.cs" />
|
||||||
<Compile Include="Model\Xem\XemResult.cs" />
|
<Compile Include="Model\Xem\XemResult.cs" />
|
||||||
|
@ -492,10 +495,7 @@
|
||||||
<Compile Include="Notifications\Email\EmailProvider.cs">
|
<Compile Include="Notifications\Email\EmailProvider.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Xbmc\XbmcProvider.cs">
|
<Compile Include="Notifications\Xbmc\XbmcService.cs">
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Notifications\Xbmc\EventClientProvider.cs">
|
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Xbmc\ResourceManager.cs">
|
<Compile Include="Notifications\Xbmc\ResourceManager.cs">
|
||||||
|
|
|
@ -3,22 +3,22 @@
|
||||||
<JSRemoteDebuggerConfigurationSettings>
|
<JSRemoteDebuggerConfigurationSettings>
|
||||||
<option name="engineId" value="chrome" />
|
<option name="engineId" value="chrome" />
|
||||||
<option name="fileUrl" value="http://localhost:8989" />
|
<option name="fileUrl" value="http://localhost:8989" />
|
||||||
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
|
<mapping local-file="$PROJECT_DIR$/Calendar" url="http://localhost:8989/Calendar" />
|
||||||
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" />
|
<mapping local-file="$PROJECT_DIR$/MainMenuView.js" url="http://localhost:8989/MainMenuView.js" />
|
||||||
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
|
<mapping local-file="$PROJECT_DIR$/Settings" url="http://localhost:8989/Settings" />
|
||||||
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
|
<mapping local-file="$PROJECT_DIR$/Upcoming" url="http://localhost:8989/Upcoming" />
|
||||||
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
|
<mapping local-file="$PROJECT_DIR$/app.js" url="http://localhost:8989/app.js" />
|
||||||
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
|
<mapping local-file="$PROJECT_DIR$/Mixins" url="http://localhost:8989/Mixins" />
|
||||||
<mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" />
|
<mapping local-file="$PROJECT_DIR$/Missing" url="http://localhost:8989/Missing" />
|
||||||
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
|
<mapping local-file="$PROJECT_DIR$/Quality" url="http://localhost:8989/Quality" />
|
||||||
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
|
<mapping local-file="$PROJECT_DIR$/Config.js" url="http://localhost:8989/Config.js" />
|
||||||
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
|
<mapping local-file="$PROJECT_DIR$/Shared" url="http://localhost:8989/Shared" />
|
||||||
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
|
<mapping local-file="$PROJECT_DIR$/AddSeries" url="http://localhost:8989/AddSeries" />
|
||||||
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
|
<mapping local-file="$PROJECT_DIR$/HeaderView.js" url="http://localhost:8989/HeaderView.js" />
|
||||||
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
|
<mapping local-file="$PROJECT_DIR$" url="http://localhost:8989" />
|
||||||
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
|
<mapping local-file="$PROJECT_DIR$/Routing.js" url="http://localhost:8989/Routing.js" />
|
||||||
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
|
<mapping local-file="$PROJECT_DIR$/Controller.js" url="http://localhost:8989/Controller.js" />
|
||||||
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
|
<mapping local-file="$PROJECT_DIR$/Series" url="http://localhost:8989/Series" />
|
||||||
</JSRemoteDebuggerConfigurationSettings>
|
</JSRemoteDebuggerConfigurationSettings>
|
||||||
<RunnerSettings RunnerId="JavascriptDebugRunner" />
|
<RunnerSettings RunnerId="JavascriptDebugRunner" />
|
||||||
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
|
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
|
||||||
|
|
|
@ -3,22 +3,22 @@
|
||||||
<JSRemoteDebuggerConfigurationSettings>
|
<JSRemoteDebuggerConfigurationSettings>
|
||||||
<option name="engineId" value="firefox" />
|
<option name="engineId" value="firefox" />
|
||||||
<option name="fileUrl" value="http://localhost:8989" />
|
<option name="fileUrl" value="http://localhost:8989" />
|
||||||
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
|
<mapping local-file="$PROJECT_DIR$/Calendar" url="http://localhost:8989/Calendar" />
|
||||||
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" />
|
<mapping local-file="$PROJECT_DIR$/MainMenuView.js" url="http://localhost:8989/MainMenuView.js" />
|
||||||
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
|
<mapping local-file="$PROJECT_DIR$/Settings" url="http://localhost:8989/Settings" />
|
||||||
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
|
<mapping local-file="$PROJECT_DIR$/Upcoming" url="http://localhost:8989/Upcoming" />
|
||||||
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
|
<mapping local-file="$PROJECT_DIR$/app.js" url="http://localhost:8989/app.js" />
|
||||||
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
|
<mapping local-file="$PROJECT_DIR$/Mixins" url="http://localhost:8989/Mixins" />
|
||||||
<mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" />
|
<mapping local-file="$PROJECT_DIR$/Missing" url="http://localhost:8989/Missing" />
|
||||||
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
|
<mapping local-file="$PROJECT_DIR$/Config.js" url="http://localhost:8989/Config.js" />
|
||||||
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
|
<mapping local-file="$PROJECT_DIR$/Quality" url="http://localhost:8989/Quality" />
|
||||||
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
|
<mapping local-file="$PROJECT_DIR$/AddSeries" url="http://localhost:8989/AddSeries" />
|
||||||
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
|
<mapping local-file="$PROJECT_DIR$/Shared" url="http://localhost:8989/Shared" />
|
||||||
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
|
<mapping local-file="$PROJECT_DIR$/HeaderView.js" url="http://localhost:8989/HeaderView.js" />
|
||||||
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
|
<mapping local-file="$PROJECT_DIR$" url="http://localhost:8989" />
|
||||||
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
|
<mapping local-file="$PROJECT_DIR$/Routing.js" url="http://localhost:8989/Routing.js" />
|
||||||
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
|
<mapping local-file="$PROJECT_DIR$/Controller.js" url="http://localhost:8989/Controller.js" />
|
||||||
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
|
<mapping local-file="$PROJECT_DIR$/Series" url="http://localhost:8989/Series" />
|
||||||
</JSRemoteDebuggerConfigurationSettings>
|
</JSRemoteDebuggerConfigurationSettings>
|
||||||
<RunnerSettings RunnerId="JavascriptDebugRunner" />
|
<RunnerSettings RunnerId="JavascriptDebugRunner" />
|
||||||
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
|
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
|
||||||
|
|
Loading…
Reference in New Issue