diff --git a/NzbDrone.Core/Model/NzbInfoModel.cs b/NzbDrone.Core/Model/NzbInfoModel.cs deleted file mode 100644 index 7f3264740..000000000 --- a/NzbDrone.Core/Model/NzbInfoModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace NzbDrone.Core.Model -{ - public class NzbInfoModel - { - public string Title { get; set; } - public Uri Link { get; set; } - - public bool IsPassworded() - { - return Title.EndsWith("(Passworded)", StringComparison.InvariantCultureIgnoreCase); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index ac032a955..94a53b6bd 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -180,7 +180,6 @@ - diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index b9558bdbd..de9073b02 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -1,293 +1,230 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using NLog; -using NzbDrone.Core.Model; -using NzbDrone.Core.Repository; -using SubSonic.Repository; - -namespace NzbDrone.Core.Providers -{ - public class EpisodeProvider - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly QualityProvider _quality; - private readonly SeasonProvider _seasons; - private readonly SeriesProvider _series; - private readonly IRepository _sonicRepo; - private readonly TvDbProvider _tvDb; - - public EpisodeProvider(IRepository sonicRepo, SeriesProvider seriesProvider, - SeasonProvider seasonProvider, TvDbProvider tvDbProvider, - QualityProvider quality) - { - _sonicRepo = sonicRepo; - _series = seriesProvider; - _tvDb = tvDbProvider; - _seasons = seasonProvider; - _quality = quality; - } - - public EpisodeProvider() - { - } - - public virtual Episode GetEpisode(long id) - { - return _sonicRepo.Single(id); - } - - public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) - { - return - _sonicRepo.Single( - c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber); - } - - public virtual IList GetEpisodeBySeries(long seriesId) - { - return _sonicRepo.Find(e => e.SeriesId == seriesId); - } - - public virtual IList GetEpisodeBySeason(long seasonId) - { - return _sonicRepo.Find(e => e.SeasonId == seasonId); - } - - public virtual IList GetEpisodeByParseResult(EpisodeParseResult parseResult) - { - var seasonEpisodes = _sonicRepo.All().Where(e => - e.SeriesId == parseResult.SeriesId && - e.SeasonNumber == parseResult.SeasonNumber).ToList(); - - //Has to be done separately since subsonic doesn't support contain method - return seasonEpisodes.Where(c => parseResult.Episodes.Contains(c.EpisodeNumber)).ToList(); - - } - - public virtual String GetSabTitle(EpisodeParseResult parseResult) - { - //Show Name - 1x01-1x02 - Episode Name - //Show Name - 1x01 - Episode Name - var episodeString = new List(); - - foreach (var episode in parseResult.Episodes) - { - episodeString.Add(String.Format("{0}x{1}", parseResult.SeasonNumber, episode)); - } - - var epNumberString = String.Join("-", episodeString); - var series = _series.GetSeries(parseResult.SeriesId); - var folderName = new DirectoryInfo(series.Path).Name; - - var result = String.Format("{0} - {1} - {2} {3}", folderName, epNumberString, parseResult.EpisodeTitle, parseResult.Quality); - - if (parseResult.Proper) - { - result += " [Proper]"; - } - - return result; - } - - /// - /// Comprehensive check on whether or not this episode is needed. - /// - /// Episode that needs to be checked - /// - public virtual bool IsNeeded(EpisodeParseResult parsedReport) - { - foreach (var episode in parsedReport.Episodes) - { - var episodeInfo = GetEpisode(parsedReport.SeriesId, parsedReport.SeasonNumber, episode); - - if (episodeInfo == null) - { - - //Todo: How do we want to handle this really? Episode could be released before information is on TheTvDB - //(Parks and Rec did this a lot in the first season, from experience) - //Keivan: Should automatically add the episode to db with minimal information. then update the description/title when available. - episodeInfo = new Episode - { - SeriesId = parsedReport.SeriesId, - AirDate = DateTime.Now.Date, - EpisodeNumber = episode, - SeasonNumber = parsedReport.SeasonNumber, - Title = String.Empty, - Overview = String.Empty, - Language = "en" - }; - - _sonicRepo.Add(episodeInfo); - - } - - var file = episodeInfo.EpisodeFile; - - if (file != null) - { - //If not null we need to see if this episode has the quality as the download (or if it is better) - if (file.Quality == parsedReport.Quality && file.Proper) continue; - - //There will never be a time when the episode quality is less than what we have and we want it... ever.... I think. - if (file.Quality > parsedReport.Quality) continue; - - //Now we need to handle upgrades and actually pay attention to the Cutoff Value - if (file.Quality < parsedReport.Quality) - { - var quality = _quality.Find(episodeInfo.Series.QualityProfileId); - - if (quality.Cutoff <= file.Quality && file.Proper) continue; - } - } - - return true; //If we get to this point and the file has not yet been rejected then accept it - } - - return false; - } - - public virtual void RefreshEpisodeInfo(int seriesId) - { - Logger.Info("Starting episode info refresh for series:{0}", seriesId); - int successCount = 0; - int failCount = 0; - var targetSeries = _tvDb.GetSeries(seriesId, true); - - var updateList = new List(); - var newList = new List(); - - Logger.Debug("Updating season info for series:{0}", targetSeries.SeriesName); - targetSeries.Episodes.Select(e => new { e.SeasonId, e.SeasonNumber }) - .Distinct().ToList() - .ForEach(s => _seasons.EnsureSeason(seriesId, s.SeasonId, s.SeasonNumber)); - - foreach (var episode in targetSeries.Episodes) - { - try - { - //DateTime throws an error in SQLServer per message below: - //SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM. - //So lets hack it so it works for SQLServer (as well as SQLite), perhaps we can find a better solution - //Todo: Fix this hack - if (episode.FirstAired < new DateTime(1753, 1, 1)) - episode.FirstAired = new DateTime(1753, 1, 1); - - Logger.Trace("Updating info for [{0}] - S{1}E{2}", targetSeries.SeriesName, episode.SeasonNumber, episode.EpisodeNumber); - var newEpisode = new Episode - { - AirDate = episode.FirstAired, - EpisodeId = episode.Id, - EpisodeNumber = episode.EpisodeNumber, - Language = episode.Language.Abbriviation, - Overview = episode.Overview, - SeasonId = episode.SeasonId, - SeasonNumber = episode.SeasonNumber, - SeriesId = seriesId, - Title = episode.EpisodeName - }; - - if (_sonicRepo.Exists(e => e.EpisodeId == newEpisode.EpisodeId)) - { - updateList.Add(newEpisode); - } - else - { - newList.Add(newEpisode); - } - - successCount++; - } - catch (Exception e) - { - Logger.FatalException( - String.Format("An error has occurred while updating episode info for series {0}", seriesId), e); - failCount++; - } - } - - _sonicRepo.AddMany(newList); - _sonicRepo.UpdateMany(updateList); - - Logger.Debug("Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} ", - targetSeries.SeriesName, successCount, failCount); - } - - public virtual void RefreshEpisodeInfo(Season season) - { - Logger.Info("Starting episode info refresh for season {0} of series:{1}", season.SeasonNumber, - season.SeriesId); - int successCount = 0; - int failCount = 0; - var targetSeries = _tvDb.GetSeries(season.SeriesId, true); - - var updateList = new List(); - var newList = new List(); - - foreach (var episode in targetSeries.Episodes.Where(e => e.SeasonId == season.SeasonId)) - { - try - { - //DateTime throws an error in SQLServer per message below: - //SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM. - //So lets hack it so it works for SQLServer (as well as SQLite), perhaps we can find a better solution - //Todo: Fix this hack - if (episode.FirstAired < new DateTime(1753, 1, 1)) - episode.FirstAired = new DateTime(1753, 1, 1); - - Logger.Trace("Updating info for series:{0} - episode:{1}", targetSeries.SeriesName, - episode.EpisodeNumber); - var newEpisode = new Episode - { - AirDate = episode.FirstAired, - EpisodeId = episode.Id, - EpisodeNumber = episode.EpisodeNumber, - Language = episode.Language.Abbriviation, - Overview = episode.Overview, - SeasonId = episode.SeasonId, - SeasonNumber = episode.SeasonNumber, - SeriesId = season.SeriesId, - Title = episode.EpisodeName - }; - - - //TODO: Replace this db check with a local check. Should make things even faster - if (_sonicRepo.Exists(e => e.EpisodeId == newEpisode.EpisodeId)) - { - updateList.Add(newEpisode); - } - else - { - newList.Add(newEpisode); - } - - successCount++; - } - catch (Exception e) - { - Logger.FatalException( - String.Format("An error has occurred while updating episode info for season {0} of series {1}", - season.SeasonNumber, season.SeriesId), e); - failCount++; - } - } - - _sonicRepo.AddMany(newList); - _sonicRepo.UpdateMany(updateList); - - Logger.Debug("Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} ", - targetSeries.SeriesName, successCount, failCount); - } - - public virtual void DeleteEpisode(int episodeId) - { - _sonicRepo.Delete(episodeId); - } - - public virtual void UpdateEpisode(Episode episode) - { - _sonicRepo.Update(episode); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NLog; +using NzbDrone.Core.Model; +using NzbDrone.Core.Repository; +using SubSonic.Repository; + +namespace NzbDrone.Core.Providers +{ + public class EpisodeProvider + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + private readonly QualityProvider _quality; + private readonly SeasonProvider _seasons; + private readonly SeriesProvider _series; + private readonly IRepository _sonicRepo; + private readonly TvDbProvider _tvDb; + + public EpisodeProvider(IRepository sonicRepo, SeriesProvider seriesProvider, + SeasonProvider seasonProvider, TvDbProvider tvDbProvider, + QualityProvider quality) + { + _sonicRepo = sonicRepo; + _series = seriesProvider; + _tvDb = tvDbProvider; + _seasons = seasonProvider; + _quality = quality; + } + + public EpisodeProvider() + { + } + + public virtual Episode GetEpisode(long id) + { + return _sonicRepo.Single(id); + } + + public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) + { + return + _sonicRepo.Single( + c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber); + } + + public virtual IList GetEpisodeBySeries(long seriesId) + { + return _sonicRepo.Find(e => e.SeriesId == seriesId); + } + + public virtual IList GetEpisodeBySeason(long seasonId) + { + return _sonicRepo.Find(e => e.SeasonId == seasonId); + } + + public virtual IList GetEpisodeByParseResult(EpisodeParseResult parseResult) + { + var seasonEpisodes = _sonicRepo.All().Where(e => + e.SeriesId == parseResult.SeriesId && + e.SeasonNumber == parseResult.SeasonNumber).ToList(); + + //Has to be done separately since subsonic doesn't support contain method + return seasonEpisodes.Where(c => parseResult.Episodes.Contains(c.EpisodeNumber)).ToList(); + + } + + public virtual String GetSabTitle(EpisodeParseResult parseResult) + { + //Show Name - 1x01-1x02 - Episode Name + //Show Name - 1x01 - Episode Name + var episodeString = new List(); + + foreach (var episode in parseResult.Episodes) + { + episodeString.Add(String.Format("{0}x{1}", parseResult.SeasonNumber, episode)); + } + + var epNumberString = String.Join("-", episodeString); + var series = _series.GetSeries(parseResult.SeriesId); + var folderName = new DirectoryInfo(series.Path).Name; + + var result = String.Format("{0} - {1} - {2} {3}", folderName, epNumberString, parseResult.EpisodeTitle, parseResult.Quality); + + if (parseResult.Proper) + { + result += " [Proper]"; + } + + return result; + } + + /// + /// Comprehensive check on whether or not this episode is needed. + /// + /// Episode that needs to be checked + /// + public virtual bool IsNeeded(EpisodeParseResult parsedReport) + { + foreach (var episode in parsedReport.Episodes) + { + var episodeInfo = GetEpisode(parsedReport.SeriesId, parsedReport.SeasonNumber, episode); + + if (episodeInfo == null) + { + + //Todo: How do we want to handle this really? Episode could be released before information is on TheTvDB + //(Parks and Rec did this a lot in the first season, from experience) + //Keivan: Should automatically add the episode to db with minimal information. then update the description/title when available. + episodeInfo = new Episode + { + SeriesId = parsedReport.SeriesId, + AirDate = DateTime.Now.Date, + EpisodeNumber = episode, + SeasonNumber = parsedReport.SeasonNumber, + Title = String.Empty, + Overview = String.Empty, + Language = "en" + }; + + _sonicRepo.Add(episodeInfo); + + } + + var file = episodeInfo.EpisodeFile; + + if (file != null) + { + //If not null we need to see if this episode has the quality as the download (or if it is better) + if (file.Quality == parsedReport.Quality && file.Proper) continue; + + //There will never be a time when the episode quality is less than what we have and we want it... ever.... I think. + if (file.Quality > parsedReport.Quality) continue; + + //Now we need to handle upgrades and actually pay attention to the Cutoff Value + if (file.Quality < parsedReport.Quality) + { + var quality = _quality.Find(episodeInfo.Series.QualityProfileId); + + if (quality.Cutoff <= file.Quality && file.Proper) continue; + } + } + + return true; //If we get to this point and the file has not yet been rejected then accept it + } + + return false; + } + + public virtual void RefreshEpisodeInfo(int seriesId) + { + Logger.Info("Starting episode info refresh for series:{0}", seriesId); + int successCount = 0; + int failCount = 0; + var targetSeries = _tvDb.GetSeries(seriesId, true); + + var updateList = new List(); + var newList = new List(); + + Logger.Debug("Updating season info for series:{0}", targetSeries.SeriesName); + targetSeries.Episodes.Select(e => new { e.SeasonId, e.SeasonNumber }) + .Distinct().ToList() + .ForEach(s => _seasons.EnsureSeason(seriesId, s.SeasonId, s.SeasonNumber)); + + foreach (var episode in targetSeries.Episodes) + { + try + { + //DateTime throws an error in SQLServer per message below: + //SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM. + //So lets hack it so it works for SQLServer (as well as SQLite), perhaps we can find a better solution + //Todo: Fix this hack + if (episode.FirstAired < new DateTime(1753, 1, 1)) + episode.FirstAired = new DateTime(1753, 1, 1); + + Logger.Trace("Updating info for [{0}] - S{1}E{2}", targetSeries.SeriesName, episode.SeasonNumber, episode.EpisodeNumber); + var newEpisode = new Episode + { + AirDate = episode.FirstAired, + TvDbEpisodeId = episode.Id, + EpisodeNumber = episode.EpisodeNumber, + Language = episode.Language.Abbriviation, + Overview = episode.Overview, + SeasonId = episode.SeasonId, + SeasonNumber = episode.SeasonNumber, + SeriesId = seriesId, + Title = episode.EpisodeName + }; + + var existingEpisode = GetEpisode(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber); + + if (existingEpisode != null) + { + newEpisode.EpisodeId = existingEpisode.EpisodeId; + updateList.Add(newEpisode); + } + else + { + newList.Add(newEpisode); + } + + successCount++; + } + catch (Exception e) + { + Logger.FatalException( + String.Format("An error has occurred while updating episode info for series {0}", seriesId), e); + failCount++; + } + } + + _sonicRepo.AddMany(newList); + _sonicRepo.UpdateMany(updateList); + + Logger.Debug("Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} ", + targetSeries.SeriesName, successCount, failCount); + } + + public virtual void DeleteEpisode(int episodeId) + { + _sonicRepo.Delete(episodeId); + } + + public virtual void UpdateEpisode(Episode episode) + { + _sonicRepo.Update(episode); + } + } } \ No newline at end of file diff --git a/NzbDrone.Core/Repository/Episode.cs b/NzbDrone.Core/Repository/Episode.cs index f9092512c..348d8fabe 100644 --- a/NzbDrone.Core/Repository/Episode.cs +++ b/NzbDrone.Core/Repository/Episode.cs @@ -7,9 +7,11 @@ namespace NzbDrone.Core.Repository { public class Episode { - [SubSonicPrimaryKey(false)] + [SubSonicPrimaryKey] public virtual int EpisodeId { get; set; } + public int? TvDbEpisodeId { get; set; } + public virtual int SeriesId { get; set; } public virtual int EpisodeFileId { get; set; } public virtual int SeasonId { get; set; }