@ -22,6 +22,8 @@ namespace NzbDrone.Core.Providers
private readonly EpisodeProvider _episodeProvider ;
private static readonly Logger Logger = LogManager . GetCurrentClassLogger ( ) ;
private static readonly List < PostDownloadInfoModel > InfoList = new List < PostDownloadInfoModel > ( ) ;
[Inject]
public PostDownloadProvider ( ConfigProvider configProvider , DiskProvider diskProvider ,
DiskScanProvider diskScanProvider , SeriesProvider seriesProvider ,
@ -39,7 +41,7 @@ namespace NzbDrone.Core.Providers
}
public virtual void S tart ( ProgressNotification notification )
public virtual void S canDropFolder ( ProgressNotification notification )
{
var dropFolder = _configProvider . SabDropDirectory ;
@ -55,55 +57,47 @@ namespace NzbDrone.Core.Providers
return ;
}
ProcessDropFolder ( dropFolder ) ;
}
public virtual void ProcessDropFolder ( string dropFolder )
{
foreach ( var subfolder in _diskProvider . GetDirectories ( dropFolder ) )
{
try
{
var subfolderInfo = new DirectoryInfo ( subfolder ) ;
if ( subfolderInfo . Name . StartsWith ( "_UNPACK_" , StringComparison . CurrentCultureIgnoreCase ))
if ( subfolderInfo . Name . StartsWith ( "_UNPACK_" ))
{
_episodeProvider. SetPostDownloadStatus ( subfolderInfo . Name . Substring ( 8 ) , PostDownloadStatusType . Unpacking ) ;
ProcessFailedOrUnpackingDownload( subfolderInfo , PostDownloadStatusType . Unpacking ) ;
Logger . Debug ( "Folder [{0}] is still being unpacked. skipping." , subfolder ) ;
continue ;
}
if ( subfolderInfo . Name . StartsWith ( "_FAILED_" , StringComparison . CurrentCultureIgnoreCase ))
if ( subfolderInfo . Name . StartsWith ( "_FAILED_" ))
{
_episodeProvider. SetPostDownloadStatus ( subfolderInfo . Name . Substring ( 8 ) , PostDownloadStatusType . Failed ) ;
ProcessFailedOrUnpackingDownload( subfolderInfo , PostDownloadStatusType . Failed ) ;
Logger . Debug ( "Folder [{0}] is marked as failed. skipping." , subfolder ) ;
continue ;
}
if ( subfolderInfo . Name . StartsWith ( "_NzbDrone_" , StringComparison . CurrentCultureIgnoreCase ))
if ( subfolderInfo . Name . StartsWith ( "_NzbDrone_" ))
{
Logger . Debug ( "Folder [{0}] is marked as already processedby NzbDrone. skipping." , subfolder ) ;
continue ;
}
if ( subfolderInfo . Name . StartsWith ( "_NzbDrone_InvalidSeries_" ) )
ReProcessDownload ( new PostDownloadInfoModel { Name = subfolderInfo . FullName , Status = PostDownloadStatusType . InvalidSeries } ) ;
//Parse the Folder name
var seriesName = Parser . ParseSeriesName ( subfolderInfo . Name ) ;
var series = _seriesProvider . FindSeries ( seriesName ) ;
else if ( subfolderInfo . Name . StartsWith ( "_NzbDrone_ParseError_" ) )
ReProcessDownload ( new PostDownloadInfoModel { Name = subfolderInfo . FullName , Status = PostDownloadStatusType . ParseError } ) ;
if ( series = = null )
{
Logger . Warn ( "Unable to Import new download [{0}], series doesn't exist in database." , subfolder ) ;
else
ReProcessDownload ( new PostDownloadInfoModel { Name = subfolderInfo . FullName , Status = PostDownloadStatusType . Unknown } ) ;
//Rename the Directory so it's not processed again.
_diskProvider . MoveDirectory ( subfolderInfo . FullName , Path . Combine ( subfolderInfo . Parent . FullName , "_NzbDrone_" + subfolderInfo . Name ) ) ;
continue ;
}
var importedFiles = _diskScanProvider . Scan ( series , subfolder ) ;
importedFiles . ForEach ( file = > _diskScanProvider . MoveEpisodeFile ( file , true ) ) ;
//Delete the folder only if folder is small enough
if ( _diskProvider . GetDirectorySize ( subfolder ) < 10. Megabytes ( ) )
_diskProvider . DeleteFolder ( subfolder , true ) ;
//Otherwise rename the folder to say it was already processed once by NzbDrone so it will not be continually processed
else
_diskProvider . MoveDirectory ( subfolderInfo . FullName , Path . Combine ( subfolderInfo . Parent . FullName , "_NzbDrone_" + subfolderInfo . Name ) ) ;
//Process a successful download
ProcessDownload ( subfolderInfo ) ;
}
catch ( Exception e )
@ -112,5 +106,117 @@ namespace NzbDrone.Core.Providers
}
}
}
public virtual void ProcessDownload ( DirectoryInfo subfolderInfo )
{
//Parse the Folder name
var seriesName = Parser . ParseSeriesName ( subfolderInfo . Name ) ;
var series = _seriesProvider . FindSeries ( seriesName ) ;
if ( series = = null )
{
Logger . Warn ( "Unable to Import new download [{0}], series doesn't exist in database." , subfolderInfo . FullName ) ;
//Rename the Directory so it's not processed again.
_diskProvider . MoveDirectory ( subfolderInfo . FullName ,
Path . Combine ( subfolderInfo . Parent . FullName ,
"_NzbDrone_InvalidSeries_" + subfolderInfo . Name ) ) ;
return ;
}
var importedFiles = _diskScanProvider . Scan ( series , subfolderInfo . FullName ) ;
importedFiles . ForEach ( file = > _diskScanProvider . MoveEpisodeFile ( file , true ) ) ;
//Delete the folder only if folder is small enough
if ( _diskProvider . GetDirectorySize ( subfolderInfo . FullName ) < 10. Megabytes ( ) )
_diskProvider . DeleteFolder ( subfolderInfo . FullName , true ) ;
//Otherwise rename the folder to say it was already processed once by NzbDrone
else
{
if ( importedFiles . Count = = 0 )
{
Logger . Warn ( "Unable to Import new download [{0}], unable to parse episode file(s)." , subfolderInfo . FullName ) ;
_diskProvider . MoveDirectory ( subfolderInfo . FullName ,
Path . Combine ( subfolderInfo . Parent . FullName ,
"_NzbDrone_ParseError_" + subfolderInfo . Name ) ) ;
}
//Unknown Error Importing (Possibly a lesser quality than episode currently on disk)
else
{
Logger . Warn ( "Unable to Import new download [{0}]." , subfolderInfo . FullName ) ;
_diskProvider . MoveDirectory ( subfolderInfo . FullName ,
Path . Combine ( subfolderInfo . Parent . FullName ,
"_NzbDrone_" + subfolderInfo . Name ) ) ;
}
}
}
public virtual void ProcessFailedOrUnpackingDownload ( DirectoryInfo directoryInfo , PostDownloadStatusType postDownloadStatus )
{
//Check to see if its already in InfoList, if it is, check if enough time has passed to process
if ( InfoList . Any ( i = > i . Name = = directoryInfo . FullName ) )
{
var model = InfoList . Single ( i = > i . Name = = directoryInfo . FullName ) ;
//Process if 30 minutes has passed
if ( model . Added > DateTime . Now . AddMinutes ( 30 ) )
ReProcessDownload ( model ) ;
//If everything processed successfully up until now, remove it from InfoList
InfoList . Remove ( model ) ;
return ;
}
//Add to InfoList for possible later processing
InfoList . Add ( new PostDownloadInfoModel { Name = directoryInfo . FullName ,
Added = DateTime . Now ,
Status = postDownloadStatus
} ) ;
//Remove the first 8 characters of the folder name (removes _UNPACK_ or _FAILED_) before processing
var parseResult = Parser . ParseTitle ( directoryInfo . Name . Substring ( 8 ) ) ;
parseResult . Series = _seriesProvider . FindSeries ( parseResult . CleanTitle ) ;
var episodeIds = _episodeProvider . GetEpisodesByParseResult ( parseResult ) . Select ( e = > e . EpisodeId ) ;
_episodeProvider . SetPostDownloadStatus ( episodeIds , postDownloadStatus ) ;
}
public virtual void ReProcessDownload ( PostDownloadInfoModel model )
{
var directoryInfo = new DirectoryInfo ( model . Name ) ;
var newName = Path . Combine ( directoryInfo . Parent . FullName , directoryInfo . Name . Substring ( GetPrefixLength ( model . Status ) ) ) ;
_diskProvider . MoveDirectory ( directoryInfo . FullName , newName ) ;
directoryInfo = new DirectoryInfo ( newName ) ;
ProcessDownload ( directoryInfo ) ;
}
public int GetPrefixLength ( PostDownloadStatusType postDownloadStatus )
{
//_UNPACK_ & _FAILED_ have a length of 8
if ( postDownloadStatus = = PostDownloadStatusType . Unpacking | | postDownloadStatus = = PostDownloadStatusType . Failed )
return 8 ;
//_NzbDrone_InvalidSeries_ - Length = 24
if ( postDownloadStatus = = PostDownloadStatusType . InvalidSeries )
return 24 ;
//_NzbDrone_ParseError_ - Length =
if ( postDownloadStatus = = PostDownloadStatusType . ParseError )
return 21 ;
//_NzbDrone_ - Length = 10
if ( postDownloadStatus = = PostDownloadStatusType . Unknown )
return 10 ;
//Default to zero
return 0 ;
}
}
}