mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-03-05 13:20:20 -05:00
Compare commits
7 Commits
v2.0.0.531
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63853494f8 | ||
|
|
6593575850 | ||
|
|
bbf74a8835 | ||
|
|
1fc2866032 | ||
|
|
eb2e7b9c79 | ||
|
|
cab900f656 | ||
|
|
e2b91e5dc4 |
@@ -2,9 +2,13 @@ using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Security;
|
||||
|
||||
namespace NzbDrone.Common.Http.Dispatchers
|
||||
@@ -14,12 +18,16 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
private readonly IHttpProxySettingsProvider _proxySettingsProvider;
|
||||
private readonly ICreateManagedWebProxy _createManagedWebProxy;
|
||||
private readonly IUserAgentBuilder _userAgentBuilder;
|
||||
private readonly IPlatformInfo _platformInfo;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder)
|
||||
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder, IPlatformInfo platformInfo, Logger logger)
|
||||
{
|
||||
_proxySettingsProvider = proxySettingsProvider;
|
||||
_createManagedWebProxy = createManagedWebProxy;
|
||||
_userAgentBuilder = userAgentBuilder;
|
||||
_platformInfo = platformInfo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
||||
@@ -39,7 +47,7 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
|
||||
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
|
||||
}
|
||||
|
||||
|
||||
webRequest.Method = request.Method.ToString();
|
||||
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
|
||||
webRequest.KeepAlive = request.ConnectionKeepAlive;
|
||||
@@ -84,6 +92,9 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
|
||||
if (httpWebResponse == null)
|
||||
{
|
||||
// Workaround for mono not closing connections properly in certain situations.
|
||||
AbortWebRequest(webRequest);
|
||||
|
||||
// The default messages for WebException on mono are pretty horrible.
|
||||
if (e.Status == WebExceptionStatus.NameResolutionFailure)
|
||||
{
|
||||
@@ -198,5 +209,36 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for mono not closing connections properly on timeouts
|
||||
private void AbortWebRequest(HttpWebRequest webRequest)
|
||||
{
|
||||
// First affected version was mono 5.16
|
||||
if (OsInfo.IsNotWindows && _platformInfo.Version >= new Version(5, 16))
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentOperationInfo = webRequest.GetType().GetField("currentOperation", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var currentOperation = currentOperationInfo.GetValue(webRequest);
|
||||
|
||||
if (currentOperation != null)
|
||||
{
|
||||
var responseStreamInfo = currentOperation.GetType().GetField("responseStream", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var responseStream = responseStreamInfo.GetValue(currentOperation) as Stream;
|
||||
// Note that responseStream will likely be null once mono fixes it.
|
||||
responseStream?.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// This can fail randomly on future mono versions that have been changed/fixed. Log to sentry and ignore.
|
||||
_logger.Trace()
|
||||
.Exception(ex)
|
||||
.Message("Unable to dispose responseStream on mono {0}", _platformInfo.Version)
|
||||
.WriteSentryWarn("MonoCloseWaitPatchFailed", ex.Message)
|
||||
.Write();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.QBittorrent;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
{
|
||||
@@ -99,15 +100,18 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
Subject.Definition.Settings.As<QBittorrentSettings>().RecentTvPriority = (int)QBittorrentPriority.First;
|
||||
}
|
||||
|
||||
protected void GivenMaxRatio(float maxRatio, bool removeOnMaxRatio = true)
|
||||
protected void GivenGlobalSeedLimits(float maxRatio, int maxSeedingTime = -1, bool removeOnMaxRatio = false)
|
||||
{
|
||||
Mocker.GetMock<IQBittorrentProxy>()
|
||||
.Setup(s => s.GetConfig(It.IsAny<QBittorrentSettings>()))
|
||||
.Returns(new QBittorrentPreferences
|
||||
{
|
||||
RemoveOnMaxRatio = removeOnMaxRatio,
|
||||
MaxRatio = maxRatio
|
||||
});
|
||||
.Setup(s => s.GetConfig(It.IsAny<QBittorrentSettings>()))
|
||||
.Returns(new QBittorrentPreferences
|
||||
{
|
||||
RemoveOnMaxRatio = removeOnMaxRatio,
|
||||
MaxRatio = maxRatio,
|
||||
MaxRatioEnabled = maxRatio >= 0,
|
||||
MaxSeedingTime = maxSeedingTime,
|
||||
MaxSeedingTimeEnabled = maxSeedingTime >= 0
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void GivenTorrents(List<QBittorrentTorrent> torrents)
|
||||
@@ -277,17 +281,33 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
id.Should().Be(expectedHash);
|
||||
}
|
||||
|
||||
public void Download_should_refuse_magnet_if_dht_is_disabled()
|
||||
[Test]
|
||||
public void Download_should_refuse_magnet_if_no_trackers_provided_and_dht_is_disabled()
|
||||
{
|
||||
|
||||
Mocker.GetMock<IQBittorrentProxy>()
|
||||
.Setup(s => s.GetConfig(It.IsAny<QBittorrentSettings>()))
|
||||
.Returns(new QBittorrentPreferences() { DhtEnabled = false });
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
remoteEpisode.Release.DownloadUrl = "magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR&tr=udp";
|
||||
remoteEpisode.Release.DownloadUrl = "magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR";
|
||||
|
||||
Assert.Throws<NotSupportedException>(() => Subject.Download(remoteEpisode));
|
||||
Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteEpisode));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_accept_magnet_if_trackers_provided_and_dht_is_disabled()
|
||||
{
|
||||
Mocker.GetMock<IQBittorrentProxy>()
|
||||
.Setup(s => s.GetConfig(It.IsAny<QBittorrentSettings>()))
|
||||
.Returns(new QBittorrentPreferences() { DhtEnabled = false });
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
remoteEpisode.Release.DownloadUrl = "magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR&tr=udp://abc";
|
||||
|
||||
Assert.DoesNotThrow(() => Subject.Download(remoteEpisode));
|
||||
|
||||
Mocker.GetMock<IQBittorrentProxy>()
|
||||
.Verify(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<QBittorrentSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -371,7 +391,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_not_reached()
|
||||
{
|
||||
GivenMaxRatio(1.0f);
|
||||
GivenGlobalSeedLimits(1.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
@@ -392,11 +412,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
item.CanMoveFiles.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_paused()
|
||||
protected virtual QBittorrentTorrent GivenCompletedTorrent(
|
||||
string state = "pausedUP",
|
||||
float ratio = 0.1f, float ratioLimit = -2,
|
||||
int seedingTime = 1, int seedingTimeLimit = -2)
|
||||
{
|
||||
GivenMaxRatio(1.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
@@ -404,12 +424,32 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
Size = 1000,
|
||||
Progress = 1.0,
|
||||
Eta = 8640000,
|
||||
State = "uploading",
|
||||
State = state,
|
||||
Label = "",
|
||||
SavePath = "",
|
||||
Ratio = 1.0f
|
||||
Ratio = ratio,
|
||||
RatioLimit = ratioLimit,
|
||||
SeedingTimeLimit = seedingTimeLimit
|
||||
};
|
||||
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||
|
||||
GivenTorrents(new List<QBittorrentTorrent>() { torrent });
|
||||
|
||||
Mocker.GetMock<IQBittorrentProxy>()
|
||||
.Setup(s => s.GetTorrentProperties("HASH", It.IsAny<QBittorrentSettings>()))
|
||||
.Returns(new QBittorrentTorrentProperties
|
||||
{
|
||||
Hash = "HASH",
|
||||
SeedingTime = seedingTime
|
||||
});
|
||||
|
||||
return torrent;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(1.0f);
|
||||
GivenCompletedTorrent("uploading", ratio: 1.0f);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeFalse();
|
||||
@@ -419,21 +459,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set()
|
||||
{
|
||||
GivenMaxRatio(1.0f, false);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
Name = _title,
|
||||
Size = 1000,
|
||||
Progress = 1.0,
|
||||
Eta = 8640000,
|
||||
State = "uploading",
|
||||
Label = "",
|
||||
SavePath = "",
|
||||
Ratio = 1.0f
|
||||
};
|
||||
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||
GivenGlobalSeedLimits(-1);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 1.0f);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeFalse();
|
||||
@@ -443,21 +470,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
[Test]
|
||||
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused()
|
||||
{
|
||||
GivenMaxRatio(1.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
Name = _title,
|
||||
Size = 1000,
|
||||
Progress = 1.0,
|
||||
Eta = 8640000,
|
||||
State = "pausedUP",
|
||||
Label = "",
|
||||
SavePath = "",
|
||||
Ratio = 1.0f
|
||||
};
|
||||
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||
GivenGlobalSeedLimits(1.0f);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 1.0f);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeTrue();
|
||||
@@ -467,22 +481,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
[Test]
|
||||
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused()
|
||||
{
|
||||
GivenMaxRatio(2.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
Name = _title,
|
||||
Size = 1000,
|
||||
Progress = 1.0,
|
||||
Eta = 8640000,
|
||||
State = "pausedUP",
|
||||
Label = "",
|
||||
SavePath = "",
|
||||
Ratio = 1.0f,
|
||||
RatioLimit = 0.8f
|
||||
};
|
||||
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||
GivenGlobalSeedLimits(2.0f);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 1.0f, ratioLimit: 0.8f);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeTrue();
|
||||
@@ -492,33 +492,75 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
[Test]
|
||||
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused()
|
||||
{
|
||||
GivenMaxRatio(0.2f);
|
||||
GivenGlobalSeedLimits(0.2f);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 0.5f, ratioLimit: 0.8f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
Hash = "HASH",
|
||||
Name = _title,
|
||||
Size = 1000,
|
||||
Progress = 1.0,
|
||||
Eta = 8640000,
|
||||
State = "pausedUP",
|
||||
Label = "",
|
||||
SavePath = "",
|
||||
Ratio = 0.5f,
|
||||
RatioLimit = 0.8f
|
||||
};
|
||||
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeFalse();
|
||||
item.CanMoveFiles.Should().BeFalse();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_seedingtime_reached_and_not_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(-1, 20);
|
||||
GivenCompletedTorrent("uploading", ratio: 2.0f, seedingTime: 30);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeFalse();
|
||||
item.CanMoveFiles.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_and_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(-1, 20);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeTrue();
|
||||
item.CanMoveFiles.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_removable_and_should_allow_move_files_if_overridden_max_seedingtime_reached_and_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(-1, 40);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20, seedingTimeLimit: 10);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeTrue();
|
||||
item.CanMoveFiles.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_removable_if_overridden_max_seedingtime_not_reached_and_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(-1, 20);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 30, seedingTimeLimit: 40);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeFalse();
|
||||
item.CanMoveFiles.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_but_ratio_not_and_paused()
|
||||
{
|
||||
GivenGlobalSeedLimits(2.0f, 20);
|
||||
GivenCompletedTorrent("pausedUP", ratio: 1.0f, seedingTime: 30);
|
||||
|
||||
var item = Subject.GetItems().Single();
|
||||
item.CanBeRemoved.Should().BeTrue();
|
||||
item.CanMoveFiles.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_category_from_the_category_if_set()
|
||||
{
|
||||
const string category = "tv-sonarr";
|
||||
GivenMaxRatio(1.0f);
|
||||
GivenGlobalSeedLimits(1.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
@@ -543,7 +585,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
||||
public void should_get_category_from_the_label_if_the_category_is_not_available()
|
||||
{
|
||||
const string category = "tv-sonarr";
|
||||
GivenMaxRatio(1.0f);
|
||||
GivenGlobalSeedLimits(1.0f);
|
||||
|
||||
var torrent = new QBittorrentTorrent
|
||||
{
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace NzbDrone.Core.Test.Framework
|
||||
|
||||
Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>()));
|
||||
Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
|
||||
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>()));
|
||||
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<NLog.Logger>()));
|
||||
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<IPlatformInfo>(), TestLogger));
|
||||
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger));
|
||||
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
|
||||
Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger));
|
||||
Mocker.SetConstant<ISonarrCloudRequestBuilder>(new SonarrCloudRequestBuilder());
|
||||
|
||||
@@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
@@ -77,12 +78,14 @@ namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
||||
_insertedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -146,6 +149,63 @@ namespace NzbDrone.Core.Test.TvTests
|
||||
_updatedEpisodes.Should().OnlyContain(e => e.Monitored == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_set_monitored_status_for_old_episodes_to_false_if_recent_enough()
|
||||
{
|
||||
var series = GetSeries();
|
||||
series.Seasons = new List<Season>();
|
||||
series.Seasons.Add(new Season { SeasonNumber = 1, Monitored = true });
|
||||
|
||||
var episodes = GetEpisodes().OrderBy(v => v.SeasonNumber).ThenBy(v => v.EpisodeNumber).Take(5).ToList();
|
||||
|
||||
episodes[1].AirDateUtc = DateTime.UtcNow.AddDays(-15);
|
||||
episodes[2].AirDateUtc = DateTime.UtcNow.AddDays(-10);
|
||||
episodes[3].AirDateUtc = DateTime.UtcNow.AddDays(1);
|
||||
|
||||
var existingEpisodes = episodes.Skip(4).ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(existingEpisodes);
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, episodes);
|
||||
|
||||
_insertedEpisodes = _insertedEpisodes.OrderBy(v => v.EpisodeNumber).ToList();
|
||||
|
||||
_insertedEpisodes.Should().HaveCount(4);
|
||||
_insertedEpisodes[0].Monitored.Should().Be(true);
|
||||
_insertedEpisodes[1].Monitored.Should().Be(true);
|
||||
_insertedEpisodes[2].Monitored.Should().Be(true);
|
||||
_insertedEpisodes[3].Monitored.Should().Be(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_set_monitored_status_for_old_episodes_to_false_if_no_episodes_existed()
|
||||
{
|
||||
var series = GetSeries();
|
||||
series.Seasons = new List<Season>();
|
||||
|
||||
var episodes = GetEpisodes().OrderBy(v => v.SeasonNumber).ThenBy(v => v.EpisodeNumber).Take(4).ToList();
|
||||
|
||||
episodes[1].AirDateUtc = DateTime.UtcNow.AddDays(-15);
|
||||
episodes[2].AirDateUtc = DateTime.UtcNow.AddDays(-10);
|
||||
episodes[3].AirDateUtc = DateTime.UtcNow.AddDays(1);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, episodes);
|
||||
|
||||
_insertedEpisodes = _insertedEpisodes.OrderBy(v => v.EpisodeNumber).ToList();
|
||||
|
||||
_insertedEpisodes.Should().HaveSameCount(episodes);
|
||||
_insertedEpisodes[0].Monitored.Should().Be(false);
|
||||
_insertedEpisodes[1].Monitored.Should().Be(false);
|
||||
_insertedEpisodes[2].Monitored.Should().Be(false);
|
||||
_insertedEpisodes[3].Monitored.Should().Be(true);
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_duplicate_remote_episodes_before_processing()
|
||||
{
|
||||
|
||||
@@ -1,22 +1,40 @@
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.History;
|
||||
|
||||
namespace NzbDrone.Core.Analytics
|
||||
{
|
||||
public interface IAnalyticsService
|
||||
{
|
||||
bool IsEnabled { get; }
|
||||
bool InstallIsActive { get; }
|
||||
}
|
||||
|
||||
public class AnalyticsService : IAnalyticsService
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly IHistoryService _historyService;
|
||||
|
||||
public AnalyticsService(IConfigFileProvider configFileProvider)
|
||||
public AnalyticsService(IHistoryService historyService, IConfigFileProvider configFileProvider)
|
||||
{
|
||||
_configFileProvider = configFileProvider;
|
||||
_historyService = historyService;
|
||||
}
|
||||
|
||||
public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfo.IsProduction;
|
||||
|
||||
public bool InstallIsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
var lastRecord = _historyService.Paged(new PagingSpec<History.History>() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending });
|
||||
var monthAgo = DateTime.UtcNow.AddMonths(-1);
|
||||
|
||||
return lastRecord.Records.Any(v => v.Date > monthAgo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestCategory());
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestOutputPath());
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestOutputPath());
|
||||
failures.AddIfNotNull(TestGetNZB());
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
|
||||
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
|
||||
{
|
||||
if (!Proxy.GetConfig(Settings).DhtEnabled)
|
||||
if (!Proxy.GetConfig(Settings).DhtEnabled && !magnetLink.Contains("&tr="))
|
||||
{
|
||||
throw new NotSupportedException("Magnet Links not supported if DHT is disabled");
|
||||
throw new NotSupportedException("Magnet Links without trackers not supported if DHT is disabled");
|
||||
}
|
||||
|
||||
Proxy.AddTorrentFromUrl(magnetLink, Settings);
|
||||
@@ -133,7 +133,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
// Avoid removing torrents that haven't reached the global max ratio.
|
||||
// Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api).
|
||||
item.CanMoveFiles = item.CanBeRemoved = (torrent.State == "pausedUP" && HasReachedSeedLimit(torrent, config));
|
||||
|
||||
|
||||
if (!item.OutputPath.IsEmpty && item.OutputPath.FileName != torrent.Name)
|
||||
{
|
||||
@@ -216,7 +215,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestPrioritySupport());
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
@@ -387,23 +386,40 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
{
|
||||
if (torrent.RatioLimit >= 0)
|
||||
{
|
||||
if (torrent.Ratio < torrent.RatioLimit) return false;
|
||||
if (torrent.Ratio >= torrent.RatioLimit) return true;
|
||||
}
|
||||
else if (torrent.RatioLimit == -2 && config.MaxRatioEnabled)
|
||||
{
|
||||
if (torrent.Ratio < config.MaxRatio) return false;
|
||||
if (torrent.Ratio >= config.MaxRatio) return true;
|
||||
}
|
||||
|
||||
if (torrent.SeedingTimeLimit >= 0)
|
||||
{
|
||||
if (torrent.SeedingTime < torrent.SeedingTimeLimit) return false;
|
||||
if (!torrent.SeedingTime.HasValue)
|
||||
{
|
||||
FetchTorrentDetails(torrent);
|
||||
}
|
||||
|
||||
if (torrent.SeedingTime >= torrent.SeedingTimeLimit) return true;
|
||||
}
|
||||
else if (torrent.RatioLimit == -2 && config.MaxSeedingTimeEnabled)
|
||||
else if (torrent.SeedingTimeLimit == -2 && config.MaxSeedingTimeEnabled)
|
||||
{
|
||||
if (torrent.SeedingTime < config.MaxSeedingTime) return false;
|
||||
if (!torrent.SeedingTime.HasValue)
|
||||
{
|
||||
FetchTorrentDetails(torrent);
|
||||
}
|
||||
|
||||
if (torrent.SeedingTime >= config.MaxSeedingTime) return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void FetchTorrentDetails(QBittorrentTorrent torrent)
|
||||
{
|
||||
var torrentProperties = Proxy.GetTorrentProperties(torrent.Hash, Settings);
|
||||
|
||||
torrent.SeedingTime = torrentProperties.SeedingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
string GetVersion(QBittorrentSettings settings);
|
||||
QBittorrentPreferences GetConfig(QBittorrentSettings settings);
|
||||
List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings);
|
||||
QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings);
|
||||
|
||||
void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings);
|
||||
void AddTorrentFromFile(string fileName, Byte[] fileContent, QBittorrentSettings settings);
|
||||
|
||||
@@ -87,14 +87,25 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
|
||||
public List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/query/torrents")
|
||||
.AddQueryParam("label", settings.TvCategory)
|
||||
.AddQueryParam("category", settings.TvCategory);
|
||||
var request = BuildRequest(settings).Resource("/query/torrents");
|
||||
if (settings.TvCategory.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
request.AddQueryParam("label", settings.TvCategory);
|
||||
request.AddQueryParam("category", settings.TvCategory);
|
||||
}
|
||||
var response = ProcessRequest<List<QBittorrentTorrent>>(request, settings);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource($"/query/propertiesGeneral/{hash}");
|
||||
var response = ProcessRequest<QBittorrentTorrentProperties>(request, settings);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/command/download")
|
||||
|
||||
@@ -86,13 +86,25 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
|
||||
public List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/info")
|
||||
.AddQueryParam("category", settings.TvCategory);
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/info");
|
||||
if (settings.TvCategory.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
request.AddQueryParam("category", settings.TvCategory);
|
||||
}
|
||||
var response = ProcessRequest<List<QBittorrentTorrent>>(request, settings);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/properties")
|
||||
.AddQueryParam("hash", hash);
|
||||
var response = ProcessRequest<QBittorrentTorrentProperties>(request, settings);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/add")
|
||||
|
||||
@@ -30,10 +30,17 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
public float RatioLimit { get; set; } = -2;
|
||||
|
||||
[JsonProperty(PropertyName = "seeding_time")]
|
||||
public long SeedingTime { get; set; } // Torrent seeding time
|
||||
public long? SeedingTime { get; set; } // Torrent seeding time (not provided by the list api)
|
||||
|
||||
[JsonProperty(PropertyName = "seeding_time_limit")] // Per torrent seeding time limit (-2 = use global, -1 = unlimited)
|
||||
public long SeedingTimeLimit { get; set; } = -2;
|
||||
}
|
||||
|
||||
public class QBittorrentTorrentProperties
|
||||
{
|
||||
public string Hash { get; set; } // Torrent hash
|
||||
|
||||
[JsonProperty(PropertyName = "seeding_time")]
|
||||
public long SeedingTime { get; set; } // Torrent seeding time
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
foreach (RTorrentTorrent torrent in torrents)
|
||||
{
|
||||
// Don't concern ourselves with categories other than specified
|
||||
if (torrent.Category != Settings.TvCategory) continue;
|
||||
if (Settings.TvCategory.IsNotNullOrWhiteSpace() && torrent.Category != Settings.TvCategory) continue;
|
||||
|
||||
if (torrent.Path.StartsWith("."))
|
||||
{
|
||||
throw new DownloadClientException("Download paths paths must be absolute. Please specify variable \"directory\" in rTorrent.");
|
||||
throw new DownloadClientException("Download paths must be absolute. Please specify variable \"directory\" in rTorrent.");
|
||||
}
|
||||
|
||||
var item = new DownloadClientItem();
|
||||
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
failures.AddIfNotNull(TestDirectory());
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
failures.AddIfNotNull(TestConnection());
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestGetTorrents());
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Newznab
|
||||
{
|
||||
@@ -102,7 +103,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
base.Test(failures);
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestCapabilities());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Torznab
|
||||
{
|
||||
@@ -91,7 +92,7 @@ namespace NzbDrone.Core.Indexers.Torznab
|
||||
protected override void Test(List<ValidationFailure> failures)
|
||||
{
|
||||
base.Test(failures);
|
||||
if (failures.Any()) return;
|
||||
if (failures.HasErrors()) return;
|
||||
failures.AddIfNotNull(TestCapabilities());
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,9 @@ namespace NzbDrone.Core.Tv
|
||||
return;
|
||||
}
|
||||
|
||||
var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue && a.AirDateUtc.Value.Before(DateTime.UtcNow.AddDays(1)) && a.Monitored).ToList();
|
||||
var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue
|
||||
&& a.AirDateUtc.Value.Between(DateTime.UtcNow.AddDays(-14), DateTime.UtcNow.AddDays(1))
|
||||
&& a.Monitored).ToList();
|
||||
|
||||
if (previouslyAired.Empty())
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace NzbDrone.Core.Tv
|
||||
|
||||
var existingEpisodes = _episodeService.GetEpisodeBySeries(series.Id);
|
||||
var seasons = series.Seasons;
|
||||
var hasExisting = existingEpisodes.Any();
|
||||
|
||||
var updateList = new List<Episode>();
|
||||
var newList = new List<Episode>();
|
||||
@@ -82,6 +83,8 @@ namespace NzbDrone.Core.Tv
|
||||
}
|
||||
}
|
||||
|
||||
UnmonitorReaddedEpisodes(series, newList, hasExisting);
|
||||
|
||||
var allEpisodes = new List<Episode>();
|
||||
allEpisodes.AddRange(newList);
|
||||
allEpisodes.AddRange(updateList);
|
||||
@@ -117,6 +120,41 @@ namespace NzbDrone.Core.Tv
|
||||
return season == null || season.Monitored;
|
||||
}
|
||||
|
||||
|
||||
private void UnmonitorReaddedEpisodes(Series series, List<Episode> episodes, bool hasExisting)
|
||||
{
|
||||
if (series.AddOptions != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var threshold = DateTime.UtcNow.AddDays(-14);
|
||||
|
||||
var oldEpisodes = episodes.Where(e => e.AirDateUtc.HasValue && e.AirDateUtc.Value.Before(threshold)).ToList();
|
||||
|
||||
if (oldEpisodes.Any())
|
||||
{
|
||||
if (hasExisting)
|
||||
{
|
||||
_logger.Warn("Show {0} ({1}) had {2} old episodes appear, please check monitored status.", series.TvdbId, series.Title, oldEpisodes.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
threshold = DateTime.UtcNow.AddDays(-1);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
if (episode.AirDateUtc.HasValue && episode.AirDateUtc.Value.Before(threshold))
|
||||
{
|
||||
episode.Monitored = false;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Warn("Show {0} ({1}) had {2} old episodes appear, unmonitored aired episodes to prevent unexpected downloads.", series.TvdbId, series.Title, oldEpisodes.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustMultiEpisodeAirTime(Series series, IEnumerable<Episode> allEpisodes)
|
||||
{
|
||||
if (series.Network == "Netflix")
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Analytics;
|
||||
|
||||
namespace NzbDrone.Core.Update
|
||||
{
|
||||
@@ -15,14 +16,16 @@ namespace NzbDrone.Core.Update
|
||||
public class UpdatePackageProvider : IUpdatePackageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IPlatformInfo _platformInfo;
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
private readonly IPlatformInfo _platformInfo;
|
||||
private readonly IAnalyticsService _analyticsService;
|
||||
|
||||
public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IPlatformInfo platformInfo)
|
||||
public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_platformInfo = platformInfo;
|
||||
_analyticsService = analyticsService;
|
||||
_requestBuilder = requestBuilder.Services;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
|
||||
@@ -32,10 +35,15 @@ namespace NzbDrone.Core.Update
|
||||
.AddQueryParam("version", currentVersion)
|
||||
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
|
||||
.AddQueryParam("runtimeVer", _platformInfo.Version)
|
||||
.SetSegment("branch", branch)
|
||||
.Build();
|
||||
.SetSegment("branch", branch);
|
||||
|
||||
var update = _httpClient.Get<UpdatePackageAvailable>(request).Resource;
|
||||
if (_analyticsService.IsEnabled)
|
||||
{
|
||||
// Send if the system is active so we know which versions to deprecate/ignore
|
||||
request.AddQueryParam("active", _analyticsService.InstallIsActive.ToString().ToLower());
|
||||
}
|
||||
|
||||
var update = _httpClient.Get<UpdatePackageAvailable>(request.Build()).Resource;
|
||||
|
||||
if (!update.Available) return null;
|
||||
|
||||
@@ -49,10 +57,15 @@ namespace NzbDrone.Core.Update
|
||||
.AddQueryParam("version", currentVersion)
|
||||
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
|
||||
.AddQueryParam("runtimeVer", _platformInfo.Version)
|
||||
.SetSegment("branch", branch)
|
||||
.Build();
|
||||
.SetSegment("branch", branch);
|
||||
|
||||
var updates = _httpClient.Get<List<UpdatePackage>>(request);
|
||||
if (_analyticsService.IsEnabled)
|
||||
{
|
||||
// Send if the system is active so we know which versions to deprecate/ignore
|
||||
request.AddQueryParam("active", _analyticsService.InstallIsActive.ToString().ToLower());
|
||||
}
|
||||
|
||||
var updates = _httpClient.Get<List<UpdatePackage>>(request.Build());
|
||||
|
||||
return updates.Resource;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
|
||||
namespace NzbDrone.Core.Validation
|
||||
{
|
||||
@@ -19,5 +21,21 @@ namespace NzbDrone.Core.Validation
|
||||
throw new ValidationException(result.Errors);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasErrors(this List<ValidationFailure> list)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
var extended = item as NzbDroneValidationFailure;
|
||||
if (extended != null && extended.IsWarning)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user