diff --git a/NzbDrone.Core/Model/SeasonModel.cs b/NzbDrone.Core/Model/SeasonModel.cs
new file mode 100644
index 000000000..c23be62cf
--- /dev/null
+++ b/NzbDrone.Core/Model/SeasonModel.cs
@@ -0,0 +1,15 @@
+using NzbDrone.Core.Repository.Quality;
+using SubSonic.SqlGeneration.Schema;
+
+namespace NzbDrone.Core.Model
+{
+ public class SeasonModel
+ {
+ public string SeriesTitle { get; set; }
+ public int SeriesId { get; set; }
+ public int SeasonNumber { get; set; }
+ public QualityTypes Quality { get; set; }
+ public long Size { get; set; }
+ public bool Proper { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/NzbDrone.Core/Model/SeasonParseResult.cs b/NzbDrone.Core/Model/SeasonParseResult.cs
new file mode 100644
index 000000000..4f45ce305
--- /dev/null
+++ b/NzbDrone.Core/Model/SeasonParseResult.cs
@@ -0,0 +1,18 @@
+using NzbDrone.Core.Repository.Quality;
+using SubSonic.SqlGeneration.Schema;
+
+namespace NzbDrone.Core.Model
+{
+ public class SeasonParseResult
+ {
+ internal string SeriesTitle { get; set; }
+ internal int SeasonNumber { get; set; }
+ internal int Year { get; set; }
+
+ public override string ToString()
+ {
+ return string.Format("Series:{0} Season:{1}", SeriesTitle, SeasonNumber);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj
index 0a70748e9..f91a198ed 100644
--- a/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/NzbDrone.Core/NzbDrone.Core.csproj
@@ -166,6 +166,8 @@
+
+
diff --git a/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs b/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs
index fa536ddae..32911e591 100644
--- a/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs
+++ b/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs
@@ -11,7 +11,7 @@ namespace NzbDrone.Core.Providers
{
//This interface will contain methods to process individual RSS Feed Items (Queue if wanted)
- bool DownloadIfWanted(NzbInfoModel nzb, Indexer indexer);
+ void DownloadIfWanted(NzbInfoModel nzb, Indexer indexer);
string GetTitleFix(List episodes, int seriesId);
}
}
diff --git a/NzbDrone.Core/Providers/ISeasonProvider.cs b/NzbDrone.Core/Providers/ISeasonProvider.cs
index 20b8ffcb9..4e4b27cb7 100644
--- a/NzbDrone.Core/Providers/ISeasonProvider.cs
+++ b/NzbDrone.Core/Providers/ISeasonProvider.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using NzbDrone.Core.Model;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers
@@ -6,6 +7,7 @@ namespace NzbDrone.Core.Providers
public interface ISeasonProvider
{
Season GetSeason(int seasonId);
+ Season GetSeason(int seriesId, int seasonNumber);
List GetSeasons(int seriesId);
Season GetLatestSeason(int seriesId);
void EnsureSeason(int seriesId, int seasonId, int seasonNumber);
diff --git a/NzbDrone.Core/Providers/RssItemProcessingProvider.cs b/NzbDrone.Core/Providers/RssItemProcessingProvider.cs
index e3e9008c6..6d0c3db0b 100644
--- a/NzbDrone.Core/Providers/RssItemProcessingProvider.cs
+++ b/NzbDrone.Core/Providers/RssItemProcessingProvider.cs
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Providers
#region IRssItemProcessingProvider Members
- public bool DownloadIfWanted(NzbInfoModel nzb, Indexer indexer)
+ public void DownloadIfWanted(NzbInfoModel nzb, Indexer indexer)
{
//Do we want this item?
try
@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Providers
if (nzb.IsPassworded())
{
Logger.Debug("Skipping Passworded Report {0}", nzb.Title);
- return false;
+ return;
}
var episodeParseResults = Parser.ParseEpisodeInfo(nzb.Title);
@@ -56,24 +56,26 @@ namespace NzbDrone.Core.Providers
if (episodeParseResults.Count() > 0)
{
ProcessStandardItem(nzb, indexer, episodeParseResults);
- return false;
+ return;
}
- //Todo: Try to handle Season X style naming
+ //Handles Full Season NZBs
+ var seasonParsedResult = Parser.ParseSeasonInfo(nzb.Title);
- if (episodeParseResults.Count() < 1)
+ if (seasonParsedResult != null)
{
- Logger.Debug("Unsupported Title: {0}", nzb.Title);
- return false;
+ //ProcessFullSeasonItem
+ return;
}
+
+ Logger.Debug("Unsupported Title: {0}", nzb.Title);
}
catch (Exception ex)
{
Logger.Error("Unsupported Title: {0}", nzb.Title);
- Logger.ErrorException("Error Parsing NZB: " + ex.Message, ex);
+ Logger.ErrorException("Error Parsing/Processing NZB: " + ex.Message, ex);
}
- return false;
}
public string GetTitleFix(List episodes, int seriesId)
@@ -157,39 +159,19 @@ namespace NzbDrone.Core.Providers
return;
}
- //If their is more than one episode in this NZB check to see if it has been added as a single NZB
-
- //Do we want to download the NZB Directly or Send to SABnzbd?
-
nzb.TitleFix = GetTitleFix(episodeParseResults, series.SeriesId); //Get the TitleFix so we can use it later
nzb.TitleFix = String.Format("{0} [{1}]", nzb.TitleFix, nzb.Quality); //Add Quality to the titleFix
if (Convert.ToBoolean(_configProvider.GetValue("UseBlackHole", true, true)))
{
- var path = _configProvider.GetValue("BlackholeDirectory", String.Empty, true);
-
- if (String.IsNullOrEmpty(path))
- {
- //Use the NZBDrone root Directory + /NZBs
- //path = CentralDispatch.StartupPath + "NZBs";
- path = @"C:\Test\NZBs";
- }
-
- if (_diskProvider.FolderExists(path))
- {
- var filename = path + Path.DirectorySeparatorChar + nzb.TitleFix + ".nzb";
-
- if (_httpProvider.DownloadFile(nzb.Link.ToString(), filename))
- AddToHistory(episodeParseResults, series, nzb, indexer);
- }
-
- else
- Logger.Error("Blackhole Directory doesn't exist, not saving NZB: '{0}'", path);
+ if (DownloadNzb(nzb))
+ AddToHistory(episodeParseResults, series, nzb, indexer);
}
//Send it to SABnzbd
else
{
+ //Only need to do this check if it contains more than one episode (because we already checked individually before)
if (episodeParseResults.Count > 1)
{
if (_sabProvider.IsInQueue(nzb.TitleFix))
@@ -199,18 +181,140 @@ namespace NzbDrone.Core.Providers
if (indexer.IndexerName != "Newzbin")
{
if (AddByUrl(nzb))
- {
AddToHistory(episodeParseResults, series, nzb, indexer);
- }
-
}
-
+
else
{
- //AddById(episodeParseResults, series, nzb, indexer);
+ //Send to SAB using Newzbin ID
}
}
-
+ }
+
+ private void ProcessFullSeasonItem(NzbInfoModel nzb, Indexer indexer, SeasonParseResult seasonParseResult)
+ {
+ //Will try to match via NormalizeTitle, if that fails it will look for a scene name and do a lookup for your shows
+ var series = _seriesProvider.FindSeries(seasonParseResult.SeriesTitle);
+
+ if (series == null)
+ {
+ //If we weren't able to find a title using the clean name, lets try again looking for a scene name
+
+ var sceneId = SceneNameHelper.FindByName(seasonParseResult.SeriesTitle);
+
+ if (sceneId != 0)
+ series = _seriesProvider.GetSeries(sceneId);
+
+ if (series == null)
+ {
+ Logger.Debug("Show is not being watched: {0}", seasonParseResult.SeriesTitle);
+ return;
+ }
+ }
+
+ Logger.Debug("Show is being watched: {0}", series.Title);
+
+ nzb.Proper = Parser.ParseProper(nzb.Title);
+ nzb.Quality = Parser.ParseQuality(nzb.Title);
+
+ if (!_seriesProvider.QualityWanted(series.SeriesId, nzb.Quality))
+ {
+ Logger.Info("Quality [{0}] is not wanted for: {1}", nzb.Quality, series.Title);
+ return;
+ }
+
+ var season = _seasonProvider.GetSeason(series.SeriesId, seasonParseResult.SeasonNumber);
+
+ if (season == null)
+ return;
+
+ if (_seasonProvider.IsIgnored(season.SeriesId))
+ return;
+
+ //Check to see if this is an upgrade for all our files
+
+ var episodesWithoutFiles = season.Episodes.Where(e => e.EpisodeFileId == 0);
+
+ var downloadWholeSeason = false;
+
+ if (season.Episodes.Count() == episodesWithoutFiles.Count())
+ {
+ //We don't have any episodes for this season, so as it stands right now we need the entire NZB
+ //Download!
+ downloadWholeSeason = true;
+ }
+
+ else
+ {
+ var episodesNeeded = season.Episodes.Count;
+
+ foreach (var episode in season.Episodes)
+ {
+ var episodeModel = new EpisodeModel();
+ episodeModel.Proper = nzb.Proper;
+ episodeModel.SeriesId = series.SeriesId;
+ episodeModel.SeriesTitle = series.Title;
+ episodeModel.Quality = nzb.Quality;
+ episodeModel.SeasonNumber = episode.SeasonNumber;
+ episodeModel.EpisodeNumber = episode.EpisodeNumber;
+
+ if (!_episodeProvider.IsNeeded(episodeModel))
+ {
+ downloadWholeSeason = false;
+ episodesNeeded--; //Decrement the number of downloads we need, used if we want to replace all existing episodes if this will upgrade over X% of files
+ break; //We only want to download this NZB if ALL episodes can be upgraded by this Season NZB
+ }
+ }
+ }
+
+ if (downloadWholeSeason)
+ {
+ //Do the final check to ensure we should download this NZB
+
+ if (Convert.ToBoolean(_configProvider.GetValue("UseBlackHole", true, true)))
+ {
+ if (DownloadNzb(nzb))
+ {
+ var episodeParseResults = new List();
+ episodeParseResults.AddRange(
+ season.Episodes.Select(
+ e =>
+ new EpisodeParseResult {EpisodeNumber = e.EpisodeNumber, SeasonNumber = e.SeasonNumber}));
+
+ AddToHistory(episodeParseResults, series, nzb, indexer);
+ }
+ }
+
+ //Send it to SABnzbd
+ else
+ {
+ if (_sabProvider.IsInQueue(nzb.TitleFix))
+ return;
+
+ if (indexer.IndexerName != "Newzbin")
+ {
+ if (AddByUrl(nzb))
+ {
+ var episodeParseResults = new List();
+ episodeParseResults.AddRange(
+ season.Episodes.Select(
+ e =>
+ new EpisodeParseResult { EpisodeNumber = e.EpisodeNumber, SeasonNumber = e.SeasonNumber }));
+
+ AddToHistory(episodeParseResults, series, nzb, indexer);
+ }
+
+ }
+
+ else
+ {
+ //Send to SAB using Newzbin ID
+ }
+ }
+ }
+
+ //Possibly grab the whole season if a certain % of the season is missing, rather than for 1 or 2 episodes
+ throw new NotImplementedException("NzbDrone is currently not able to handle downloadinga whole season when less than a whole season it missing");
}
private bool AddByUrl(NzbInfoModel nzb)
@@ -246,5 +350,28 @@ namespace NzbDrone.Core.Providers
_historyProvider.Insert(history);
}
}
+
+ private bool DownloadNzb(NzbInfoModel nzb)
+ {
+ var path = _configProvider.GetValue("BlackholeDirectory", String.Empty, true);
+
+ if (String.IsNullOrEmpty(path))
+ {
+ //Use the NZBDrone root Directory + /NZBs
+ //path = CentralDispatch.StartupPath + "NZBs";
+ path = @"C:\Test\NZBs";
+ }
+
+ if (_diskProvider.FolderExists(path))
+ {
+ var filename = path + Path.DirectorySeparatorChar + nzb.TitleFix + ".nzb";
+
+ if (_httpProvider.DownloadFile(nzb.Link.ToString(), filename))
+ return true;
+ }
+
+ Logger.Error("Blackhole Directory doesn't exist, not saving NZB: '{0}'", path);
+ return false;
+ }
}
}
diff --git a/NzbDrone.Core/Providers/SabProvider.cs b/NzbDrone.Core/Providers/SabProvider.cs
index 1b60d60f3..9d49a76f8 100644
--- a/NzbDrone.Core/Providers/SabProvider.cs
+++ b/NzbDrone.Core/Providers/SabProvider.cs
@@ -92,8 +92,6 @@ namespace NzbDrone.Core.Providers
return true;
return false;
-
- throw new NotImplementedException();
}
#endregion
diff --git a/NzbDrone.Core/Providers/SeasonProvider.cs b/NzbDrone.Core/Providers/SeasonProvider.cs
index 21eaa2a8c..eea1a5370 100644
--- a/NzbDrone.Core/Providers/SeasonProvider.cs
+++ b/NzbDrone.Core/Providers/SeasonProvider.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using NLog;
+using NzbDrone.Core.Model;
using NzbDrone.Core.Repository;
using SubSonic.Repository;
using System.Linq;
@@ -10,11 +11,14 @@ namespace NzbDrone.Core.Providers
class SeasonProvider : ISeasonProvider
{
private readonly IRepository _sonicRepo;
+ private readonly ISeriesProvider _seriesProvider;
+
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
- public SeasonProvider(IRepository dataRepository)
+ public SeasonProvider(IRepository dataRepository, ISeriesProvider seriesProvider)
{
_sonicRepo = dataRepository;
+ _seriesProvider = seriesProvider;
}
public Season GetSeason(int seasonId)
@@ -22,6 +26,11 @@ namespace NzbDrone.Core.Providers
return _sonicRepo.Single(seasonId);
}
+ public Season GetSeason(int seriesId, int seasonNumber)
+ {
+ return _sonicRepo.Single(s => s.SeriesId == seriesId && s.SeasonNumber == seasonNumber);
+ }
+
public List GetSeasons(int seriesId)
{
return _sonicRepo.All().Where(s => s.SeriesId == seriesId).ToList();
@@ -70,7 +79,7 @@ namespace NzbDrone.Core.Providers
if (season == null)
return true;
- return season.Monitored;
+ return !season.Monitored;
}
public void DeleteSeason(int seasonId)