New: Sonarr can now update series to use another tvdbid in case when tvdb removes a duplicate and Skyhook detects it.

This commit is contained in:
Taloth Saldono 2015-08-12 20:45:44 +02:00
parent 2627072aab
commit 9bcb6ff19a
9 changed files with 124 additions and 20 deletions

View File

@ -83,16 +83,27 @@ namespace NzbDrone.Common.Test.Http
ExceptionVerification.IgnoreWarns(); ExceptionVerification.IgnoreWarns();
} }
[TestCase(HttpStatusCode.MovedPermanently)] [Test]
public void should_not_follow_redirects_when_not_in_production(HttpStatusCode statusCode) public void should_not_follow_redirects_when_not_in_production()
{ {
var request = new HttpRequest("http://eu.httpbin.org/status/" + (int)statusCode); var request = new HttpRequest("http://eu.httpbin.org/redirect/1");
Subject.Get<HttpBinResource>(request); Subject.Get(request);
ExceptionVerification.ExpectedErrors(1); ExceptionVerification.ExpectedErrors(1);
} }
[Test]
public void should_follow_redirects()
{
var request = new HttpRequest("http://eu.httpbin.org/redirect/1");
request.AllowAutoRedirect = true;
Subject.Get(request);
ExceptionVerification.ExpectedErrors(0);
}
[Test] [Test]
public void should_send_user_agent() public void should_send_user_agent()
{ {

View File

@ -61,11 +61,6 @@ namespace NzbDrone.Common.Http
webRequest.AllowAutoRedirect = request.AllowAutoRedirect; webRequest.AllowAutoRedirect = request.AllowAutoRedirect;
webRequest.ContentLength = 0; webRequest.ContentLength = 0;
if (!RuntimeInfoBase.IsProduction)
{
webRequest.AllowAutoRedirect = false;
}
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
if (request.Headers != null) if (request.Headers != null)
@ -83,7 +78,7 @@ namespace NzbDrone.Common.Http
_logger.Trace("{0} ({1:n0} ms)", response, stopWatch.ElapsedMilliseconds); _logger.Trace("{0} ({1:n0} ms)", response, stopWatch.ElapsedMilliseconds);
if (request.AllowAutoRedirect && !RuntimeInfoBase.IsProduction && if (!RuntimeInfoBase.IsProduction &&
(response.StatusCode == HttpStatusCode.Moved || (response.StatusCode == HttpStatusCode.Moved ||
response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.MovedPermanently ||
response.StatusCode == HttpStatusCode.Found)) response.StatusCode == HttpStatusCode.Found))

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http
{ {
@ -16,6 +17,11 @@ namespace NzbDrone.Common.Http
AllowAutoRedirect = true; AllowAutoRedirect = true;
Cookies = new Dictionary<string, string>(); Cookies = new Dictionary<string, string>();
if (!RuntimeInfoBase.IsProduction)
{
AllowAutoRedirect = false;
}
if (httpAccept != null) if (httpAccept != null)
{ {
Headers.Accept = httpAccept.Value; Headers.Accept = httpAccept.Value;

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource.SkyHook; using NzbDrone.Core.MetadataSource.SkyHook;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -38,9 +39,7 @@ namespace NzbDrone.Core.Test.MetadataSource.SkyHook
[Test] [Test]
public void getting_details_of_invalid_series() public void getting_details_of_invalid_series()
{ {
Assert.Throws<Common.Http.HttpException>(() => Subject.GetSeriesInfo(Int32.MaxValue)); Assert.Throws<SeriesNotFoundException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
ExceptionVerification.ExpectedWarns(1);
} }
[Test] [Test]

View File

@ -5,10 +5,12 @@ using FizzWare.NBuilder;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MetadataSource; using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Commands; using NzbDrone.Core.Tv.Commands;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.TvTests namespace NzbDrone.Core.Test.TvTests
{ {
@ -34,14 +36,16 @@ namespace NzbDrone.Core.Test.TvTests
Mocker.GetMock<ISeriesService>() Mocker.GetMock<ISeriesService>()
.Setup(s => s.GetSeries(_series.Id)) .Setup(s => s.GetSeries(_series.Id))
.Returns(_series); .Returns(_series);
Mocker.GetMock<IProvideSeriesInfo>()
.Setup(s => s.GetSeriesInfo(It.IsAny<int>()))
.Callback<int>(p => { throw new SeriesNotFoundException(p); });
} }
private void GivenNewSeriesInfo(Series series) private void GivenNewSeriesInfo(Series series)
{ {
Mocker.GetMock<IProvideSeriesInfo>() Mocker.GetMock<IProvideSeriesInfo>()
.Setup(s => s.GetSeriesInfo(It.IsAny<Int32>())) .Setup(s => s.GetSeriesInfo(_series.TvdbId))
.Returns(new Tuple<Series, List<Episode>>(series, new List<Episode>())); .Returns(new Tuple<Series, List<Episode>>(series, new List<Episode>()));
} }
@ -90,5 +94,32 @@ namespace NzbDrone.Core.Test.TvTests
Mocker.GetMock<ISeriesService>() Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvRageId == newSeriesInfo.TvRageId))); .Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvRageId == newSeriesInfo.TvRageId)));
} }
[Test]
public void should_log_error_if_tvdb_id_not_found()
{
Subject.Execute(new RefreshSeriesCommand(_series.Id));
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
ExceptionVerification.ExpectedErrors(1);
}
[Test]
public void should_update_if_tvdb_id_changed()
{
var newSeriesInfo = _series.JsonClone();
newSeriesInfo.TvdbId = _series.TvdbId + 1;
GivenNewSeriesInfo(newSeriesInfo);
Subject.Execute(new RefreshSeriesCommand(_series.Id));
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvdbId == newSeriesInfo.TvdbId)));
ExceptionVerification.ExpectedWarns(1);
}
} }
} }

