Download naming uses tvdb numbering

Searching by scene name added
Removed American Dad
This commit is contained in:
Mark McDowall 2012-10-17 17:06:14 -07:00
parent 59bfa16462
commit 2fd1263619
10 changed files with 222 additions and 56 deletions

View File

@ -195,7 +195,11 @@ namespace NzbDrone.Core.Test.ProviderTests
var fakeEpisodes = new List<Episode>();
foreach(var episode in episodes)
fakeEpisodes.Add(Builder<Episode>.CreateNew().With(e => e.EpisodeNumber = episode).Build());
fakeEpisodes.Add(Builder<Episode>
.CreateNew()
.With(e => e.EpisodeNumber = episode)
.With(e => e.Title = title)
.Build());
var parsResult = new EpisodeParseResult()
{
@ -241,16 +245,49 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(c => c.Title = "My Series Name")
.Build();
var episode = Builder<Episode>.CreateNew()
.With(e => e.Title = "My Episode Title")
.Build();
var parsResult = new EpisodeParseResult
{
AirDate = new DateTime(2011, 12, 1),
Quality = new Quality(QualityTypes.Bluray720p, proper),
Series = series,
EpisodeTitle = "My Episode Title",
Episodes = new List<Episode>{ episode }
};
return Mocker.Resolve<DownloadProvider>().GetDownloadTitle(parsResult);
}
[Test]
public void should_not_repeat_the_same_episode_title()
{
var series = Builder<Series>.CreateNew()
.With(c => c.Title = "My Series Name")
.Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(2)
.All()
.With(e => e.SeasonNumber = 5)
.TheFirst(1)
.With(e => e.Title = "My Episode Title (1)")
.TheLast(1)
.With(e => e.Title = "My Episode Title (2)")
.Build();
var parsResult = new EpisodeParseResult
{
AirDate = DateTime.Now,
EpisodeNumbers = new List<int>{ 10, 11 },
Quality = new Quality(QualityTypes.HDTV, false),
SeasonNumber = 35,
Series = series,
Episodes = fakeEpisodes
};
Mocker.Resolve<DownloadProvider>().GetDownloadTitle(parsResult).Should().Be("My Series Name - 5x01-5x02 - My Episode Title [HDTV]");
}
}
}

View File

@ -699,5 +699,43 @@ namespace NzbDrone.Core.Test.ProviderTests.MediaFileProviderTests
//Assert
result.Should().Be("30 Rock - S06E06-E07 - Hello + World");
}
[Test]
public void should_have_two_episodeTitles_when_distinct_count_is_two()
{
//Setup
var fakeConfig = Mocker.GetMock<ConfigProvider>();
fakeConfig.SetupGet(c => c.SortingIncludeSeriesName).Returns(true);
fakeConfig.SetupGet(c => c.SortingIncludeEpisodeTitle).Returns(true);
fakeConfig.SetupGet(c => c.SortingAppendQuality).Returns(false);
fakeConfig.SetupGet(c => c.SortingSeparatorStyle).Returns(0);
fakeConfig.SetupGet(c => c.SortingNumberStyle).Returns(2);
fakeConfig.SetupGet(c => c.SortingReplaceSpaces).Returns(false);
fakeConfig.SetupGet(c => c.SortingMultiEpisodeStyle).Returns(3);
var episode = Builder<Episode>.CreateNew()
.With(e => e.Title = "Hello (3)")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 6)
.Build();
var episode2 = Builder<Episode>.CreateNew()
.With(e => e.Title = "Hello (2)")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 7)
.Build();
var episode3 = Builder<Episode>.CreateNew()
.With(e => e.Title = "World")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 8)
.Build();
//Act
string result = Mocker.Resolve<MediaFileProvider>().GetNewFilename(new List<Episode> { episode, episode2, episode3 }, "30 Rock", QualityTypes.HDTV, false, new EpisodeFile());
//Assert
result.Should().Be("30 Rock - S06E06-E07-E08 - Hello + World");
}
}
}

View File

