diff --git a/NzbDrone.Core.Test/ProviderTests/XbmcProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/XbmcProviderTest.cs index dc3692270..9e4a7a19d 100644 --- a/NzbDrone.Core.Test/ProviderTests/XbmcProviderTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/XbmcProviderTest.cs @@ -505,7 +505,7 @@ namespace NzbDrone.Core.Test.ProviderTests } [Test] - public void UpdateWithJson_Single() + public void UpdateWithJsonBuiltIn_Single() { //Setup @@ -530,18 +530,15 @@ namespace NzbDrone.Core.Test.ProviderTests fakeHttp.Setup(s => s.DownloadString(url, username, password)).Returns("
  • OK"); - //var fakeEventClient = Mocker.GetMock(); - //fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(UpdateLibrary(video,smb://HOMESERVER/TV/30 Rock/))")); - //Act - var result = Mocker.Resolve().UpdateWithJson(fakeSeries, host, username, password); + var result = Mocker.Resolve().UpdateWithJsonExecBuiltIn(fakeSeries, host, username, password); //Assert result.Should().BeTrue(); } [Test] - public void UpdateWithJson_All() + public void UpdateWithJsonBuiltIn_All() { //Setup @@ -570,7 +567,71 @@ namespace NzbDrone.Core.Test.ProviderTests //fakeEventClient.Setup(s => s.SendAction("localhost", ActionType.ExecBuiltin, "ExecBuiltIn(UpdateLibrary(video))")); //Act - var result = Mocker.Resolve().UpdateWithJson(fakeSeries, host, username, password); + var result = Mocker.Resolve().UpdateWithJsonExecBuiltIn(fakeSeries, host, username, password); + + //Assert + 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.CreateNew() + .With(s => s.SeriesId = 79488) + .With(s => s.Title = "30 Rock") + .Build(); + + var fakeHttp = Mocker.GetMock(); + fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", "")))) + .Returns(tvshows); + + fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is( + e => e.Replace(" ", "") + .Replace("\r\n", "") + .Replace("\t", "") + .Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}")))) + .Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}"); + + //Act + var result = Mocker.Resolve().UpdateWithJsonVideoLibraryScan(fakeSeries, host, username, password); + + //Assert + 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.CreateNew() + .With(s => s.SeriesId = 79488) + .With(s => s.Title = "30 Rock") + .Build(); + + var fakeHttp = Mocker.GetMock(); + fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is(e => e.Replace(" ", "").Replace("\r\n", "").Replace("\t", "") == expectedJson.Replace(" ", "")))) + .Returns(tvshows); + + fakeHttp.Setup(s => s.PostCommand(host, username, password, It.Is( + e => !e.Replace(" ", "") + .Replace("\r\n", "") + .Replace("\t", "") + .Contains("\"params\":{\"directory\":\"smb://HOMESERVER/TV/30Rock/\"}")))) + .Returns("{\"id\":55,\"jsonrpc\":\"2.0\",\"result\":\"OK\"}"); + + //Act + var result = Mocker.Resolve().UpdateWithJsonVideoLibraryScan(fakeSeries, host, username, password); //Assert result.Should().BeTrue(); diff --git a/NzbDrone.Core/Model/Xbmc/XbmcVersion.cs b/NzbDrone.Core/Model/Xbmc/XbmcVersion.cs index b5ad93ead..5b777844d 100644 --- a/NzbDrone.Core/Model/Xbmc/XbmcVersion.cs +++ b/NzbDrone.Core/Model/Xbmc/XbmcVersion.cs @@ -119,5 +119,10 @@ namespace NzbDrone.Core.Model.Xbmc if (obj.GetType() != typeof(XbmcVersion)) return false; return Equals((XbmcVersion)obj); } + + public static XbmcVersion NONE = new XbmcVersion(0, 0, 0); + public static XbmcVersion DHARMA = new XbmcVersion(2, 0, 0); + public static XbmcVersion EDEN = new XbmcVersion(4, 0, 0); + public static XbmcVersion FRODO = new XbmcVersion(6, 0, 0); } } diff --git a/NzbDrone.Core/Providers/XbmcProvider.cs b/NzbDrone.Core/Providers/XbmcProvider.cs index c4cc4aa8d..62482e869 100644 --- a/NzbDrone.Core/Providers/XbmcProvider.cs +++ b/NzbDrone.Core/Providers/XbmcProvider.cs @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Providers } } - UpdateWithJson(series, host, username, password); + UpdateWithJsonExecBuiltIn(series, host, username, password); } else if (version >= new XbmcVersion(5)) @@ -115,7 +115,7 @@ namespace NzbDrone.Core.Providers } } - UpdateWithJson(series, host, username, password); + UpdateWithJsonVideoLibraryScan(series, host, username, password); } //Log Version zero if check failed @@ -124,7 +124,7 @@ namespace NzbDrone.Core.Providers } } - public virtual bool UpdateWithJson(Series series, string host, string username, string password) + public virtual bool UpdateWithJsonExecBuiltIn(Series series, string host, string username, string password) { try { @@ -145,8 +145,6 @@ namespace NzbDrone.Core.Providers 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); - //_eventClientProvider.SendAction(hostOnly, ActionType.ExecBuiltin, command); var command = String.Format("ExecBuiltIn(UpdateLibrary(video,{0}))", path.File); SendCommand(host, command, username, password); } @@ -154,8 +152,6 @@ namespace NzbDrone.Core.Providers else { Logger.Trace("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series.Title, host); - var command = String.Format("ExecBuiltIn(UpdateLibrary(video))"); - //_eventClientProvider.SendAction(hostOnly, ActionType.ExecBuiltin, command); SendCommand(host, "ExecBuiltIn(UpdateLibrary(video))", username, password); } } @@ -169,6 +165,57 @@ namespace NzbDrone.Core.Providers 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.SeriesId || 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>(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