diff --git a/NzbDrone.Core.Test/DiskScanJobTest.cs b/NzbDrone.Core.Test/DiskScanJobTest.cs index 6022d6604..ac829cb19 100644 --- a/NzbDrone.Core.Test/DiskScanJobTest.cs +++ b/NzbDrone.Core.Test/DiskScanJobTest.cs @@ -80,7 +80,7 @@ public void job_with_no_target_should_scan_all_series() mocker.GetMock() .Setup(p => p.GetAllSeries()) - .Returns(series.AsQueryable()); + .Returns(series); mocker.GetMock() .Setup(s => s.Scan(series[0])) @@ -109,7 +109,7 @@ public void failed_scan_should_not_terminated_job() mocker.GetMock() .Setup(p => p.GetAllSeries()) - .Returns(series.AsQueryable()); + .Returns(series); mocker.GetMock() .Setup(s => s.Scan(series[0])) @@ -140,7 +140,7 @@ public void job_with_no_target_should_scan_series_with_episodes() mocker.GetMock() .Setup(p => p.GetAllSeries()) - .Returns(series.AsQueryable()); + .Returns(series); mocker.GetMock() .Setup(s => s.Scan(series[0])) diff --git a/NzbDrone.Core.Test/ImportNewSeriesJobTest.cs b/NzbDrone.Core.Test/ImportNewSeriesJobTest.cs index 3fc94b945..aeb6bd14e 100644 --- a/NzbDrone.Core.Test/ImportNewSeriesJobTest.cs +++ b/NzbDrone.Core.Test/ImportNewSeriesJobTest.cs @@ -35,7 +35,7 @@ public void import_new_series_succesfull() mocker.GetMock() .Setup(p => p.GetAllSeries()) - .Returns(series.AsQueryable()); + .Returns(series); mocker.GetMock() @@ -95,7 +95,7 @@ public void failed_import_should_not_be_stuck_in_loop() mocker.GetMock() .Setup(p => p.GetAllSeries()) - .Returns(series.AsQueryable()); + .Returns(series); mocker.GetMock() .Setup(j => j.Start(notification, series[0].SeriesId)) diff --git a/NzbDrone.Core.Test/IndexerTests.cs b/NzbDrone.Core.Test/IndexerTests.cs index 3861e9d03..8e7e662e2 100644 --- a/NzbDrone.Core.Test/IndexerTests.cs +++ b/NzbDrone.Core.Test/IndexerTests.cs @@ -187,8 +187,31 @@ public void nzbsorg_search_returns_valid_results() Assert.ForAll(result, r => r.CleanTitle == "simpsons"); Assert.ForAll(result, r => r.SeasonNumber == 21); Assert.ForAll(result, r => r.EpisodeNumbers.Contains(23)); + } + [Test] + public void nzbsorg_multi_word_search_returns_valid_results() + { + var mocker = new AutoMoqer(); + + mocker.GetMock() + .SetupGet(c => c.NzbsOrgUId) + .Returns("43516"); + + mocker.GetMock() + .SetupGet(c => c.NzbsOrgHash) + .Returns("bc8edb4cc49d4ae440775adec5ac001f"); + + + mocker.Resolve(); + + var result = mocker.Resolve().FetchEpisode("Blue Bloods", 1, 19); + + Assert.IsNotEmpty(result); + Assert.ForAll(result, r => r.CleanTitle == "bluebloods"); + Assert.ForAll(result, r => r.SeasonNumber == 1); + Assert.ForAll(result, r => r.EpisodeNumbers.Contains(19)); } } } diff --git a/NzbDrone.Core.Test/MediaFileProviderTests.cs b/NzbDrone.Core.Test/MediaFileProviderTests.cs index 8ca8d2ba6..aa9f09e7a 100644 --- a/NzbDrone.Core.Test/MediaFileProviderTests.cs +++ b/NzbDrone.Core.Test/MediaFileProviderTests.cs @@ -324,10 +324,10 @@ public void scan_series_should_update_last_scan_date() public void scan_media_job_should_not_scan_new_series() { var mocker = new AutoMoqer(); - IQueryable fakeSeries = Builder.CreateListOfSize(2) + var fakeSeries = Builder.CreateListOfSize(2) .WhereTheFirst(1).Has(c => c.Episodes = new List()) .AndTheNext(1).Has(c => c.Episodes = Builder.CreateListOfSize(10).Build()) - .Build().AsQueryable(); + .Build(); mocker.GetMock() .Setup(c => c.GetAllSeries()).Returns(fakeSeries); diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index c8eac9ea0..6efed79d7 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -110,6 +110,9 @@ private static void BindIndexers() _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); + + var indexers = _kernel.GetAll(); + _kernel.Get().InitializeIndexers(indexers.ToList()); } private static void BindJobs() @@ -119,6 +122,7 @@ private static void BindJobs() _kernel.Bind().To().InTransientScope(); _kernel.Bind().To().InTransientScope(); _kernel.Bind().To().InTransientScope(); + _kernel.Bind().To().InTransientScope(); _kernel.Get().Initialize(); _kernel.Get().StartTimer(30); diff --git a/NzbDrone.Core/Providers/Indexer/IndexerBase.cs b/NzbDrone.Core/Providers/Indexer/IndexerBase.cs index 647cd4f7a..071d8b33e 100644 --- a/NzbDrone.Core/Providers/Indexer/IndexerBase.cs +++ b/NzbDrone.Core/Providers/Indexer/IndexerBase.cs @@ -25,7 +25,7 @@ protected IndexerBase(HttpProvider httpProvider, ConfigProvider configProvider) public IndexerBase() { - + } /// @@ -96,7 +96,7 @@ public virtual IList FetchRss() public virtual IList FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber) { - _logger.Debug("Searching {0} for {1}-S{2}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber); + _logger.Debug("Searching {0} for {1}-S{2:00}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber); var result = new List(); @@ -162,5 +162,10 @@ public EpisodeParseResult ParseFeed(SyndicationItem item) return CustomParser(item, episodeParseResult); } + + protected static string GetQueryTitle(string title) + { + return title.Trim().Replace(' ', '+'); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/Indexer/NzbsOrg.cs b/NzbDrone.Core/Providers/Indexer/NzbsOrg.cs index a9ed732bb..80ceef824 100644 --- a/NzbDrone.Core/Providers/Indexer/NzbsOrg.cs +++ b/NzbDrone.Core/Providers/Indexer/NzbsOrg.cs @@ -11,7 +11,8 @@ namespace NzbDrone.Core.Providers.Indexer { public class NzbsOrg : IndexerBase { - public NzbsOrg(HttpProvider httpProvider, ConfigProvider configProvider) : base(httpProvider, configProvider) + public NzbsOrg(HttpProvider httpProvider, ConfigProvider configProvider) + : base(httpProvider, configProvider) { } @@ -43,11 +44,11 @@ protected override IList GetSearchUrls(string seriesTitle, int seasonNum foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&action=search&q={1}+s{2}e{3:00}", url, seriesTitle, seasonNumber, episodeNumber)); + searchUrls.Add(String.Format("{0}&action=search&q={1}+s{2:00}e{3:00}", url, GetQueryTitle(seriesTitle), seasonNumber, episodeNumber)); } return searchUrls; } - } + } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index 866bce749..641475851 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -33,9 +34,9 @@ public SeriesProvider() { } - public virtual IQueryable GetAllSeries() + public virtual IList GetAllSeries() { - return _repository.All(); + return _repository.All().ToList(); } public virtual Series GetSeries(int seriesId) diff --git a/NzbDrone.Web/Controllers/EpisodeController.cs b/NzbDrone.Web/Controllers/EpisodeController.cs new file mode 100644 index 000000000..d2c954fdc --- /dev/null +++ b/NzbDrone.Web/Controllers/EpisodeController.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Web.Mvc; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Providers.Jobs; +using NzbDrone.Web.Models; + +namespace NzbDrone.Web.Controllers +{ + public class EpisodeController : Controller + { + + private readonly JobProvider _jobProvider; + + + public EpisodeController(JobProvider jobProvider) + { + + _jobProvider = jobProvider; + } + + public JsonResult Search(int episodeId) + { + _jobProvider.QueueJob(typeof(EpisodeSearchJob), episodeId); + return new JsonResult { Data = "ok" }; + } + + + } +} \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index d4b0c8411..c827a14fb 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -215,6 +215,7 @@ True UploadLocalization.en-US.resx + diff --git a/NzbDrone.Web/Views/Series/Details.cshtml b/NzbDrone.Web/Views/Series/Details.cshtml index d29f74dd1..99a8d3c85 100644 --- a/NzbDrone.Web/Views/Series/Details.cshtml +++ b/NzbDrone.Web/Views/Series/Details.cshtml @@ -78,6 +78,8 @@ columns.Bound(c => c.AirDate).Format("{0:d}").Width(0); columns.Bound(c => c.Quality).Width(0); columns.Bound(c => c.Status).Width(0); + columns.Bound(o => o.EpisodeId).Title("") + .ClientTemplate("')\" >Search"); }) .DetailView(detailView => detailView.ClientTemplate("
<#= Overview #>
<#= Path #>
")) .ClientEvents(clientEvents => @@ -150,5 +152,18 @@ function episodeDetailExpanded(e) { $console.log("OnDetailViewExpand :: " + e.masterRow.cells[1].innerHTML); } + + var searchUrl = '@Url.Action("Search", "Episode")'; + + function searchForEpisode(id) { + $.ajax({ + type: "POST", + url: searchUrl, + data: jQuery.param({ episodeId: id }), + error: function (req, status, error) { + alert("Sorry! We could search for " + id + " at this time. " + error); + } + }); + } }