View File

@ -0,0 +1,29 @@
using System;
using NzbDrone.Common.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Exceptions
{
public class SeriesNotFoundException : NzbDroneException
{
public int TvdbSeriesId { get; set; }
public SeriesNotFoundException(int tvdbSeriesId)
: base(string.Format("Series with tvdbid {0} was not found, it may have been removed from TheTVDB.", tvdbSeriesId))
{
TvdbSeriesId = tvdbSeriesId;
}
public SeriesNotFoundException(int tvdbSeriesId, string message, params object[] args)
: base(message, args)
{
TvdbSeriesId = tvdbSeriesId;
}
public SeriesNotFoundException(int tvdbSeriesId, string message)
: base(message)
{
TvdbSeriesId = tvdbSeriesId;
}
}
}

View File

@ -2,11 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource.SkyHook.Resource; using NzbDrone.Core.MetadataSource.SkyHook.Resource;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -31,8 +30,23 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
{ {
var httpRequest = _requestBuilder.Build(tvdbSeriesId.ToString()); var httpRequest = _requestBuilder.Build(tvdbSeriesId.ToString());
httpRequest.AddSegment("route", "shows"); httpRequest.AddSegment("route", "shows");
httpRequest.AllowAutoRedirect = true;
httpRequest.SuppressHttpError = true;
var httpResponse = _httpClient.Get<ShowResource>(httpRequest); var httpResponse = _httpClient.Get<ShowResource>(httpRequest);
if (httpResponse.HasHttpError)
{
if (httpResponse.StatusCode == HttpStatusCode.NotFound)
{
throw new SeriesNotFoundException(tvdbSeriesId);
}
else
{
throw new HttpException(httpRequest, httpResponse);
}
}
var episodes = httpResponse.Resource.Episodes.Select(MapEpisode); var episodes = httpResponse.Resource.Episodes.Select(MapEpisode);
var series = MapSeries(httpResponse.Resource); var series = MapSeries(httpResponse.Resource);
@ -71,7 +85,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
} }
} }
var term = HttpUtility.UrlEncode((title.ToLower().Trim())); var term = System.Web.HttpUtility.UrlEncode((title.ToLower().Trim()));
var httpRequest = _requestBuilder.Build("?term={term}"); var httpRequest = _requestBuilder.Build("?term={term}");
httpRequest.AddSegment("route", "search"); httpRequest.AddSegment("route", "search");
httpRequest.AddSegment("term", term); httpRequest.AddSegment("term", term);
@ -80,7 +94,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return httpResponse.Resource.SelectList(MapSeries); return httpResponse.Resource.SelectList(MapSeries);
} }
catch (Common.Http.HttpException) catch (HttpException)
{ {
throw new SkyHookException("Search for '{0}' failed. Unable to communicate with SkyHook.", title); throw new SkyHookException("Search for '{0}' failed. Unable to communicate with SkyHook.", title);
} }

View File

@ -431,6 +431,7 @@
<Compile Include="Exceptions\BadRequestException.cs" /> <Compile Include="Exceptions\BadRequestException.cs" />
<Compile Include="Exceptions\DownstreamException.cs" /> <Compile Include="Exceptions\DownstreamException.cs" />
<Compile Include="Exceptions\NzbDroneClientException.cs" /> <Compile Include="Exceptions\NzbDroneClientException.cs" />
<Compile Include="Exceptions\SeriesNotFoundException.cs" />
<Compile Include="Exceptions\ReleaseDownloadException.cs" /> <Compile Include="Exceptions\ReleaseDownloadException.cs" />
<Compile Include="Exceptions\StatusCodeToExceptions.cs" /> <Compile Include="Exceptions\StatusCodeToExceptions.cs" />
<Compile Include="Fluent.cs" /> <Compile Include="Fluent.cs" />

View File

@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.DataAugmentation.DailySeries; using NzbDrone.Core.DataAugmentation.DailySeries;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
@ -48,10 +49,27 @@ namespace NzbDrone.Core.Tv
private void RefreshSeriesInfo(Series series) private void RefreshSeriesInfo(Series series)
{ {
_logger.ProgressInfo("Updating Info for {0}", series.Title); _logger.ProgressInfo("Updating Info for {0}", series.Title);
var tuple = _seriesInfo.GetSeriesInfo(series.TvdbId);
Tuple<Series, List<Episode>> tuple;
try
{
tuple = _seriesInfo.GetSeriesInfo(series.TvdbId);
}
catch (SeriesNotFoundException)
{
_logger.Error("Series '{0}' (tvdbid {1}) was not found, it may have been removed from TheTVDB.", series.Title, series.TvdbId);
return;
}
var seriesInfo = tuple.Item1; var seriesInfo = tuple.Item1;
if (series.TvdbId != seriesInfo.TvdbId)
{
_logger.Warn("Series '{0}' (tvdbid {1}) was replaced with '{2}' (tvdbid {3}), because the original was a duplicate.", series.Title, series.TvdbId, seriesInfo.Title, seriesInfo.TvdbId);
series.TvdbId = seriesInfo.TvdbId;
}
series.Title = seriesInfo.Title; series.Title = seriesInfo.Title;
series.TitleSlug = seriesInfo.TitleSlug; series.TitleSlug = seriesInfo.TitleSlug;
series.TvRageId = seriesInfo.TvRageId; series.TvRageId = seriesInfo.TvRageId;