2017-09-26 02:31:52 +00:00
using System ;
2014-05-13 17:57:46 +00:00
using System.Collections.Generic ;
2020-01-03 12:49:24 +00:00
using System.Linq ;
using System.Net ;
using FluentValidation.Results ;
using NLog ;
2014-05-13 17:57:46 +00:00
using NzbDrone.Common.Disk ;
2020-01-03 12:49:24 +00:00
using NzbDrone.Common.Extensions ;
2014-05-13 17:57:46 +00:00
using NzbDrone.Common.Http ;
2020-01-03 12:49:24 +00:00
using NzbDrone.Core.Configuration ;
2014-05-13 17:57:46 +00:00
using NzbDrone.Core.MediaFiles.TorrentInfo ;
using NzbDrone.Core.Parser.Model ;
using NzbDrone.Core.RemotePathMappings ;
2020-01-03 12:49:24 +00:00
using NzbDrone.Core.Validation ;
2014-05-13 17:57:46 +00:00
namespace NzbDrone.Core.Download.Clients.Deluge
{
public class Deluge : TorrentClientBase < DelugeSettings >
{
private readonly IDelugeProxy _proxy ;
public Deluge ( IDelugeProxy proxy ,
ITorrentFileInfoReader torrentFileInfoReader ,
IHttpClient httpClient ,
IConfigService configService ,
IDiskProvider diskProvider ,
IRemotePathMappingService remotePathMappingService ,
Logger logger )
2014-12-23 01:17:48 +00:00
: base ( torrentFileInfoReader , httpClient , configService , diskProvider , remotePathMappingService , logger )
2014-05-13 17:57:46 +00:00
{
_proxy = proxy ;
}
2019-06-09 17:54:53 +00:00
public override void MarkItemAsImported ( DownloadClientItem downloadClientItem )
{
// set post-import category
if ( Settings . MusicImportedCategory . IsNotNullOrWhiteSpace ( ) & &
Settings . MusicImportedCategory ! = Settings . MusicCategory )
{
try
{
_proxy . SetTorrentLabel ( downloadClientItem . DownloadId . ToLower ( ) , Settings . MusicImportedCategory , Settings ) ;
}
catch ( DownloadClientUnavailableException )
{
_logger . Warn ( "Failed to set torrent post-import label \"{0}\" for {1} in Deluge. Does the label exist?" ,
2020-01-03 12:49:24 +00:00
Settings . MusicImportedCategory ,
downloadClientItem . Title ) ;
2019-06-09 17:54:53 +00:00
}
}
}
2017-08-14 02:58:42 +00:00
protected override string AddFromMagnetLink ( RemoteAlbum remoteAlbum , string hash , string magnetLink )
2014-05-13 17:57:46 +00:00
{
var actualHash = _proxy . AddTorrentFromMagnet ( magnetLink , Settings ) ;
2018-03-15 01:39:37 +00:00
if ( actualHash . IsNullOrWhiteSpace ( ) )
{
throw new DownloadClientException ( "Deluge failed to add magnet " + magnetLink ) ;
}
2019-06-09 17:54:53 +00:00
_proxy . SetTorrentSeedingConfiguration ( actualHash , remoteAlbum . SeedConfiguration , Settings ) ;
if ( Settings . MusicCategory . IsNotNullOrWhiteSpace ( ) )
2014-05-13 17:57:46 +00:00
{
2019-06-09 17:54:53 +00:00
_proxy . SetTorrentLabel ( actualHash , Settings . MusicCategory , Settings ) ;
2014-05-13 17:57:46 +00:00
}
2017-08-14 02:58:42 +00:00
var isRecentAlbum = remoteAlbum . IsRecentAlbum ( ) ;
2014-05-13 17:57:46 +00:00
2020-01-03 12:49:24 +00:00
if ( ( isRecentAlbum & & Settings . RecentTvPriority = = ( int ) DelugePriority . First ) | |
( ! isRecentAlbum & & Settings . OlderTvPriority = = ( int ) DelugePriority . First ) )
2014-05-13 17:57:46 +00:00
{
_proxy . MoveTorrentToTopInQueue ( actualHash , Settings ) ;
}
return actualHash . ToUpper ( ) ;
}
2017-08-14 02:58:42 +00:00
protected override string AddFromTorrentFile ( RemoteAlbum remoteAlbum , string hash , string filename , byte [ ] fileContent )
2014-05-13 17:57:46 +00:00
{
var actualHash = _proxy . AddTorrentFromFile ( filename , fileContent , Settings ) ;
2017-10-29 02:57:03 +00:00
if ( actualHash . IsNullOrWhiteSpace ( ) )
{
throw new DownloadClientException ( "Deluge failed to add torrent " + filename ) ;
}
2018-06-02 01:59:54 +00:00
_proxy . SetTorrentSeedingConfiguration ( actualHash , remoteAlbum . SeedConfiguration , Settings ) ;
2019-06-09 17:54:53 +00:00
if ( Settings . MusicCategory . IsNotNullOrWhiteSpace ( ) )
2014-05-13 17:57:46 +00:00
{
2019-06-09 17:54:53 +00:00
_proxy . SetTorrentLabel ( actualHash , Settings . MusicCategory , Settings ) ;
2014-05-13 17:57:46 +00:00
}
2018-01-14 20:01:31 +00:00
var isRecentAlbum = remoteAlbum . IsRecentAlbum ( ) ;
2014-05-13 17:57:46 +00:00
2020-01-03 12:49:24 +00:00
if ( ( isRecentAlbum & & Settings . RecentTvPriority = = ( int ) DelugePriority . First ) | |
( ! isRecentAlbum & & Settings . OlderTvPriority = = ( int ) DelugePriority . First ) )
2014-05-13 17:57:46 +00:00
{
_proxy . MoveTorrentToTopInQueue ( actualHash , Settings ) ;
}
return actualHash . ToUpper ( ) ;
}
2016-12-09 06:54:15 +00:00
public override string Name = > "Deluge" ;
2015-04-25 16:22:53 +00:00
2014-05-13 17:57:46 +00:00
public override IEnumerable < DownloadClientItem > GetItems ( )
{
IEnumerable < DelugeTorrent > torrents ;
2019-06-09 17:54:53 +00:00
if ( Settings . MusicCategory . IsNotNullOrWhiteSpace ( ) )
2014-05-13 17:57:46 +00:00
{
2018-02-16 02:52:15 +00:00
torrents = _proxy . GetTorrentsByLabel ( Settings . MusicCategory , Settings ) ;
2014-05-13 17:57:46 +00:00
}
2017-10-27 03:21:06 +00:00
else
2014-05-13 17:57:46 +00:00
{
2017-10-27 03:21:06 +00:00
torrents = _proxy . GetTorrents ( Settings ) ;
2014-05-13 17:57:46 +00:00
}
var items = new List < DownloadClientItem > ( ) ;
foreach ( var torrent in torrents )
{
2020-01-03 12:49:24 +00:00
if ( torrent . Hash = = null )
{
continue ;
}
2018-07-18 01:04:10 +00:00
2014-05-13 17:57:46 +00:00
var item = new DownloadClientItem ( ) ;
2014-12-19 00:26:42 +00:00
item . DownloadId = torrent . Hash . ToUpper ( ) ;
2014-05-13 17:57:46 +00:00
item . Title = torrent . Name ;
2018-02-16 02:52:15 +00:00
item . Category = Settings . MusicCategory ;
2014-05-13 17:57:46 +00:00
2020-11-16 21:34:49 +00:00
item . DownloadClientInfo = DownloadClientItemClientInfo . FromDownloadClient ( this ) ;
2014-05-13 17:57:46 +00:00
2014-10-12 22:00:03 +00:00
var outputPath = _remotePathMappingService . RemapRemoteToLocal ( Settings . Host , new OsPath ( torrent . DownloadPath ) ) ;
item . OutputPath = outputPath + torrent . Name ;
2014-05-13 17:57:46 +00:00
item . RemainingSize = torrent . Size - torrent . BytesDownloaded ;
2018-06-02 01:59:54 +00:00
item . SeedRatio = torrent . Ratio ;
2019-06-09 17:54:53 +00:00
2017-10-30 01:43:23 +00:00
try
{
item . RemainingTime = TimeSpan . FromSeconds ( torrent . Eta ) ;
}
catch ( OverflowException ex )
{
_logger . Debug ( ex , "ETA for {0} is too long: {1}" , torrent . Name , torrent . Eta ) ;
item . RemainingTime = TimeSpan . MaxValue ;
}
2014-05-13 17:57:46 +00:00
item . TotalSize = torrent . Size ;
if ( torrent . State = = DelugeTorrentStatus . Error )
{
2014-11-22 02:10:24 +00:00
item . Status = DownloadItemStatus . Warning ;
item . Message = "Deluge is reporting an error" ;
2014-05-13 17:57:46 +00:00
}
else if ( torrent . IsFinished & & torrent . State ! = DelugeTorrentStatus . Checking )
{
item . Status = DownloadItemStatus . Completed ;
}
else if ( torrent . State = = DelugeTorrentStatus . Queued )
{
item . Status = DownloadItemStatus . Queued ;
}
else if ( torrent . State = = DelugeTorrentStatus . Paused )
{
item . Status = DownloadItemStatus . Paused ;
}
else
{
item . Status = DownloadItemStatus . Downloading ;
}
2018-06-02 01:59:54 +00:00
// Here we detect if Deluge is managing the torrent and whether the seed criteria has been met.
// This allows drone to delete the torrent as appropriate.
item . CanMoveFiles = item . CanBeRemoved =
torrent . IsAutoManaged & &
torrent . StopAtRatio & &
torrent . Ratio > = torrent . StopRatio & &
torrent . State = = DelugeTorrentStatus . Paused ;
2014-05-13 17:57:46 +00:00
items . Add ( item ) ;
}
return items ;
}
2014-12-23 01:17:48 +00:00
public override void RemoveItem ( string downloadId , bool deleteData )
2014-05-13 17:57:46 +00:00
{
2014-12-23 01:17:48 +00:00
_proxy . RemoveTorrent ( downloadId . ToLower ( ) , deleteData , Settings ) ;
2014-05-13 17:57:46 +00:00
}
2017-10-08 03:54:13 +00:00
public override DownloadClientInfo GetStatus ( )
2014-05-13 17:57:46 +00:00
{
var config = _proxy . GetConfig ( Settings ) ;
2014-10-12 22:00:03 +00:00
var destDir = new OsPath ( config . GetValueOrDefault ( "download_location" ) as string ) ;
2014-05-13 17:57:46 +00:00
if ( config . GetValueOrDefault ( "move_completed" , false ) . ToString ( ) = = "True" )
{
2014-10-12 22:00:03 +00:00
destDir = new OsPath ( config . GetValueOrDefault ( "move_completed_path" ) as string ) ;
2014-05-13 17:57:46 +00:00
}
2017-10-08 03:54:13 +00:00
var status = new DownloadClientInfo
2014-05-13 17:57:46 +00:00
{
IsLocalhost = Settings . Host = = "127.0.0.1" | | Settings . Host = = "localhost"
} ;
2014-10-12 22:00:03 +00:00
if ( ! destDir . IsEmpty )
2014-05-13 17:57:46 +00:00
{
2014-10-12 22:00:03 +00:00
status . OutputRootFolders = new List < OsPath > { _remotePathMappingService . RemapRemoteToLocal ( Settings . Host , destDir ) } ;
2014-05-13 17:57:46 +00:00
}
2019-06-09 17:54:53 +00:00
2014-05-13 17:57:46 +00:00
return status ;
}
protected override void Test ( List < ValidationFailure > failures )
{
failures . AddIfNotNull ( TestConnection ( ) ) ;
2020-01-03 12:49:24 +00:00
if ( failures . HasErrors ( ) )
{
return ;
}
2014-05-13 17:57:46 +00:00
failures . AddIfNotNull ( TestCategory ( ) ) ;
failures . AddIfNotNull ( TestGetTorrents ( ) ) ;
}
private ValidationFailure TestConnection ( )
{
try
{
_proxy . GetVersion ( Settings ) ;
}
catch ( DownloadClientAuthenticationException ex )
{
2019-03-13 23:10:58 +00:00
_logger . Error ( ex , "Unable to authenticate" ) ;
2014-05-13 17:57:46 +00:00
return new NzbDroneValidationFailure ( "Password" , "Authentication failed" ) ;
}
catch ( WebException ex )
{
2017-10-08 05:14:26 +00:00
_logger . Error ( ex , "Unable to test connection" ) ;
2014-12-07 07:23:11 +00:00
switch ( ex . Status )
2014-05-13 17:57:46 +00:00
{
2014-12-07 07:23:11 +00:00
case WebExceptionStatus . ConnectFailure :
return new NzbDroneValidationFailure ( "Host" , "Unable to connect" )
{
DetailedDescription = "Please verify the hostname and port."
} ;
case WebExceptionStatus . ConnectionClosed :
return new NzbDroneValidationFailure ( "UseSsl" , "Verify SSL settings" )
{
2019-06-09 17:54:53 +00:00
DetailedDescription = "Please verify your SSL configuration on both Deluge and Lidarr."
2014-12-07 07:23:11 +00:00
} ;
case WebExceptionStatus . SecureChannelFailure :
return new NzbDroneValidationFailure ( "UseSsl" , "Unable to connect through SSL" )
{
2019-06-09 17:54:53 +00:00
DetailedDescription = "Lidarr is unable to connect to Deluge using SSL. This problem could be computer related. Please try to configure both drone and Deluge to not use SSL."
2014-12-07 07:23:11 +00:00
} ;
default :
2015-10-03 17:45:26 +00:00
return new NzbDroneValidationFailure ( string . Empty , "Unknown exception: " + ex . Message ) ;
2014-05-13 17:57:46 +00:00
}
}
catch ( Exception ex )
{
2017-10-08 05:14:26 +00:00
_logger . Error ( ex , "Failed to test connection" ) ;
2015-10-03 17:45:26 +00:00
return new NzbDroneValidationFailure ( string . Empty , "Unknown exception: " + ex . Message ) ;
2014-05-13 17:57:46 +00:00
}
return null ;
}
private ValidationFailure TestCategory ( )
{
2019-06-09 17:54:53 +00:00
if ( Settings . MusicCategory . IsNullOrWhiteSpace ( ) & & Settings . MusicImportedCategory . IsNullOrWhiteSpace ( ) )
2014-05-13 17:57:46 +00:00
{
return null ;
}
2014-12-23 01:17:48 +00:00
2014-05-13 17:57:46 +00:00
var enabledPlugins = _proxy . GetEnabledPlugins ( Settings ) ;
if ( ! enabledPlugins . Contains ( "Label" ) )
{
2018-07-18 01:16:39 +00:00
return new NzbDroneValidationFailure ( "MusicCategory" , "Label plugin not activated" )
2014-05-13 17:57:46 +00:00
{
DetailedDescription = "You must have the Label plugin enabled in Deluge to use categories."
} ;
}
var labels = _proxy . GetAvailableLabels ( Settings ) ;
2019-06-09 17:54:53 +00:00
if ( Settings . MusicCategory . IsNotNullOrWhiteSpace ( ) & & ! labels . Contains ( Settings . MusicCategory ) )
2014-05-13 17:57:46 +00:00
{
2018-02-16 02:52:15 +00:00
_proxy . AddLabel ( Settings . MusicCategory , Settings ) ;
2014-05-13 17:57:46 +00:00
labels = _proxy . GetAvailableLabels ( Settings ) ;
2018-02-16 02:52:15 +00:00
if ( ! labels . Contains ( Settings . MusicCategory ) )
2014-05-13 17:57:46 +00:00
{
2018-07-18 01:16:39 +00:00
return new NzbDroneValidationFailure ( "MusicCategory" , "Configuration of label failed" )
2014-05-13 17:57:46 +00:00
{
2019-06-09 17:54:53 +00:00
DetailedDescription = "Lidarr was unable to add the label to Deluge."
} ;
}
}
if ( Settings . MusicImportedCategory . IsNotNullOrWhiteSpace ( ) & & ! labels . Contains ( Settings . MusicImportedCategory ) )
{
_proxy . AddLabel ( Settings . MusicImportedCategory , Settings ) ;
labels = _proxy . GetAvailableLabels ( Settings ) ;
if ( ! labels . Contains ( Settings . MusicImportedCategory ) )
{
return new NzbDroneValidationFailure ( "MusicImportedCategory" , "Configuration of label failed" )
{
DetailedDescription = "Lidarr was unable to add the label to Deluge."
2014-05-13 17:57:46 +00:00
} ;
}
}
return null ;
}
private ValidationFailure TestGetTorrents ( )
{
try
{
_proxy . GetTorrents ( Settings ) ;
}
catch ( Exception ex )
{
2017-10-08 05:14:26 +00:00
_logger . Error ( ex , "Unable to get torrents" ) ;
2015-10-03 17:45:26 +00:00
return new NzbDroneValidationFailure ( string . Empty , "Failed to get the list of torrents: " + ex . Message ) ;
2014-05-13 17:57:46 +00:00
}
return null ;
}
}
}