diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index 115d6abfa..bbcd65f06 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -63,11 +63,13 @@ namespace NzbDrone.Core _kernel.Bind().To(); _kernel.Bind().To(); _kernel.Bind().To(); + _kernel.Bind().To(); _kernel.Bind().To(); _kernel.Bind().To(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); + _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); diff --git a/NzbDrone.Core/Helpers/SceneNameHelper.cs b/NzbDrone.Core/Helpers/SceneNameHelper.cs index fd3caf08b..48957240c 100644 --- a/NzbDrone.Core/Helpers/SceneNameHelper.cs +++ b/NzbDrone.Core/Helpers/SceneNameHelper.cs @@ -74,9 +74,9 @@ namespace NzbDrone.Core.Helpers new SceneNameModel { SeriesId = 73244, Name = "The Office US" }, }; - public static int FindByName(string seriesName) + public static int FindByName(string cleanSeriesName) { - var map = _sceneNameMappings.Single(s => s.Name == seriesName); + var map = _sceneNameMappings.Single(s => Parser.NormalizeTitle(s.Name) == cleanSeriesName); if (map == null) return 0; diff --git a/NzbDrone.Core/Model/EpisodeParseResult.cs b/NzbDrone.Core/Model/EpisodeParseResult.cs index 5fd6f6bf4..cafde35f4 100644 --- a/NzbDrone.Core/Model/EpisodeParseResult.cs +++ b/NzbDrone.Core/Model/EpisodeParseResult.cs @@ -3,7 +3,7 @@ using SubSonic.SqlGeneration.Schema; namespace NzbDrone.Core.Model { - internal class EpisodeParseResult + public class EpisodeParseResult { internal string SeriesTitle { get; set; } internal int SeasonNumber { get; set; } diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 7ff84ac3e..2fdee13df 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -189,6 +189,7 @@ + @@ -197,6 +198,7 @@ + diff --git a/NzbDrone.Core/Providers/BacklogProvider.cs b/NzbDrone.Core/Providers/BacklogProvider.cs index cf5cb4e4a..f32b8f808 100644 --- a/NzbDrone.Core/Providers/BacklogProvider.cs +++ b/NzbDrone.Core/Providers/BacklogProvider.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.Providers private readonly IConfigProvider _configProvider; private readonly IIndexerProvider _indexerProvider; private readonly IRssProvider _rssProvider; + private readonly IRssItemProcessingProvider _rssItemProcessor; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private List _seriesList; @@ -28,7 +29,7 @@ namespace NzbDrone.Core.Providers public BacklogProvider(ISeriesProvider seriesProvider, INotificationProvider notificationProvider, IConfigProvider configProvider, IIndexerProvider indexerProvider, - IRssProvider rssProvider) + IRssProvider rssProvider, IRssItemProcessingProvider _rssItemProcessor) { _seriesProvider = seriesProvider; _notificationProvider = notificationProvider; diff --git a/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs b/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs new file mode 100644 index 000000000..c57fb2c81 --- /dev/null +++ b/NzbDrone.Core/Providers/IRssItemProcessingProvider.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Core.Model; +using NzbDrone.Core.Repository; + +namespace NzbDrone.Core.Providers +{ + public interface IRssItemProcessingProvider + { + //This interface will contain methods to process individual RSS Feed Items (Queue if wanted) + + void QueueIfWanted(NzbInfoModel nzb, Indexer indexer); + string GetTitleFix(List episodes, int seriesId); + } +} diff --git a/NzbDrone.Core/Providers/RssItemProcessingProvider.cs b/NzbDrone.Core/Providers/RssItemProcessingProvider.cs new file mode 100644 index 000000000..4b6bc0506 --- /dev/null +++ b/NzbDrone.Core/Providers/RssItemProcessingProvider.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using NzbDrone.Core.Helpers; +using NzbDrone.Core.Model; +using NzbDrone.Core.Repository; + +namespace NzbDrone.Core.Providers +{ + public class RssItemProcessingProvider : IRssItemProcessingProvider + { + private ISeriesProvider _seriesProvider; + private ISeasonProvider _seasonProvider; + private IEpisodeProvider _episodeProvider; + private IHistoryProvider _historyProvider; + private IDownloadProvider _sabProvider; + private IConfigProvider _configProvider; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public RssItemProcessingProvider(ISeriesProvider seriesProvider, ISeasonProvider seasonProvider, + IEpisodeProvider episodeProvider, IHistoryProvider historyProvider, + IDownloadProvider sabProvider, IConfigProvider configProvider) + { + _seriesProvider = seriesProvider; + _seasonProvider = seasonProvider; + _episodeProvider = episodeProvider; + _historyProvider = historyProvider; + _sabProvider = sabProvider; + _configProvider = configProvider; + } + + #region IRssItemProcessingProvider Members + + public void QueueIfWanted(NzbInfoModel nzb, Indexer indexer) + { + //Do we want this item? + try + { + if (nzb.IsPassworded()) + { + Logger.Debug("Skipping Passworded Report {0}", nzb.Title); + return; + } + + var episodeParseResults = Parser.ParseEpisodeInfo(nzb.Title); + + if (episodeParseResults.Count() > 1) + { + ProcessStandardItem(nzb, indexer, episodeParseResults); + return; + } + + //Try to handle Season X style naming + + if (episodeParseResults.Count() < 1) + { + Logger.Debug("Unsupported Title: {0}", nzb.Title); + return; + } + } + + catch (Exception ex) + { + Logger.ErrorException("Error Parsing NZB: " + ex.Message, ex); + } + } + + public string GetTitleFix(List episodes, int seriesId) + { + var series = _seriesProvider.GetSeries(seriesId); + + int seasonNumber = 0; + string episodeNumbers = String.Empty; + string episodeTitles = String.Empty; + + foreach (var episode in episodes) + { + var episodeInDb = _episodeProvider.GetEpisode(seriesId, episode.SeasonNumber, episode.EpisodeNumber); + + if (episodeInDb == null) + { + Logger.Debug("Episode Not found in Database"); + return String.Format("{0} - {1:00}x{2}", series.Title, episode.SeasonNumber, episode.SeriesTitle); + } + + seasonNumber = episodeInDb.SeasonNumber; + episodeNumbers = String.Format("{0}x{1:00}", episodeNumbers, episodeInDb.EpisodeNumber); + episodeTitles = String.Format("{0} + {1}", episodeTitles, episodeInDb.Title); + } + + episodeTitles = episodeTitles.Trim(' ', '+'); + + return String.Format("{0} - {1}{2} - {3}", series.Title, seasonNumber, episodeNumbers, episodeTitles); + } + + #endregion + + private void ProcessStandardItem(NzbInfoModel nzb, Indexer indexer, List episodeParseResults) + { + //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(episodeParseResults[0].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 + series = _seriesProvider.GetSeries(SceneNameHelper.FindByName(episodeParseResults[0].SeriesTitle)); + + if (series == null) + { + Logger.Debug("Show is not being watched: {0}", episodeParseResults[0].SeriesTitle); + return; + } + } + + Logger.Debug("Show is being watched: {0}", series.Title); + + nzb.TitleFix = GetTitleFix(episodeParseResults, series.SeriesId); //Get the TitleFix so we can use it later + + nzb.Proper = Parser.ParseProper(nzb.Title); + nzb.Quality = Parser.ParseQuality(nzb.Title); + + nzb.TitleFix = String.Format("{0} [{1}]", nzb.TitleFix, nzb.Quality); //Add Quality to the titleFix + + //Loop through the list of the episodeParseResults to ensure that all the episodes are needed + foreach (var episode in episodeParseResults) + { + //IsEpisodeWanted? + 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)) + return; + + var titleFix = GetTitleFix(new List { episode }, episodeModel.SeriesId); + titleFix = String.Format("{0} [{1}]", titleFix, nzb.Quality); //Add Quality to the titleFix + + if (_sabProvider.IsInQueue(titleFix)) + return; + } + + //If their is more than one episode in this NZB check to see if it has been added as a single NZB + if (episodeParseResults.Count > 1) + { + if (_sabProvider.IsInQueue(nzb.TitleFix)) + return; + } + + //Only add to history if it was added to properly sent to SABnzbd + if (indexer.IndexerName != "Newzbin") + AddByUrl(episodeParseResults, series, nzb, indexer); + + else + { + //AddById(episodeParseResults, series, nzb, indexer); + } + } + + private void AddByUrl(List episodeParseResults, Series series, NzbInfoModel nzb, Indexer indexer) + { + if (_sabProvider.AddByUrl(nzb.Link.ToString(), nzb.TitleFix)) + { + //We need to loop through the episodeParseResults so each episode in the NZB is properly handled + foreach (var epr in episodeParseResults) + { + var episode = _episodeProvider.GetEpisode(series.SeriesId, epr.SeasonNumber, epr.EpisodeNumber); + + if (episode == null) + { + //Not sure how we got this far, so lets throw an exception + throw new ArgumentOutOfRangeException(); + } + + //Set episode status to grabbed + episode.Status = EpisodeStatusType.Grabbed; + + //Add to History + var history = new History(); + history.Date = DateTime.Now; + history.EpisodeId = episode.EpisodeId; + history.IndexerName = indexer.IndexerName; + history.IsProper = nzb.Proper; + history.Quality = nzb.Quality; + history.NzbTitle = nzb.Title; + + _historyProvider.Insert(history); + } + } + } + } +} diff --git a/NzbDrone.Core/Providers/RssSyncProvider.cs b/NzbDrone.Core/Providers/RssSyncProvider.cs index 3299a2695..f86ddb0be 100644 --- a/NzbDrone.Core/Providers/RssSyncProvider.cs +++ b/NzbDrone.Core/Providers/RssSyncProvider.cs @@ -26,14 +26,18 @@ namespace NzbDrone.Core.Providers private IHistoryProvider _history; private IDownloadProvider _sab; private IConfigProvider _configProvider; + private IRssItemProcessingProvider _rssItemProcessor; private readonly INotificationProvider _notificationProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private ProgressNotification _rssSyncNotification; - public RssSyncProvider(IIndexerProvider indexerProvider, IRssProvider rss, ISeriesProvider series, - ISeasonProvider season, IEpisodeProvider episode, IHistoryProvider history, IDownloadProvider sab, INotificationProvider notificationProvider, IConfigProvider configProvider) + public RssSyncProvider(IIndexerProvider indexerProvider, IRssProvider rss, + ISeriesProvider series, ISeasonProvider season, + IEpisodeProvider episode, IHistoryProvider history, + IDownloadProvider sab, INotificationProvider notificationProvider, + IConfigProvider configProvider, IRssItemProcessingProvider rssItemProcessor) { _indexerProvider = indexerProvider; _rss = rss; @@ -44,6 +48,7 @@ namespace NzbDrone.Core.Providers _sab = sab; _notificationProvider = notificationProvider; _configProvider = configProvider; + _rssItemProcessor = rssItemProcessor; } #region IRssSyncProvider Members @@ -113,7 +118,7 @@ namespace NzbDrone.Core.Providers foreach (RssItem item in feedItems) { NzbInfoModel nzb = Parser.ParseNzbInfo(indexer, item); - QueueIfWanted(nzb, i); + _rssItemProcessor.QueueIfWanted(nzb, i); } } _rssSyncNotification.CurrentStatus = "RSS Sync Completed"; @@ -123,143 +128,6 @@ namespace NzbDrone.Core.Providers } } - private void QueueIfWanted(NzbInfoModel nzb, Indexer indexer) - { - //Do we want this item? - try - { - if (nzb.IsPassworded()) - { - Logger.Debug("Skipping Passworded Report {0}", nzb.Title); - return; - } - - var episodeParseResults = Parser.ParseEpisodeInfo(nzb.Title); - - if (episodeParseResults.Count() < 1) - { - Logger.Debug("Unsupported Title: {0}", nzb.Title); - return; - } - - //Todo: How to determine if we want the show if the FeedTitle is drastically different from the TitleOnDisk (CSI is one that comes to mind) - var series = _series.FindSeries(episodeParseResults[0].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 - series = _series.GetSeries(SceneNameHelper.FindByName(episodeParseResults[0].SeriesTitle)); - - if (series == null) - { - Logger.Debug("Show is not being watched: {0}", episodeParseResults[0].SeriesTitle); - return; - } - } - - Logger.Debug("Show is being watched: {0}", series.Title); - - nzb.TitleFix = GetTitleFix(episodeParseResults, series.SeriesId); //Get the TitleFix so we can use it later - - nzb.Proper = Parser.ParseProper(nzb.Title); - nzb.Quality = Parser.ParseQuality(nzb.Title); - - nzb.TitleFix = String.Format("{0} [{1}]", nzb.TitleFix, nzb.Quality); //Add Quality to the titleFix - - //Loop through the list of the episodeParseResults to ensure that all the episodes are needed) - foreach (var episode in episodeParseResults) - { - //IsEpisodeWanted? - 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 (!_episode.IsNeeded(episodeModel)) - return; - - var titleFix = GetTitleFix(new List { episode }, episodeModel.SeriesId); - titleFix = String.Format("{0} [{1}]", titleFix, nzb.Quality); //Add Quality to the titleFix - - if (_sab.IsInQueue(titleFix)) - return; - } - - //If their is more than one episode in this NZB check to see if it has been added as a single NZB - if (episodeParseResults.Count > 1) - { - if (_sab.IsInQueue(nzb.TitleFix)) - return; - } - - //Only add to history if it was added to properly sent to SABnzbd - if (_sab.AddByUrl(nzb.Link.ToString(), nzb.TitleFix)) - { - //We need to loop through the episodeParseResults so each episode in the NZB is properly handled - foreach (var epr in episodeParseResults) - { - var episode = _episode.GetEpisode(series.SeriesId, epr.SeasonNumber, epr.EpisodeNumber); - - if (episode == null) - { - //Not sure how we got this far, so lets throw an exception - throw new ArgumentOutOfRangeException(); - } - - //Set episode status to grabbed - episode.Status = EpisodeStatusType.Grabbed; - - //Add to History - var history = new History(); - history.Date = DateTime.Now; - history.EpisodeId = episode.EpisodeId; - history.IndexerName = indexer.IndexerName; - history.IsProper = nzb.Proper; - history.Quality = nzb.Quality; - history.NzbTitle = nzb.Title; - - _history.Insert(history); - } - } - } - - catch (Exception ex) - { - Logger.ErrorException("Error Parsing NZB: " + ex.Message, ex); - } - } - - private string GetTitleFix(List episodes, int seriesId) - { - var series = _series.GetSeries(seriesId); - - int seasonNumber = 0; - string episodeNumbers = String.Empty; - string episodeTitles = String.Empty; - - foreach (var episode in episodes) - { - var episodeInDb = _episode.GetEpisode(seriesId, episode.SeasonNumber, episode.EpisodeNumber); - - if (episodeInDb == null) - { - Logger.Debug("Episode Not found in Database"); - return String.Format("{0} - {1:00}x{2}", series.Title, episode.SeasonNumber, episode.SeriesTitle); - } - - seasonNumber = episodeInDb.SeasonNumber; - episodeNumbers = String.Format("{0}x{1:00}", episodeNumbers, episodeInDb.EpisodeNumber); - episodeTitles = String.Format("{0} + {1}", episodeTitles, episodeInDb.Title); - } - - episodeTitles = episodeTitles.Trim(' ', '+'); - - return String.Format("{0} - {1}{2} - {3}", series.Title, seasonNumber, episodeNumbers, episodeTitles); - } - private void GetUsersUrl(Indexer indexer) { if (indexer.IndexerName == "NzbMatrix") diff --git a/NzbDrone.Core/Providers/XbmcProvider.cs b/NzbDrone.Core/Providers/XbmcProvider.cs index cd9621d10..9f7bac7f0 100644 --- a/NzbDrone.Core/Providers/XbmcProvider.cs +++ b/NzbDrone.Core/Providers/XbmcProvider.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Text; using System.Xml.Linq; using NLog; @@ -15,12 +14,10 @@ namespace NzbDrone.Core.Providers private readonly IConfigProvider _configProvider; private readonly IHttpProvider _httpProvider; - private WebClient _webClient; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public XbmcProvider(IConfigProvider configProvider, IHttpProvider httpProvider) { - _webClient = new WebClient(); _configProvider = configProvider; _httpProvider = httpProvider; } diff --git a/NzbDrone.Web/Content/style.css b/NzbDrone.Web/Content/style.css index dd0e83363..bd306bee2 100644 --- a/NzbDrone.Web/Content/style.css +++ b/NzbDrone.Web/Content/style.css @@ -239,6 +239,11 @@ input[type="text"]:hover /* Add Series */ .tvDbSearchResults +{ + width: 400px; +} + +.rootDirectories { width: 400px; } \ No newline at end of file diff --git a/NzbDrone.Web/Views/Series/AddNew.aspx b/NzbDrone.Web/Views/Series/AddNew.aspx index 7bf3bba21..fc015ab6a 100644 --- a/NzbDrone.Web/Views/Series/AddNew.aspx +++ b/NzbDrone.Web/Views/Series/AddNew.aspx @@ -29,7 +29,7 @@
-