mirror of https://github.com/Radarr/Radarr
Patch/onedr0p 3 14 17 (#1171)
* Upstream patch for rtorrent * Whoops goes PTP
This commit is contained in:
parent
1ccfde334f
commit
18fcda5fd6
|
@ -25,26 +25,26 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
|
|||
};
|
||||
|
||||
_downloading = new RTorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
IsFinished = false,
|
||||
IsOpen = true,
|
||||
IsActive = true,
|
||||
Name = _title,
|
||||
TotalSize = 1000,
|
||||
RemainingSize = 500,
|
||||
Path = "somepath"
|
||||
};
|
||||
{
|
||||
Hash = "HASH",
|
||||
IsFinished = false,
|
||||
IsOpen = true,
|
||||
IsActive = true,
|
||||
Name = _title,
|
||||
TotalSize = 1000,
|
||||
RemainingSize = 500,
|
||||
Path = "somepath"
|
||||
};
|
||||
|
||||
_completed = new RTorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
IsFinished = true,
|
||||
Name = _title,
|
||||
TotalSize = 1000,
|
||||
RemainingSize = 0,
|
||||
Path = "somepath"
|
||||
};
|
||||
{
|
||||
Hash = "HASH",
|
||||
IsFinished = true,
|
||||
Name = _title,
|
||||
TotalSize = 1000,
|
||||
RemainingSize = 0,
|
||||
Path = "somepath"
|
||||
};
|
||||
|
||||
Mocker.GetMock<ITorrentFileInfoReader>()
|
||||
.Setup(s => s.GetHashFromTorrentFile(It.IsAny<byte[]>()))
|
||||
|
@ -54,11 +54,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
|
|||
protected void GivenSuccessfulDownload()
|
||||
{
|
||||
Mocker.GetMock<IRTorrentProxy>()
|
||||
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
|
||||
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
|
||||
.Callback(PrepareClientToReturnCompletedItem);
|
||||
|
||||
Mocker.GetMock<IRTorrentProxy>()
|
||||
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<RTorrentSettings>()))
|
||||
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
|
||||
.Callback(PrepareClientToReturnCompletedItem);
|
||||
|
||||
|
||||
|
@ -116,11 +116,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
|
|||
{
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
var remoteEpisode = CreateRemoteMovie();
|
||||
|
||||
var id = Subject.Download(remoteMovie);
|
||||
var id = Subject.Download(remoteEpisode);
|
||||
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,52 +49,36 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
|
||||
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
|
||||
{
|
||||
_proxy.AddTorrentFromUrl(magnetLink, Settings);
|
||||
_proxy.AddTorrentFromUrl(magnetLink, Settings.MovieCategory, RTorrentPriority.Normal, Settings.MovieDirectory, Settings);
|
||||
|
||||
// Download the magnet to the appropriate directory.
|
||||
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
|
||||
SetDownloadDirectory(hash);
|
||||
_proxy.StartTorrent(hash, Settings);
|
||||
|
||||
// Wait for the magnet to be resolved.
|
||||
var tries = 10;
|
||||
var retryDelay = 500;
|
||||
if (WaitForTorrent(hash, tries, retryDelay))
|
||||
{
|
||||
_logger.Info("Resolved magnet for {0}", remoteMovie.Movie.CleanTitle);
|
||||
SetDownloadDirectory(hash);
|
||||
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
|
||||
_proxy.StartTorrent(hash, Settings);
|
||||
return hash;
|
||||
}
|
||||
else
|
||||
|
||||
// Wait a bit for the magnet to be resolved.
|
||||
if (!WaitForTorrent(hash, tries, retryDelay))
|
||||
{
|
||||
_logger.Warn("rTorrent could not resolve magnet within {0} seconds, download may remain stuck: {1}.", tries * retryDelay / 1000, magnetLink);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
|
||||
{
|
||||
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
|
||||
_proxy.AddTorrentFromFile(filename, fileContent, Settings.MovieCategory, RTorrentPriority.Normal, Settings.MovieDirectory, Settings);
|
||||
|
||||
var tries = 5;
|
||||
var retryDelay = 200;
|
||||
if (WaitForTorrent(hash, tries, retryDelay))
|
||||
var tries = 10;
|
||||
var retryDelay = 500;
|
||||
if (!WaitForTorrent(hash, tries, retryDelay))
|
||||
{
|
||||
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
|
||||
SetDownloadDirectory(hash);
|
||||
_proxy.StartTorrent(hash, Settings);
|
||||
return hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("rTorrent could not add file");
|
||||
_logger.Debug("rTorrent didn't add the torrent within {0} seconds: {1}.", tries * retryDelay / 1000, filename);
|
||||
|
||||
RemoveItem(hash, true);
|
||||
throw new ReleaseDownloadException(remoteMovie.Release, "Downloading torrent failed");
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string Name => "rTorrent";
|
||||
|
@ -233,14 +217,6 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
return result.Errors.First();
|
||||
}
|
||||
|
||||
private void SetDownloadDirectory(string hash)
|
||||
{
|
||||
if (Settings.MovieDirectory.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
_proxy.SetTorrentDownloadDirectory(hash, Settings.MovieDirectory, Settings);
|
||||
}
|
||||
}
|
||||
|
||||
private bool WaitForTorrent(string hash, int tries, int retryDelay)
|
||||
{
|
||||
for (var i = 0; i < tries; i++)
|
||||
|
|
|
@ -13,15 +13,10 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
string GetVersion(RTorrentSettings settings);
|
||||
List<RTorrentTorrent> GetTorrents(RTorrentSettings settings);
|
||||
|
||||
void AddTorrentFromUrl(string torrentUrl, RTorrentSettings settings);
|
||||
void AddTorrentFromFile(string fileName, byte[] fileContent, RTorrentSettings settings);
|
||||
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);
|
||||
void RemoveTorrent(string hash, RTorrentSettings settings);
|
||||
void SetTorrentPriority(string hash, RTorrentPriority priority, RTorrentSettings settings);
|
||||
void SetTorrentLabel(string hash, string label, RTorrentSettings settings);
|
||||
void SetTorrentDownloadDirectory(string hash, string directory, RTorrentSettings settings);
|
||||
bool HasHashTorrent(string hash, RTorrentSettings settings);
|
||||
void StartTorrent(string hash, RTorrentSettings settings);
|
||||
void SetDeferredMagnetProperties(string hash, string category, string directory, RTorrentPriority priority, RTorrentSettings settings);
|
||||
}
|
||||
|
||||
public interface IRTorrent : IXmlRpcProxy
|
||||
|
@ -29,35 +24,20 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
[XmlRpcMethod("d.multicall2")]
|
||||
object[] TorrentMulticall(params string[] parameters);
|
||||
|
||||
[XmlRpcMethod("load.normal")]
|
||||
int LoadUrl(string target, string data);
|
||||
[XmlRpcMethod("load.start")]
|
||||
int LoadStart(string target, string data, params string[] commands);
|
||||
|
||||
[XmlRpcMethod("load.raw")]
|
||||
int LoadBinary(string target, byte[] data);
|
||||
[XmlRpcMethod("load.raw_start")]
|
||||
int LoadRawStart(string target, byte[] data, params string[] commands);
|
||||
|
||||
[XmlRpcMethod("d.erase")]
|
||||
int Remove(string hash);
|
||||
|
||||
[XmlRpcMethod("d.custom1.set")]
|
||||
string SetLabel(string hash, string label);
|
||||
|
||||
[XmlRpcMethod("d.priority.set")]
|
||||
int SetPriority(string hash, long priority);
|
||||
|
||||
[XmlRpcMethod("d.directory.set")]
|
||||
int SetDirectory(string hash, string directory);
|
||||
|
||||
[XmlRpcMethod("method.set_key")]
|
||||
int SetKey(string target, string key, string cmd_key, string value);
|
||||
|
||||
[XmlRpcMethod("d.name")]
|
||||
string GetName(string hash);
|
||||
|
||||
[XmlRpcMethod("system.client_version")]
|
||||
string GetVersion();
|
||||
|
||||
[XmlRpcMethod("system.multicall")]
|
||||
object[] SystemMulticall(object[] parameters);
|
||||
}
|
||||
|
||||
public class RTorrentProxy : IRTorrentProxy
|
||||
|
@ -101,20 +81,20 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
var items = new List<RTorrentTorrent>();
|
||||
foreach (object[] torrent in ret)
|
||||
{
|
||||
var labelDecoded = System.Web.HttpUtility.UrlDecode((string) torrent[3]);
|
||||
var labelDecoded = System.Web.HttpUtility.UrlDecode((string)torrent[3]);
|
||||
|
||||
var item = new RTorrentTorrent();
|
||||
item.Name = (string) torrent[0];
|
||||
item.Hash = (string) torrent[1];
|
||||
item.Path = (string) torrent[2];
|
||||
item.Name = (string)torrent[0];
|
||||
item.Hash = (string)torrent[1];
|
||||
item.Path = (string)torrent[2];
|
||||
item.Category = labelDecoded;
|
||||
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]);
|
||||
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]);
|
||||
|
||||
items.Add(item);
|
||||
}
|
||||
|
@ -122,26 +102,26 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
return items;
|
||||
}
|
||||
|
||||
public void AddTorrentFromUrl(string torrentUrl, RTorrentSettings settings)
|
||||
public void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: load.normal");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.LoadUrl("", torrentUrl);
|
||||
var response = client.LoadStart("", torrentUrl, GetCommands(label, priority, directory));
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could not add torrent: {0}.", torrentUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTorrentFromFile(string fileName, byte[] fileContent, RTorrentSettings settings)
|
||||
public void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: load.raw");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.LoadBinary("", fileContent);
|
||||
var response = client.LoadRawStart("", fileContent, GetCommands(label, priority, directory));
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could not add torrent: {0}.", fileName);
|
||||
|
@ -161,94 +141,26 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
}
|
||||
}
|
||||
|
||||
public void SetTorrentPriority(string hash, RTorrentPriority priority, RTorrentSettings settings)
|
||||
private string[] GetCommands(string label, RTorrentPriority priority, string directory)
|
||||
{
|
||||
_logger.Debug("Executing remote method: d.priority.set");
|
||||
var result = new List<string>();
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.SetPriority(hash, (long) priority);
|
||||
if (response != 0)
|
||||
if (label.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
throw new DownloadClientException("Could not set priority on torrent: {0}.", hash);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTorrentLabel(string hash, string label, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: d.custom1.set");
|
||||
|
||||
var labelEncoded = System.Web.HttpUtility.UrlEncode(label);
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var setLabel = client.SetLabel(hash, labelEncoded);
|
||||
if (setLabel != labelEncoded)
|
||||
{
|
||||
throw new DownloadClientException("Could set label on torrent: {0}.", hash);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTorrentDownloadDirectory(string hash, string directory, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: d.directory.set");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.SetDirectory(hash, directory);
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could not set directory for torrent: {0}.", hash);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDeferredMagnetProperties(string hash, string category, string directory, RTorrentPriority priority, RTorrentSettings settings)
|
||||
{
|
||||
var commands = new List<string>();
|
||||
|
||||
if (category.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
commands.Add("d.custom1.set=" + category);
|
||||
}
|
||||
|
||||
if (directory.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
commands.Add("d.directory.set=" + directory);
|
||||
result.Add("d.custom1.set=" + label);
|
||||
}
|
||||
|
||||
if (priority != RTorrentPriority.Normal)
|
||||
{
|
||||
commands.Add("d.priority.set=" + (long)priority);
|
||||
result.Add("d.priority.set=" + (int)priority);
|
||||
}
|
||||
|
||||
// Ensure it gets started if the user doesn't have schedule=...,start_tied=
|
||||
commands.Add("d.open=");
|
||||
commands.Add("d.start=");
|
||||
|
||||
if (commands.Any())
|
||||
if (directory.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var key = "event.download.inserted_new";
|
||||
var cmd_key = "sonarr_deferred_" + hash;
|
||||
|
||||
commands.Add(string.Format("print=\"Applying deferred properties to {0}\"", hash));
|
||||
|
||||
// Remove event handler once triggered.
|
||||
commands.Add(string.Format("\"method.set_key={0},{1}\"", key, cmd_key));
|
||||
|
||||
var setKeyValue = string.Format("branch=\"equal=d.hash=,cat={0}\",{{{1}}}", hash, string.Join(",", commands));
|
||||
|
||||
_logger.Debug("Executing remote method: method.set_key = {0},{1},{2}", key, cmd_key, setKeyValue);
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
// Commands need a target, in this case the target is an empty string
|
||||
// See: https://github.com/rakshasa/rtorrent/issues/227
|
||||
var response = client.SetKey("", key, cmd_key, setKeyValue);
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could set properties for torrent: {0}.", hash);
|
||||
}
|
||||
result.Add("d.directory.set=" + directory);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public bool HasHashTorrent(string hash, RTorrentSettings settings)
|
||||
|
@ -270,32 +182,6 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
}
|
||||
}
|
||||
|
||||
public void StartTorrent(string hash, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote methods: d.open and d.start");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var multicallResponse = client.SystemMulticall(new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
methodName = "d.open",
|
||||
@params = new[] { hash }
|
||||
},
|
||||
new
|
||||
{
|
||||
methodName = "d.start",
|
||||
@params = new[] { hash }
|
||||
},
|
||||
}).SelectMany(c => ((IEnumerable<int>)c));
|
||||
|
||||
if (multicallResponse.Any(r => r != 0))
|
||||
{
|
||||
throw new DownloadClientException("Could not start torrent: {0}.", hash);
|
||||
}
|
||||
}
|
||||
|
||||
private IRTorrent BuildClient(RTorrentSettings settings)
|
||||
{
|
||||
var client = XmlRpcProxyGen.Create<IRTorrent>();
|
||||
|
@ -316,4 +202,4 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
|||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Common.Http;
|
||||
|
@ -41,8 +41,8 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
}
|
||||
|
||||
var jsonResponse = JsonConvert.DeserializeObject<PassThePopcornResponse>(indexerResponse.Content);
|
||||
if (jsonResponse.TotalResults == "0" ||
|
||||
jsonResponse.TotalResults.IsNullOrWhiteSpace() ||
|
||||
if (jsonResponse.TotalResults == "0" ||
|
||||
jsonResponse.TotalResults.IsNullOrWhiteSpace() ||
|
||||
jsonResponse.Movies == null)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, "No results were found");
|
||||
|
@ -51,30 +51,20 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
|
||||
foreach (var result in jsonResponse.Movies)
|
||||
{
|
||||
foreach (var torrent in result.Torrents)
|
||||
{
|
||||
var id = torrent.Id;
|
||||
var title = torrent.ReleaseName;
|
||||
foreach (var torrent in result.Torrents)
|
||||
{
|
||||
var id = torrent.Id;
|
||||
var title = torrent.ReleaseName;
|
||||
|
||||
if (torrent.GoldenPopcorn)
|
||||
{
|
||||
title = $"{title} 🍿";
|
||||
}
|
||||
|
||||
if (torrent.Checked)
|
||||
{
|
||||
title = $"{title} ✔";
|
||||
}
|
||||
|
||||
var imdbId = 0;
|
||||
|
||||
int.TryParse(result.ImdbId, out imdbId);
|
||||
|
||||
if (imdbId == 0 && result.ImdbId.Substring(0, 2) == "tt")
|
||||
{
|
||||
int.TryParse(result.ImdbId.Substring(2), out imdbId);
|
||||
}
|
||||
if (torrent.GoldenPopcorn)
|
||||
{
|
||||
title = $"{title} 🍿";
|
||||
}
|
||||
|
||||
if (torrent.Checked)
|
||||
{
|
||||
title = $"{title} ✔";
|
||||
}
|
||||
|
||||
// Only add approved torrents
|
||||
if (_settings.RequireApproved && torrent.Checked)
|
||||
|
@ -92,7 +82,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
Golden = torrent.GoldenPopcorn,
|
||||
Scene = torrent.Scene,
|
||||
Approved = torrent.Checked,
|
||||
ImdbId = imdbId
|
||||
ImdbId = (result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0)
|
||||
});
|
||||
}
|
||||
// Add all torrents
|
||||
|
@ -111,7 +101,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
Golden = torrent.GoldenPopcorn,
|
||||
Scene = torrent.Scene,
|
||||
Approved = torrent.Checked,
|
||||
ImdbId = imdbId
|
||||
ImdbId = (result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0)
|
||||
});
|
||||
}
|
||||
// Don't add any torrents
|
||||
|
@ -130,10 +120,10 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Golden ? 0 : 1)
|
||||
.ThenBy(o => ((dynamic) o).Scene ? 0 : 1)
|
||||
.ThenBy(o => ((dynamic)o).Scene ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
return
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Golden ? 0 : 1)
|
||||
.ToArray();
|
||||
|
@ -142,14 +132,14 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
|||
// prefer scene
|
||||
if (_settings.Scene)
|
||||
{
|
||||
return
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Scene ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// order by date
|
||||
return
|
||||
return
|
||||
torrentInfos
|
||||
.OrderByDescending(o => o.PublishDate)
|
||||
.ToArray();
|
||||
|
|
Loading…
Reference in New Issue