diff --git a/src/NzbDrone.Api/Series/SeriesResource.cs b/src/NzbDrone.Api/Series/SeriesResource.cs index a68deaab2..2dbcfd977 100644 --- a/src/NzbDrone.Api/Series/SeriesResource.cs +++ b/src/NzbDrone.Api/Series/SeriesResource.cs @@ -57,6 +57,7 @@ namespace NzbDrone.Api.Series public int Runtime { get; set; } public int TvdbId { get; set; } public int TvRageId { get; set; } + public int TvMazeId { get; set; } public DateTime? FirstAired { get; set; } public DateTime? LastInfoSync { get; set; } public SeriesTypes SeriesType { get; set; } diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs index 20f7f70ea..1c874e991 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests _singleEpisodeSearchCriteria = new SingleEpisodeSearchCriteria { - Series = new Tv.Series { TvRageId = 10, TvdbId = 20 }, + Series = new Tv.Series { TvRageId = 10, TvdbId = 20, TvMazeId = 30 }, SceneTitles = new List { "Monkey Island" }, SeasonNumber = 1, EpisodeNumber = 2 @@ -177,6 +177,19 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests page.Url.Query.Should().Contain("tvdbid=20"); } + [Test] + public void should_search_by_tvmaze_if_supported() + { + _capabilities.SupportedTvSearchParameters = new[] { "q", "tvmazeid", "season", "ep" }; + + var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria); + results.GetTier(0).Should().HaveCount(1); + + var page = results.GetAllTiers().First().First(); + + page.Url.Query.Should().Contain("tvmazeid=30"); + } + [Test] public void should_prefer_search_by_tvdbid_if_rid_supported() { diff --git a/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs b/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs index aed900762..cd3bfc3b1 100644 --- a/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs @@ -95,6 +95,20 @@ namespace NzbDrone.Core.Test.TvTests .Verify(v => v.UpdateSeries(It.Is(s => s.TvRageId == newSeriesInfo.TvRageId))); } + [Test] + public void should_update_tvmaze_id_if_changed() + { + var newSeriesInfo = _series.JsonClone(); + newSeriesInfo.TvMazeId = _series.TvMazeId + 1; + + GivenNewSeriesInfo(newSeriesInfo); + + Subject.Execute(new RefreshSeriesCommand(_series.Id)); + + Mocker.GetMock() + .Verify(v => v.UpdateSeries(It.Is(s => s.TvMazeId == newSeriesInfo.TvMazeId))); + } + [Test] public void should_log_error_if_tvdb_id_not_found() { diff --git a/src/NzbDrone.Core/Datastore/Migration/094_add_tvmazeid.cs b/src/NzbDrone.Core/Datastore/Migration/094_add_tvmazeid.cs new file mode 100644 index 000000000..007716bfc --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/094_add_tvmazeid.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(94)] + public class add_tvmazeid : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Series").AddColumn("TvMazeId").AsInt32().WithDefaultValue(0); + Create.Index().OnTable("Series").OnColumn("TvMazeId"); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs index 5a9dc825c..8b4844ca5 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs @@ -72,6 +72,19 @@ namespace NzbDrone.Core.Indexers.Newznab } } + private bool SupportsTvMazeSearch + { + get + { + var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + + return capabilities.SupportedTvSearchParameters != null && + capabilities.SupportedTvSearchParameters.Contains("tvmazeid") && + capabilities.SupportedTvSearchParameters.Contains("season") && + capabilities.SupportedTvSearchParameters.Contains("ep"); + } + } + private bool SupportsAggregatedIdSearch { get @@ -184,6 +197,11 @@ namespace NzbDrone.Core.Indexers.Newznab ids += "&rid=" + searchCriteria.Series.TvRageId; } + if (searchCriteria.Series.TvMazeId > 0 && SupportsTvMazeSearch) + { + ids += "&tvmazeid=" + searchCriteria.Series.TvMazeId; + } + chain.Add(GetPagedRequests(maxPages, categories, "tvsearch", ids + parameters)); } else @@ -198,6 +216,12 @@ namespace NzbDrone.Core.Indexers.Newznab chain.Add(GetPagedRequests(maxPages, categories, "tvsearch", string.Format("&rid={0}{1}", searchCriteria.Series.TvRageId, parameters))); } + + else if (searchCriteria.Series.TvMazeId > 0 && SupportsTvMazeSearch) + { + chain.Add(GetPagedRequests(maxPages, categories, "tvsearch", + string.Format("&tvmazeid={0}{1}", searchCriteria.Series.TvMazeId, parameters))); + } } if (SupportsTvSearch) diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ShowResource.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ShowResource.cs index 36b1caa5e..fd442100d 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ShowResource.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ShowResource.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource public string Slug { get; set; } public string FirstAired { get; set; } public int? TvRageId { get; set; } + public int? TvMazeId { get; set; } public string Status { get; set; } public int? Runtime { get; set; } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index 7efdfe207..532d996ac 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -110,6 +110,11 @@ namespace NzbDrone.Core.MetadataSource.SkyHook series.TvRageId = show.TvRageId.Value; } + if (show.TvMazeId.HasValue) + { + series.TvMazeId = show.TvMazeId.Value; + } + series.ImdbId = show.ImdbId; series.Title = show.Title; series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.Title); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index b5f216998..7117f823a 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -272,6 +272,7 @@ + diff --git a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs index ec7af2fe9..c59cee64f 100644 --- a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs +++ b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs @@ -73,6 +73,7 @@ namespace NzbDrone.Core.Tv series.Title = seriesInfo.Title; series.TitleSlug = seriesInfo.TitleSlug; series.TvRageId = seriesInfo.TvRageId; + series.TvMazeId = seriesInfo.TvMazeId; series.ImdbId = seriesInfo.ImdbId; series.AirTime = seriesInfo.AirTime; series.Overview = seriesInfo.Overview; diff --git a/src/NzbDrone.Core/Tv/Series.cs b/src/NzbDrone.Core/Tv/Series.cs index 61046df5c..a3fdb986f 100644 --- a/src/NzbDrone.Core/Tv/Series.cs +++ b/src/NzbDrone.Core/Tv/Series.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.Tv public int TvdbId { get; set; } public int TvRageId { get; set; } + public int TvMazeId { get; set; } public string ImdbId { get; set; } public string Title { get; set; } public string CleanTitle { get; set; } diff --git a/src/UI/Handlebars/Helpers/Series.js b/src/UI/Handlebars/Helpers/Series.js index 30a198b07..1fd5a14dc 100644 --- a/src/UI/Handlebars/Helpers/Series.js +++ b/src/UI/Handlebars/Helpers/Series.js @@ -35,6 +35,10 @@ Handlebars.registerHelper('tvRageUrl', function() { return 'http://www.tvrage.com/shows/id-' + this.tvRageId; }); +Handlebars.registerHelper('tvMazeUrl', function() { + return 'http://www.tvmaze.com/shows/' + this.tvMazeId + '/_'; +}); + Handlebars.registerHelper('route', function() { return StatusModel.get('urlBase') + '/series/' + this.titleSlug; }); diff --git a/src/UI/Series/Details/InfoViewTemplate.hbs b/src/UI/Series/Details/InfoViewTemplate.hbs index e76980a43..21add05e4 100644 --- a/src/UI/Series/Details/InfoViewTemplate.hbs +++ b/src/UI/Series/Details/InfoViewTemplate.hbs @@ -40,6 +40,10 @@ {{#if tvRageId}} TV Rage {{/if}} + + {{#if tvMazeId}} + TV Maze + {{/if}}