@ -185,7 +185,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void EpisodeSearch_should_skip_if_air_date_is_null()
public void EpisodeSearch_should_skip_if_air_date_is_null_and_is_a_daily_series()
{
//Setup
_series.IsDaily = true;
@ -206,5 +206,29 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
result.Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void EpisodeSearch_should_skip_if_sceneNumbering_is_invalid_and_should_use_sceneNumbering()
{
//Setup
_series.UseSceneNumbering = true;
var episode = _episodes.First();
episode.SceneSeasonNumber = 0;
episode.SceneEpisodeNumber = 0;
episode.Series = _series;
Mocker.GetMock<UpgradePossibleSpecification>().Setup(s => s.IsSatisfiedBy(It.IsAny<Episode>()))
.Returns(true);
Mocker.GetMock<EpisodeProvider>().Setup(s => s.GetEpisode(episode.EpisodeId))
.Returns(episode);
//Act
var result = Mocker.Resolve<SearchProvider>().EpisodeSearch(MockNotification, episode.EpisodeId);
//Assert
result.Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
}
}

View File

@ -833,5 +833,41 @@ namespace NzbDrone.Core.Test.ProviderTests
}
[Test]
public void Update_UseSceneNumbering_should_update_applicable_series()
{
WithRealDb();
var series = Builder<Series>.CreateListOfSize(5)
.All()
.With(s => s.UseSceneNumbering = false)
.Build();
Db.InsertMany(series);
Mocker.Resolve<SeriesProvider>().UpdateUseSceneNumbering(new []{ 2, 3 });
var seriesResults = Db.Fetch<Series>();
seriesResults.Single(s => s.SeriesId == 2).UseSceneNumbering.Should().BeTrue();
seriesResults.Single(s => s.SeriesId == 3).UseSceneNumbering.Should().BeTrue();
}
[Test]
public void Update_UseSceneNumbering_should_not_update_other_series()
{
WithRealDb();
var series = Builder<Series>.CreateListOfSize(5)
.All()
.With(s => s.UseSceneNumbering = false)
.Build();
Db.InsertMany(series);
Mocker.Resolve<SeriesProvider>().UpdateUseSceneNumbering(new [] { 2, 3 });
var seriesResults = Db.Fetch<Series>();
seriesResults.Where(s => !s.UseSceneNumbering).Should().HaveCount(3);
seriesResults.Where(s => !s.UseSceneNumbering).Should().NotContain(s => s.SeriesId == 2 || s.SeriesId == 3);
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
@ -115,7 +116,7 @@ namespace NzbDrone.Core.Providers
if (parseResult.Series.IsDaily)
{
var dailyResult = String.Format("{0} - {1:yyyy-MM-dd} - {2} [{3}]", seriesTitle,
parseResult.AirDate, parseResult.EpisodeTitle, parseResult.Quality.QualityType);
parseResult.AirDate, parseResult.Episodes.First().Title, parseResult.Quality.QualityType);
if (parseResult.Quality.Proper)
dailyResult += " [Proper]";
@ -126,15 +127,25 @@ namespace NzbDrone.Core.Providers
//Show Name - 1x01-1x02 - Episode Name
//Show Name - 1x01 - Episode Name
var episodeString = new List<String>();
var episodeNames = new List<String>();
foreach (var episode in parseResult.Episodes)
{
episodeString.Add(String.Format("{0}x{1:00}", parseResult.SeasonNumber, episode.EpisodeNumber));
episodeString.Add(String.Format("{0}x{1:00}", episode.SeasonNumber, episode.EpisodeNumber));
episodeNames.Add(Parser.CleanupEpisodeTitle(episode.Title));
}
var epNumberString = String.Join("-", episodeString);
string episodeName;
var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, parseResult.EpisodeTitle, parseResult.Quality.QualityType);
if (episodeNames.Distinct().Count() == 1)
episodeName = episodeNames.First();
else
episodeName = String.Join(" + ", episodeNames.Distinct());
var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, episodeName, parseResult.Quality.QualityType);
if (parseResult.Quality.Proper)
{

View File

@ -226,6 +226,16 @@ namespace NzbDrone.Core.Providers
{
result.Add(episodeInfo);
if (parseResult.Series.UseSceneNumbering)
{
logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}",
parseResult.Series.Title,
episodeInfo.SceneSeasonNumber,
episodeInfo.SceneEpisodeNumber,
episodeInfo.SeasonNumber,
episodeInfo.EpisodeNumber);
}
if (parseResult.EpisodeNumbers.Count == 1)
{
parseResult.EpisodeTitle = episodeInfo.Title.Trim();

View File

@ -208,7 +208,7 @@ namespace NzbDrone.Core.Providers
result += separatorStyle.Pattern + episodeNames.First();
else
result += separatorStyle.Pattern + String.Join(" + ", episodeNames);
result += separatorStyle.Pattern + String.Join(" + ", episodeNames.Distinct());
}
if (_configProvider.SortingAppendQuality)

