2010-09-28 19:32:19 +00:00
using System ;
2010-10-17 17:22:48 +00:00
using System.Linq ;
2010-09-28 19:32:19 +00:00
using System.Collections.Generic ;
2010-09-28 05:01:54 +00:00
using System.Text.RegularExpressions ;
2010-10-05 06:21:18 +00:00
using NLog ;
2010-10-21 01:49:23 +00:00
using NzbDrone.Core.Model ;
using NzbDrone.Core.Repository ;
2010-09-28 19:32:19 +00:00
using SubSonic.Repository ;
2010-09-28 05:01:54 +00:00
namespace NzbDrone.Core.Providers
{
2011-04-10 00:14:51 +00:00
public class EpisodeProvider
2010-09-28 05:01:54 +00:00
{
2010-09-28 19:32:19 +00:00
//TODO: Remove parsing of the series name, it should be done in series provider
private readonly IRepository _sonicRepo ;
2011-04-08 23:55:23 +00:00
private readonly SeriesProvider _series ;
2011-04-10 01:34:36 +00:00
private readonly SeasonProvider _seasons ;
2011-04-07 03:34:48 +00:00
private readonly TvDbProvider _tvDb ;
2011-04-08 23:58:46 +00:00
private readonly HistoryProvider _history ;
2011-04-08 04:03:46 +00:00
private readonly QualityProvider _quality ;
2010-10-07 22:17:24 +00:00
private static readonly Logger Logger = LogManager . GetCurrentClassLogger ( ) ;
2010-09-28 19:32:19 +00:00
2011-04-08 23:55:23 +00:00
public EpisodeProvider ( IRepository sonicRepo , SeriesProvider seriesProvider ,
2011-04-10 01:34:36 +00:00
SeasonProvider seasonProvider , TvDbProvider tvDbProvider ,
2011-04-08 23:58:46 +00:00
HistoryProvider history , QualityProvider quality )
2010-09-28 05:01:54 +00:00
{
2010-09-28 19:32:19 +00:00
_sonicRepo = sonicRepo ;
2010-10-05 06:21:18 +00:00
_series = seriesProvider ;
_tvDb = tvDbProvider ;
_seasons = seasonProvider ;
2011-01-29 06:10:22 +00:00
_history = history ;
2011-02-16 16:37:28 +00:00
_quality = quality ;
2010-09-28 19:32:19 +00:00
}
2011-04-10 00:14:51 +00:00
public EpisodeProvider ( )
{
}
public virtual Episode GetEpisode ( long id )
2010-09-28 19:32:19 +00:00
{
2010-10-24 07:46:58 +00:00
return _sonicRepo . Single < Episode > ( id ) ;
}
2011-04-10 00:14:51 +00:00
public virtual Episode GetEpisode ( int seriesId , int seasonNumber , int episodeNumber )
2010-10-24 07:46:58 +00:00
{
return _sonicRepo . Single < Episode > ( c = > c . SeriesId = = seriesId & & c . SeasonNumber = = seasonNumber & & c . EpisodeNumber = = episodeNumber ) ;
2010-09-28 19:32:19 +00:00
}
2011-04-10 00:14:51 +00:00
public virtual IList < Episode > GetEpisodeBySeries ( long seriesId )
2010-09-28 19:32:19 +00:00
{
2010-10-21 01:49:23 +00:00
return _sonicRepo . Find < Episode > ( e = > e . SeriesId = = seriesId ) ;
2010-09-28 19:32:19 +00:00
}
2011-04-10 00:14:51 +00:00
public virtual IList < Episode > GetEpisodeBySeason ( long seasonId )
2010-10-30 02:46:32 +00:00
{
return _sonicRepo . Find < Episode > ( e = > e . SeasonId = = seasonId ) ;
}
2011-04-10 00:14:51 +00:00
public virtual String GetSabTitle ( Episode episode )
2010-09-28 19:32:19 +00:00
{
2010-10-05 06:21:18 +00:00
var series = _series . GetSeries ( episode . SeriesId ) ;
2010-09-28 19:32:19 +00:00
if ( series = = null ) throw new ArgumentException ( "Unknown series. ID: " + episode . SeriesId ) ;
//TODO: This method should return a standard title for the sab episode.
throw new NotImplementedException ( ) ;
2010-09-28 05:01:54 +00:00
}
2010-09-28 19:32:19 +00:00
/// <summary>
/// Comprehensive check on whether or not this episode is needed.
/// </summary>
2011-04-04 04:54:58 +00:00
/// <param name="parsedReport">Episode that needs to be checked</param>
2010-09-28 19:32:19 +00:00
/// <returns></returns>
2011-04-10 00:14:51 +00:00
public virtual bool IsNeeded ( EpisodeParseResult parsedReport )
2010-09-28 05:01:54 +00:00
{
2011-04-04 04:54:58 +00:00
foreach ( var episode in parsedReport . Episodes )
2011-02-16 16:37:28 +00:00
{
2011-04-04 04:54:58 +00:00
var episodeInfo = GetEpisode ( parsedReport . SeriesId , parsedReport . SeasonNumber , episode ) ;
2011-01-29 06:10:22 +00:00
2011-04-04 04:54:58 +00:00
if ( episodeInfo = = null )
2011-01-29 06:10:22 +00:00
{
2011-04-04 04:54:58 +00:00
//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 avilable.
throw new NotImplementedException ( "Episode was not found in the database" ) ;
2011-02-22 08:13:16 +00:00
}
2011-04-04 04:54:58 +00:00
var file = episodeInfo . EpisodeFile ;
2011-02-22 08:13:16 +00:00
2011-04-04 04:54:58 +00:00
if ( file ! = null )
2011-02-22 08:13:16 +00:00
{
2011-04-04 04:54:58 +00:00
//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 ;
2011-02-22 08:13:16 +00:00
2011-04-04 04:54:58 +00:00
//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 )
2011-02-16 16:37:28 +00:00
{
2011-04-04 04:54:58 +00:00
var quality = _quality . Find ( episodeInfo . Series . QualityProfileId ) ;
if ( quality . Cutoff < = file . Quality & & file . Proper ) continue ;
2011-02-16 16:37:28 +00:00
}
2011-01-29 06:10:22 +00:00
}
2011-04-04 04:54:58 +00:00
//IsInHistory? (NZBDrone)
if ( _history . Exists ( episodeInfo . EpisodeId , parsedReport . Quality , parsedReport . Proper ) )
{
Logger . Debug ( "Episode in history: {0}" , episode . ToString ( ) ) ;
continue ;
}
return true ; //If we get to this point and the file has not yet been rejected then accept it
2011-01-29 06:10:22 +00:00
}
2011-04-04 04:54:58 +00:00
return false ;
2010-09-28 19:32:19 +00:00
}
2011-04-10 00:14:51 +00:00
public virtual void RefreshEpisodeInfo ( int seriesId )
2010-10-05 06:21:18 +00:00
{
Logger . Info ( "Starting episode info refresh for series:{0}" , seriesId ) ;
int successCount = 0 ;
int failCount = 0 ;
var targetSeries = _tvDb . GetSeries ( seriesId , true ) ;
2010-10-17 17:22:48 +00:00
2010-10-21 01:49:23 +00:00
var updateList = new List < Episode > ( ) ;
var newList = new List < Episode > ( ) ;
2010-10-17 17:22:48 +00:00
2010-10-30 02:46:32 +00:00
Logger . Debug ( "Updating season info for series:{0}" , targetSeries . SeriesName ) ;
2010-10-17 17:22:48 +00:00
targetSeries . Episodes . Select ( e = > new { e . SeasonId , e . SeasonNumber } )
. Distinct ( ) . ToList ( )
. ForEach ( s = > _seasons . EnsureSeason ( seriesId , s . SeasonId , s . SeasonNumber ) ) ;
2010-10-05 06:21:18 +00:00
foreach ( var episode in targetSeries . Episodes )
{
try
{
2011-01-29 06:10:22 +00:00
//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 ) ;
2010-10-30 02:46:32 +00:00
Logger . Trace ( "Updating info for series:{0} - episode:{1}" , targetSeries . SeriesName , episode . EpisodeNumber ) ;
2010-10-21 01:49:23 +00:00
var newEpisode = new Episode ( )
2010-10-17 17:22:48 +00:00
{
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
} ;
2010-10-21 01:49:23 +00:00
if ( _sonicRepo . Exists < Episode > ( e = > e . EpisodeId = = newEpisode . EpisodeId ) )
2010-10-05 06:21:18 +00:00
{
2010-10-17 17:22:48 +00:00
updateList . Add ( newEpisode ) ;
}
else
{
newList . Add ( newEpisode ) ;
}
2010-10-05 06:21:18 +00:00
2010-10-17 17:22:48 +00:00
successCount + + ;
2010-10-05 06:21:18 +00:00
}
catch ( Exception e )
{
2010-10-17 17:22:48 +00:00
Logger . FatalException ( String . Format ( "An error has occurred while updating episode info for series {0}" , seriesId ) , e ) ;
2010-10-05 06:21:18 +00:00
failCount + + ;
}
}
2010-10-17 17:22:48 +00:00
_sonicRepo . AddMany ( newList ) ;
_sonicRepo . UpdateMany ( updateList ) ;
2010-10-30 02:46:32 +00:00
Logger . Debug ( "Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} " , targetSeries . SeriesName , successCount , failCount ) ;
2010-10-05 06:21:18 +00:00
}
2011-01-29 06:10:22 +00:00
2011-04-10 00:14:51 +00:00
public virtual void RefreshEpisodeInfo ( Season season )
2011-02-10 06:42:46 +00:00
{
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 < Episode > ( ) ;
var newList = new List < Episode > ( ) ;
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
} ;
if ( _sonicRepo . Exists < Episode > ( 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 ) ;
}
2011-04-10 00:14:51 +00:00
public virtual void DeleteEpisode ( int episodeId )
2011-02-18 06:49:23 +00:00
{
_sonicRepo . Delete < Episode > ( episodeId ) ;
}
2011-04-10 00:14:51 +00:00
public virtual void UpdateEpisode ( Episode episode )
2011-02-23 06:23:59 +00:00
{
_sonicRepo . Update ( episode ) ;
}
2010-09-28 05:01:54 +00:00
}
}