@ -1,5 +1,8 @@
using System ;
using System.Collections.Generic ;
using System.Collections.Immutable ;
using System.Collections.ObjectModel ;
using System.Linq ;
using System.Net ;
using Newtonsoft.Json.Linq ;
using NLog ;
@ -12,15 +15,16 @@ namespace NzbDrone.Core.Download.Clients.Transmission
{
public interface ITransmissionProxy
{
List < TransmissionTorrent > GetTorrents ( TransmissionSettings settings ) ;
IReadOnlyCollection < TransmissionTorrent > GetTorrents ( IReadOnlyCollection < string > hashStrings , TransmissionSettings settings ) ;
void AddTorrentFromUrl ( string torrentUrl , string downloadDirectory , TransmissionSettings settings ) ;
void AddTorrentFromData ( byte [ ] torrentData , string downloadDirectory , TransmissionSettings settings ) ;
void SetTorrentSeedingConfiguration ( string hash , TorrentSeedConfiguration seedConfiguration , TransmissionSettings settings ) ;
TransmissionConfig GetConfig ( TransmissionSettings settings ) ;
string GetProtocolVersion ( TransmissionSettings settings ) ;
string GetClientVersion ( TransmissionSettings settings );
string GetClientVersion ( TransmissionSettings settings , bool force = false );
void RemoveTorrent ( string hash , bool removeData , TransmissionSettings settings ) ;
void MoveTorrentToTopInQueue ( string hashString , TransmissionSettings settings ) ;
void SetTorrentLabels ( string hash , IEnumerable < string > labels , TransmissionSettings settings ) ;
}
public class TransmissionProxy : ITransmissionProxy
@ -28,50 +32,66 @@ namespace NzbDrone.Core.Download.Clients.Transmission
private readonly IHttpClient _httpClient ;
private readonly Logger _logger ;
private ICached < string > _authSessionIDCache ;
private readonly ICached < string > _authSessionIdCache ;
private readonly ICached < string > _versionCache ;
public TransmissionProxy ( ICacheManager cacheManager , IHttpClient httpClient , Logger logger )
{
_httpClient = httpClient ;
_logger = logger ;
_authSessionIDCache = cacheManager . GetCache < string > ( GetType ( ) , "authSessionID" ) ;
_authSessionIdCache = cacheManager . GetCache < string > ( GetType ( ) , "authSessionID" ) ;
_versionCache = cacheManager . GetCache < string > ( GetType ( ) , "versions" ) ;
}
public List < TransmissionTorrent > GetTorrents ( TransmissionSettings settings )
public IReadOnlyCollection < TransmissionTorrent > GetTorrents ( IReadOnlyCollection < string > hashStrings , TransmissionSettings settings )
{
var result = GetTorrentStatus ( settings) ;
var result = GetTorrentStatus ( hashStrings, settings) ;
var torrents = ( ( JArray ) result . Arguments [ "torrents" ] ) . ToObject < List < TransmissionTorrent > > ( ) ;
var torrents = ( ( JArray ) result . Arguments [ "torrents" ] ) . ToObject < ReadOnlyCollection < TransmissionTorrent > > ( ) ;
return torrents ;
}
public void AddTorrentFromUrl ( string torrentUrl , string downloadDirectory , TransmissionSettings settings )
{
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "filename" , torrentUrl ) ;
arguments . Add ( "paused" , settings . AddPaused ) ;
var arguments = new Dictionary < string , object >
{
{ "filename" , torrentUrl } ,
{ "paused" , settings . AddPaused }
} ;
if ( ! downloadDirectory . IsNullOrWhiteSpace ( ) )
{
arguments . Add ( "download-dir" , downloadDirectory ) ;
}
if ( settings . MusicCategory . IsNotNullOrWhiteSpace ( ) )
{
arguments . Add ( "labels" , new List < string > { settings . MusicCategory } ) ;
}
ProcessRequest ( "torrent-add" , arguments , settings ) ;
}
public void AddTorrentFromData ( byte [ ] torrentData , string downloadDirectory , TransmissionSettings settings )
{
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "metainfo" , Convert . ToBase64String ( torrentData ) ) ;
arguments . Add ( "paused" , settings . AddPaused ) ;
var arguments = new Dictionary < string , object >
{
{ "metainfo" , Convert . ToBase64String ( torrentData ) } ,
{ "paused" , settings . AddPaused }
} ;
if ( ! downloadDirectory . IsNullOrWhiteSpace ( ) )
{
arguments . Add ( "download-dir" , downloadDirectory ) ;
}
if ( settings . MusicCategory . IsNotNullOrWhiteSpace ( ) )
{
arguments . Add ( "labels" , new List < string > { settings . MusicCategory } ) ;
}
ProcessRequest ( "torrent-add" , arguments , settings ) ;
}
@ -82,8 +102,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission
return ;
}
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "ids" , new [ ] { hash } ) ;
var arguments = new Dictionary < string , object >
{
{ "ids" , new List < string > { hash } }
} ;
if ( seedConfiguration . Ratio ! = null )
{
@ -97,6 +119,12 @@ namespace NzbDrone.Core.Download.Clients.Transmission
arguments . Add ( "seedIdleMode" , 1 ) ;
}
// Avoid extraneous request if no limits are to be set
if ( arguments . All ( arg = > arg . Key = = "ids" ) )
{
return ;
}
ProcessRequest ( "torrent-set" , arguments , settings ) ;
}
@ -107,11 +135,16 @@ namespace NzbDrone.Core.Download.Clients.Transmission
return config . RpcVersion ;
}
public string GetClientVersion ( TransmissionSettings settings )
public string GetClientVersion ( TransmissionSettings settings , bool force = false )
{
var config = GetConfig ( settings ) ;
var cacheKey = $"version:{$" { GetBaseUrl ( settings ) } : { settings . Password } ".SHA256Hash()}" ;
if ( force )
{
_versionCache . Remove ( cacheKey ) ;
}
return config . Version ;
return _versionCa che. Get ( cacheKey , ( ) = > GetC onfig(settings ) .Version , TimeSpan . FromHours ( 6 ) ) ;
}
public TransmissionConfig GetConfig ( TransmissionSettings settings )
@ -124,21 +157,36 @@ namespace NzbDrone.Core.Download.Clients.Transmission
public void RemoveTorrent ( string hashString , bool removeData , TransmissionSettings settings )
{
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "ids" , new string [ ] { hashString } ) ;
arguments . Add ( "delete-local-data" , removeData ) ;
var arguments = new Dictionary < string , object >
{
{ "ids" , new List < string > { hashString } } ,
{ "delete-local-data" , removeData }
} ;
ProcessRequest ( "torrent-remove" , arguments , settings ) ;
}
public void MoveTorrentToTopInQueue ( string hashString , TransmissionSettings settings )
{
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "ids" , new string [ ] { hashString } ) ;
var arguments = new Dictionary < string , object >
{
{ "ids" , new List < string > { hashString } }
} ;
ProcessRequest ( "queue-move-top" , arguments , settings ) ;
}
public void SetTorrentLabels ( string hash , IEnumerable < string > labels , TransmissionSettings settings )
{
var arguments = new Dictionary < string , object >
{
{ "ids" , new List < string > { hash } } ,
{ "labels" , labels . ToImmutableHashSet ( ) }
} ;
ProcessRequest ( "torrent-set" , arguments , settings ) ;
}
private TransmissionResponse GetSessionVariables ( TransmissionSettings settings )
{
// Retrieve transmission information such as the default download directory, bandwidth throttling and seed ratio.
@ -150,14 +198,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
return ProcessRequest ( "session-stats" , null , settings ) ;
}
private TransmissionResponse GetTorrentStatus ( TransmissionSettings settings )
{
return GetTorrentStatus ( null , settings ) ;
}
private TransmissionResponse GetTorrentStatus ( IEnumerable < string > hashStrings , TransmissionSettings settings )
{
var fields = new string [ ]
var fields = new List < string >
{
"id" ,
"hashString" , // Unique torrent ID. Use this instead of the client id?
@ -177,11 +220,14 @@ namespace NzbDrone.Core.Download.Clients.Transmission
"seedRatioMode" ,
"seedIdleLimit" ,
"seedIdleMode" ,
"fileCount"
"fileCount" ,
"labels"
} ;
var arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "fields" , fields ) ;
var arguments = new Dictionary < string , object >
{
{ "fields" , fields }
} ;
if ( hashStrings ! = null )
{
@ -193,9 +239,14 @@ namespace NzbDrone.Core.Download.Clients.Transmission
return result ;
}
private string GetBaseUrl ( TransmissionSettings settings )
{
return HttpRequestBuilder . BuildBaseUrl ( settings . UseSsl , settings . Host , settings . Port , settings . UrlBase ) ;
}
private HttpRequestBuilder BuildRequest ( TransmissionSettings settings )
{
var requestBuilder = new HttpRequestBuilder ( settings . UseSsl , settings . Host , settings . Port , settings . UrlBase )
var requestBuilder = new HttpRequestBuilder ( GetBaseUrl( settings ) )
. Resource ( "rpc" )
. Accept ( HttpAccept . Json ) ;
@ -210,11 +261,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
{
var authKey = string . Format ( "{0}:{1}" , requestBuilder . BaseUrl , settings . Password ) ;
var sessionId = _authSessionI D Cache. Find ( authKey ) ;
var sessionId = _authSessionI d Cache. Find ( authKey ) ;
if ( sessionId = = null | | reauthenticate )
{
_authSessionI D Cache. Remove ( authKey ) ;
_authSessionI d Cache. Remove ( authKey ) ;
var authLoginRequest = BuildRequest ( settings ) . Build ( ) ;
authLoginRequest . SuppressHttpError = true ;
@ -242,7 +293,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
_logger . Debug ( "Transmission authentication succeeded." ) ;
_authSessionI D Cache. Set ( authKey , sessionId ) ;
_authSessionI d Cache. Set ( authKey , sessionId ) ;
}
requestBuilder . SetHeader ( "X-Transmission-Session-Id" , sessionId ) ;