View File

@ -25,7 +25,7 @@ namespace NzbDrone.Core.Providers
private readonly AllowedDownloadSpecification _allowedDownloadSpecification;
private readonly SearchHistoryProvider _searchHistoryProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
[Inject]
public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider,
@ -60,7 +60,7 @@ namespace NzbDrone.Core.Providers
if (series == null)
{
Logger.Error("Unable to find an series {0} in database", seriesId);
_logger.Error("Unable to find an series {0} in database", seriesId);
return new List<int>();
}
@ -72,17 +72,17 @@ namespace NzbDrone.Core.Providers
var reports = PerformSearch(notification, series, seasonNumber);
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
if (reports.Count == 0)
return new List<int>();
Logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber);
_logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber);
var episodeNumbers = _episodeProvider.GetEpisodeNumbersBySeason(seriesId, seasonNumber);
if (episodeNumbers == null || episodeNumbers.Count == 0)
{
Logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber);
_logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber);
return new List<int>();
}
@ -111,7 +111,7 @@ namespace NzbDrone.Core.Providers
if (series == null)
{
Logger.Error("Unable to find an series {0} in database", seriesId);
_logger.Error("Unable to find an series {0} in database", seriesId);
return new List<int>();
}
@ -122,7 +122,7 @@ namespace NzbDrone.Core.Providers
notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber);
var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber);
var reports = PerformSearch(notification, series, seasonNumber, episodes);
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
if (reports.Count == 0)
return new List<int>();
@ -140,14 +140,14 @@ namespace NzbDrone.Core.Providers
if (episode == null)
{
Logger.Error("Unable to find an episode {0} in database", episodeId);
_logger.Error("Unable to find an episode {0} in database", episodeId);
return false;
}
//Check to see if an upgrade is possible before attempting
if (!_upgradePossibleSpecification.IsSatisfiedBy(episode))
{
Logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
_logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
notification.CurrentMessage = String.Format("Skipping search for {0}, the file you have is already at cutoff", episode);
return false;
}
@ -156,11 +156,19 @@ namespace NzbDrone.Core.Providers
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
{
Logger.Warn("AirDate is not Valid for: {0}", episode);
_logger.Warn("AirDate is not Valid for: {0}", episode);
notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode);
return false;
}
if (episode.Series.UseSceneNumbering && episode.SceneSeasonNumber <= 0 && episode.SceneEpisodeNumber <= 0)
{
_logger.Warn("Series should use Scene Numbering, but it is not available: {0}", episode);
notification.CurrentMessage = String.Format("Search Failed, invalid scene episode data found: {0}", episode);
return false;
}
var searchResult = new SearchHistory
{
SearchTime = DateTime.Now,
@ -169,7 +177,7 @@ namespace NzbDrone.Core.Providers
var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List<Episode> { episode });
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
notification.CurrentMessage = "Processing search results";
if (episode.Series.IsDaily)
@ -181,6 +189,24 @@ namespace NzbDrone.Core.Providers
return true;
}
else if (episode.Series.UseSceneNumbering)
{
searchResult.EpisodeId = episodeId;
searchResult.SearchHistoryItems = ProcessSearchResults(
notification,
reports,
searchResult,
episode.Series,
episode.SceneSeasonNumber,
episode.SceneEpisodeNumber
);
_searchHistoryProvider.Add(searchResult);
if (searchResult.SearchHistoryItems.Any(r => r.Success))
return true;
}
else
{
searchResult.EpisodeId = episodeId;
@ -188,10 +214,10 @@ namespace NzbDrone.Core.Providers
_searchHistoryProvider.Add(searchResult);
if (searchResult.SearchHistoryItems.Any(r => r.Success))
return true;
return true;
}
Logger.Warn("Unable to find {0} in any of indexers.", episode);
_logger.Warn("Unable to find {0} in any of indexers.", episode);
if (reports.Any())
{
@ -250,7 +276,7 @@ namespace NzbDrone.Core.Providers
catch (Exception e)
{
Logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
_logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
}
});
@ -268,7 +294,7 @@ namespace NzbDrone.Core.Providers
{
try
{
Logger.Trace("Analysing report " + episodeParseResult);
_logger.Trace("Analysing report " + episodeParseResult);
var item = new SearchHistoryItem
{
@ -290,7 +316,7 @@ namespace NzbDrone.Core.Providers
//If series is null or doesn't match the series we're looking for return
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
{
Logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
_logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
item.SearchError = ReportRejectionType.WrongSeries;
continue;
}
@ -298,7 +324,7 @@ namespace NzbDrone.Core.Providers
//If SeasonNumber doesn't match or episode is not in the in the list in the parse result, skip the report.
if (episodeParseResult.SeasonNumber != seasonNumber)
{
Logger.Trace("Season number does not match searched season number, skipping.");
_logger.Trace("Season number does not match searched season number, skipping.");
item.SearchError = ReportRejectionType.WrongSeason;
continue;
}
@ -306,7 +332,7 @@ namespace NzbDrone.Core.Providers
//If the EpisodeNumber was passed in and it is not contained in the parseResult, skip the report.
if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value))
{
Logger.Trace("Searched episode number is not contained in post, skipping.");
_logger.Trace("Searched episode number is not contained in post, skipping.");
item.SearchError = ReportRejectionType.WrongEpisode;
continue;
}
@ -314,7 +340,7 @@ namespace NzbDrone.Core.Providers
//Make sure we haven't already downloaded a report with this episodenumber, if we have, skip the report.
if (searchResult.Successes.Intersect(episodeParseResult.EpisodeNumbers).Any())
{
Logger.Trace("Episode has already been downloaded in this search, skipping.");
_logger.Trace("Episode has already been downloaded in this search, skipping.");
item.SearchError = ReportRejectionType.Skipped;
continue;
}
@ -324,7 +350,7 @@ namespace NzbDrone.Core.Providers
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
if (item.SearchError == ReportRejectionType.None)
{
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
_logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
try
{
if (_downloadProvider.DownloadReport(episodeParseResult))
@ -342,7 +368,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
_logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
item.SearchError = ReportRejectionType.DownloadClientFailure;
}
@ -350,7 +376,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
_logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
}
}
@ -386,7 +412,7 @@ namespace NzbDrone.Core.Providers
continue;
}
Logger.Trace("Analysing report " + episodeParseResult);
_logger.Trace("Analysing report " + episodeParseResult);
//Get the matching series
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
@ -410,7 +436,7 @@ namespace NzbDrone.Core.Providers
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
if (item.SearchError == ReportRejectionType.None)
{
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
_logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
try
{
if (_downloadProvider.DownloadReport(episodeParseResult))
@ -429,7 +455,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
_logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
item.SearchError = ReportRejectionType.DownloadClientFailure;
}
@ -437,7 +463,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
_logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
}
}

