2017-10-27 03:21:06 +00:00
|
|
|
using System;
|
2015-05-08 18:50:22 +00:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Net;
|
2017-10-27 03:21:06 +00:00
|
|
|
using System.Net.Sockets;
|
|
|
|
using System.Runtime.InteropServices.ComTypes;
|
2015-05-08 18:50:22 +00:00
|
|
|
using NLog;
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
using CookComputing.XmlRpc;
|
|
|
|
|
|
|
|
namespace NzbDrone.Core.Download.Clients.RTorrent
|
|
|
|
{
|
|
|
|
public interface IRTorrentProxy
|
|
|
|
{
|
|
|
|
string GetVersion(RTorrentSettings settings);
|
|
|
|
List<RTorrentTorrent> GetTorrents(RTorrentSettings settings);
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings);
|
|
|
|
void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings);
|
2015-05-08 18:50:22 +00:00
|
|
|
void RemoveTorrent(string hash, RTorrentSettings settings);
|
2019-06-09 17:54:53 +00:00
|
|
|
void SetTorrentLabel(string hash, string label, RTorrentSettings settings);
|
2015-05-08 18:50:22 +00:00
|
|
|
bool HasHashTorrent(string hash, RTorrentSettings settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface IRTorrent : IXmlRpcProxy
|
|
|
|
{
|
2015-05-26 05:35:06 +00:00
|
|
|
[XmlRpcMethod("d.multicall2")]
|
|
|
|
object[] TorrentMulticall(params string[] parameters);
|
2015-05-08 18:50:22 +00:00
|
|
|
|
2018-08-31 03:04:40 +00:00
|
|
|
[XmlRpcMethod("load.normal")]
|
|
|
|
int LoadNormal(string target, string data, params string[] commands);
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
[XmlRpcMethod("load.start")]
|
|
|
|
int LoadStart(string target, string data, params string[] commands);
|
2015-05-08 18:50:22 +00:00
|
|
|
|
2018-08-31 03:04:40 +00:00
|
|
|
[XmlRpcMethod("load.raw")]
|
|
|
|
int LoadRaw(string target, byte[] data, params string[] commands);
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
[XmlRpcMethod("load.raw_start")]
|
|
|
|
int LoadRawStart(string target, byte[] data, params string[] commands);
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
[XmlRpcMethod("d.erase")]
|
|
|
|
int Remove(string hash);
|
|
|
|
|
2015-05-26 05:35:06 +00:00
|
|
|
[XmlRpcMethod("d.name")]
|
2015-05-08 18:50:22 +00:00
|
|
|
string GetName(string hash);
|
|
|
|
|
2019-06-09 17:54:53 +00:00
|
|
|
[XmlRpcMethod("d.custom1.set")]
|
|
|
|
string SetLabel(string hash, string label);
|
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
[XmlRpcMethod("system.client_version")]
|
|
|
|
string GetVersion();
|
|
|
|
}
|
|
|
|
|
|
|
|
public class RTorrentProxy : IRTorrentProxy
|
|
|
|
{
|
|
|
|
private readonly Logger _logger;
|
|
|
|
|
|
|
|
public RTorrentProxy(Logger logger)
|
|
|
|
{
|
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
public string GetVersion(RTorrentSettings settings)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: system.client_version");
|
|
|
|
|
|
|
|
var client = BuildClient(settings);
|
2017-10-27 03:21:06 +00:00
|
|
|
var version = ExecuteRequest(() => client.GetVersion());
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<RTorrentTorrent> GetTorrents(RTorrentSettings settings)
|
|
|
|
{
|
2015-05-26 05:35:06 +00:00
|
|
|
_logger.Debug("Executing remote method: d.multicall2");
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
var client = BuildClient(settings);
|
2017-10-27 03:21:06 +00:00
|
|
|
var ret = ExecuteRequest(() => client.TorrentMulticall("", "",
|
|
|
|
"d.name=", // string
|
|
|
|
"d.hash=", // string
|
|
|
|
"d.base_path=", // string
|
|
|
|
"d.custom1=", // string (label)
|
|
|
|
"d.size_bytes=", // long
|
|
|
|
"d.left_bytes=", // long
|
|
|
|
"d.down.rate=", // long (in bytes / s)
|
|
|
|
"d.ratio=", // long
|
|
|
|
"d.is_open=", // long
|
|
|
|
"d.is_active=", // long
|
|
|
|
"d.complete=") //long
|
|
|
|
);
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
var items = new List<RTorrentTorrent>();
|
2017-10-27 03:21:06 +00:00
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
foreach (object[] torrent in ret)
|
|
|
|
{
|
2019-06-09 17:54:53 +00:00
|
|
|
var labelDecoded = System.Web.HttpUtility.UrlDecode((string)torrent[3]);
|
2015-10-02 12:35:09 +00:00
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
var item = new RTorrentTorrent();
|
2019-06-09 17:54:53 +00:00
|
|
|
item.Name = (string)torrent[0];
|
|
|
|
item.Hash = (string)torrent[1];
|
|
|
|
item.Path = (string)torrent[2];
|
2015-10-02 12:35:09 +00:00
|
|
|
item.Category = labelDecoded;
|
2019-06-09 17:54:53 +00:00
|
|
|
item.TotalSize = (long)torrent[4];
|
|
|
|
item.RemainingSize = (long)torrent[5];
|
|
|
|
item.DownRate = (long)torrent[6];
|
|
|
|
item.Ratio = (long)torrent[7];
|
|
|
|
item.IsOpen = Convert.ToBoolean((long)torrent[8]);
|
|
|
|
item.IsActive = Convert.ToBoolean((long)torrent[9]);
|
|
|
|
item.IsFinished = Convert.ToBoolean((long)torrent[10]);
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
items.Add(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
public void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
2015-05-08 18:50:22 +00:00
|
|
|
{
|
|
|
|
var client = BuildClient(settings);
|
2018-08-31 03:04:40 +00:00
|
|
|
var response = ExecuteRequest(() =>
|
|
|
|
{
|
|
|
|
if (settings.AddStopped)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: load.normal");
|
|
|
|
return client.LoadNormal("", torrentUrl, GetCommands(label, priority, directory));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: load.start");
|
|
|
|
return client.LoadStart("", torrentUrl, GetCommands(label, priority, directory));
|
|
|
|
}
|
|
|
|
});
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
if (response != 0)
|
|
|
|
{
|
|
|
|
throw new DownloadClientException("Could not add torrent: {0}.", torrentUrl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
public void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
2015-05-08 18:50:22 +00:00
|
|
|
{
|
|
|
|
var client = BuildClient(settings);
|
2018-08-31 03:04:40 +00:00
|
|
|
var response = ExecuteRequest(() =>
|
|
|
|
{
|
|
|
|
if (settings.AddStopped)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: load.raw");
|
|
|
|
return client.LoadRaw("", fileContent, GetCommands(label, priority, directory));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: load.raw_start");
|
|
|
|
return client.LoadRawStart("", fileContent, GetCommands(label, priority, directory));
|
|
|
|
}
|
|
|
|
});
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
if (response != 0)
|
|
|
|
{
|
|
|
|
throw new DownloadClientException("Could not add torrent: {0}.", fileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 17:54:53 +00:00
|
|
|
public void SetTorrentLabel(string hash, string label, RTorrentSettings settings)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: d.custom1.set");
|
|
|
|
|
|
|
|
var client = BuildClient(settings);
|
|
|
|
var response = ExecuteRequest(() => client.SetLabel(hash, label));
|
|
|
|
|
|
|
|
if (response != label)
|
|
|
|
{
|
|
|
|
throw new DownloadClientException("Could not set label to {1} for torrent: {0}.", hash, label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
public void RemoveTorrent(string hash, RTorrentSettings settings)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: d.erase");
|
|
|
|
|
|
|
|
var client = BuildClient(settings);
|
2017-10-27 03:21:06 +00:00
|
|
|
var response = ExecuteRequest(() => client.Remove(hash));
|
2015-05-08 18:50:22 +00:00
|
|
|
|
|
|
|
if (response != 0)
|
|
|
|
{
|
|
|
|
throw new DownloadClientException("Could not remove torrent: {0}.", hash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-27 03:21:06 +00:00
|
|
|
public bool HasHashTorrent(string hash, RTorrentSettings settings)
|
|
|
|
{
|
|
|
|
_logger.Debug("Executing remote method: d.name");
|
|
|
|
|
|
|
|
var client = BuildClient(settings);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var name = ExecuteRequest(() => client.GetName(hash));
|
|
|
|
|
|
|
|
if (name.IsNullOrWhiteSpace())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var metaTorrent = name == (hash + ".meta");
|
|
|
|
|
|
|
|
return !metaTorrent;
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
private string[] GetCommands(string label, RTorrentPriority priority, string directory)
|
2015-05-08 18:50:22 +00:00
|
|
|
{
|
2017-03-11 10:50:19 +00:00
|
|
|
var result = new List<string>();
|
2015-05-08 18:50:22 +00:00
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
if (label.IsNotNullOrWhiteSpace())
|
2015-05-08 18:50:22 +00:00
|
|
|
{
|
2017-03-11 10:50:19 +00:00
|
|
|
result.Add("d.custom1.set=" + label);
|
2015-05-08 18:50:22 +00:00
|
|
|
}
|
2015-07-08 08:11:33 +00:00
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
if (priority != RTorrentPriority.Normal)
|
2016-01-17 13:32:52 +00:00
|
|
|
{
|
2017-03-11 10:50:19 +00:00
|
|
|
result.Add("d.priority.set=" + (int)priority);
|
2016-01-17 13:32:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (directory.IsNotNullOrWhiteSpace())
|
|
|
|
{
|
2017-03-12 10:18:51 +00:00
|
|
|
result.Add("d.directory.set=" + directory);
|
2016-01-17 13:32:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-11 10:50:19 +00:00
|
|
|
return result.ToArray();
|
2016-01-17 13:32:52 +00:00
|
|
|
}
|
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
private IRTorrent BuildClient(RTorrentSettings settings)
|
|
|
|
{
|
2015-05-27 05:01:38 +00:00
|
|
|
var client = XmlRpcProxyGen.Create<IRTorrent>();
|
|
|
|
|
|
|
|
client.Url = string.Format(@"{0}://{1}:{2}/{3}",
|
2015-05-08 18:50:22 +00:00
|
|
|
settings.UseSsl ? "https" : "http",
|
|
|
|
settings.Host,
|
|
|
|
settings.Port,
|
|
|
|
settings.UrlBase);
|
|
|
|
|
2015-05-26 05:35:06 +00:00
|
|
|
client.EnableCompression = true;
|
|
|
|
|
2015-05-08 18:50:22 +00:00
|
|
|
if (!settings.Username.IsNullOrWhiteSpace())
|
|
|
|
{
|
|
|
|
client.Credentials = new NetworkCredential(settings.Username, settings.Password);
|
|
|
|
}
|
|
|
|
|
|
|
|
return client;
|
|
|
|
}
|
2017-10-27 03:21:06 +00:00
|
|
|
|
|
|
|
private T ExecuteRequest<T>(Func<T> task)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return task();
|
|
|
|
}
|
|
|
|
catch (XmlRpcServerException ex)
|
|
|
|
{
|
|
|
|
throw new DownloadClientException("Unable to connect to rTorrent, please check your settings", ex);
|
|
|
|
}
|
|
|
|
catch (WebException ex)
|
|
|
|
{
|
|
|
|
throw new DownloadClientUnavailableException("Unable to connect to rTorrent, please check your settings", ex);
|
|
|
|
}
|
|
|
|
}
|
2015-05-08 18:50:22 +00:00
|
|
|
}
|
|
|
|
}
|