View File

@ -238,6 +238,14 @@ namespace NzbDrone.Core.Providers
_database.UpdateMany(allSeries);
}
public virtual void UpdateUseSceneNumbering(IEnumerable<Int32> seriesIds)
{
_database.Execute("UPDATE Series SET UseSceneNumbering = 0");
var query = String.Format("UPDATE Series SET UseSceneNumbering = 1 WHERE SeriesId IN ({0})", String.Join(",", seriesIds));
_database.Execute(query);
}
/// <summary>
/// Cleans up the AirsTime Component from TheTVDB since it can be garbage that comes in.
/// </summary>

View File

@ -51,30 +51,6 @@ namespace NzbDrone.Core.Providers
Logger.Debug("Fetching SeriesId'{0}' from tvdb", id);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, loadActors, true, true);
//Fix American Dad's scene gongshow
if (result != null && result.Id == 73141)
{
result.Episodes = result.Episodes.Where(e => e.SeasonNumber == 0 || e.EpisodeNumber > 0).ToList();
var seasonOneEpisodeCount = result.Episodes.Where(e => e.SeasonNumber == 1).Count();
var seasonOneId = result.Episodes.Where(e => e.SeasonNumber == 1).First().SeasonId;
foreach (var episode in result.Episodes)
{
if (episode.SeasonNumber > 1)
{
if (episode.SeasonNumber == 2)
{
episode.EpisodeNumber = episode.EpisodeNumber + seasonOneEpisodeCount;
episode.SeasonId = seasonOneId;
}
episode.SeasonNumber = episode.SeasonNumber - 1;
}
}
}
//Remove duplicated episodes
var episodes = result.Episodes.OrderByDescending(e => e.FirstAired).ThenByDescending(e => e.EpisodeName)
.GroupBy(e => e.SeriesId.ToString("000000") + e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))