mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 21:43:33 -07:00
Support for primary and fallback download client
This commit is contained in:
parent
4ec0cace2e
commit
3b3d81dab2
8 changed files with 320 additions and 3 deletions
|
@ -7,6 +7,7 @@ namespace Lidarr.Api.V1.DownloadClient
|
|||
{
|
||||
public bool Enable { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public int Priority { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadClientResourceMapper : ProviderResourceMapper<DownloadClientResource, DownloadClientDefinition>
|
||||
|
@ -19,6 +20,7 @@ namespace Lidarr.Api.V1.DownloadClient
|
|||
|
||||
resource.Enable = definition.Enable;
|
||||
resource.Protocol = definition.Protocol;
|
||||
resource.Priority = definition.Priority;
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
@ -31,6 +33,7 @@ namespace Lidarr.Api.V1.DownloadClient
|
|||
|
||||
definition.Enable = resource.Enable;
|
||||
definition.Protocol = resource.Protocol;
|
||||
definition.Priority = resource.Priority;
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Migration;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Migration
|
||||
{
|
||||
[TestFixture]
|
||||
public class add_download_client_priorityFixture : MigrationTest<add_download_client_priority>
|
||||
{
|
||||
[Test]
|
||||
public void should_set_prio_to_one()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("DownloadClients").Row(new
|
||||
{
|
||||
Enable = 1,
|
||||
Name = "Deluge",
|
||||
Implementation = "Deluge",
|
||||
Settings = new DelugeSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc",
|
||||
UrlBase = "/my/"
|
||||
}.ToJson(),
|
||||
ConfigContract = "DelugeSettings"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
items.First().Priority.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_renumber_prio_for_enabled_clients()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("DownloadClients").Row(new
|
||||
{
|
||||
Enable = 1,
|
||||
Name = "Deluge",
|
||||
Implementation = "Deluge",
|
||||
Settings = new DelugeSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc",
|
||||
UrlBase = "/my/"
|
||||
}.ToJson(),
|
||||
ConfigContract = "DelugeSettings"
|
||||
}).Row(new
|
||||
{
|
||||
Enable = 1,
|
||||
Name = "Deluge2",
|
||||
Implementation = "Deluge",
|
||||
Settings = new DelugeSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc",
|
||||
UrlBase = "/my/"
|
||||
}.ToJson(),
|
||||
ConfigContract = "DelugeSettings"
|
||||
}).Row(new
|
||||
{
|
||||
Enable = 1,
|
||||
Name = "sab",
|
||||
Implementation = "Sabnzbd",
|
||||
Settings = new SabnzbdSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc"
|
||||
}.ToJson(),
|
||||
ConfigContract = "SabnzbdSettings"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
|
||||
|
||||
items.Should().HaveCount(3);
|
||||
items[0].Priority.Should().Be(1);
|
||||
items[1].Priority.Should().Be(2);
|
||||
items[2].Priority.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_renumber_prio_for_disabled_clients()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("DownloadClients").Row(new
|
||||
{
|
||||
Enable = 0,
|
||||
Name = "Deluge",
|
||||
Implementation = "Deluge",
|
||||
Settings = new DelugeSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc",
|
||||
UrlBase = "/my/"
|
||||
}.ToJson(),
|
||||
ConfigContract = "DelugeSettings"
|
||||
}).Row(new
|
||||
{
|
||||
Enable = 0,
|
||||
Name = "Deluge2",
|
||||
Implementation = "Deluge",
|
||||
Settings = new DelugeSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc",
|
||||
UrlBase = "/my/"
|
||||
}.ToJson(),
|
||||
ConfigContract = "DelugeSettings"
|
||||
}).Row(new
|
||||
{
|
||||
Enable = 0,
|
||||
Name = "sab",
|
||||
Implementation = "Sabnzbd",
|
||||
Settings = new SabnzbdSettings36
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
MusicCategory = "abc"
|
||||
}.ToJson(),
|
||||
ConfigContract = "SabnzbdSettings"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<DownloadClientDefinition036>("SELECT * FROM DownloadClients");
|
||||
|
||||
items.Should().HaveCount(3);
|
||||
items[0].Priority.Should().Be(1);
|
||||
items[1].Priority.Should().Be(1);
|
||||
items[1].Priority.Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
public class DownloadClientDefinition036
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool Enable { get; set; }
|
||||
public int Priority { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Implementation { get; set; }
|
||||
public JObject Settings { get; set; }
|
||||
public string ConfigContract { get; set; }
|
||||
}
|
||||
|
||||
public class DelugeSettings36
|
||||
{
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string UrlBase { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string MusicCategory { get; set; }
|
||||
public int RecentTvPriority { get; set; }
|
||||
public int OlderTvPriority { get; set; }
|
||||
public bool UseSsl { get; set; }
|
||||
}
|
||||
|
||||
public class SabnzbdSettings36
|
||||
{
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string MusicCategory { get; set; }
|
||||
public int RecentTvPriority { get; set; }
|
||||
public int OlderTvPriority { get; set; }
|
||||
public bool UseSsl { get; set; }
|
||||
}
|
||||
}
|
|
@ -35,13 +35,14 @@ namespace NzbDrone.Core.Test.Download
|
|||
.Returns(_blockedProviders);
|
||||
}
|
||||
|
||||
private Mock<IDownloadClient> WithUsenetClient()
|
||||
private Mock<IDownloadClient> WithUsenetClient(int priority = 0)
|
||||
{
|
||||
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
|
||||
mock.SetupGet(s => s.Definition)
|
||||
.Returns(Builder<DownloadClientDefinition>
|
||||
.CreateNew()
|
||||
.With(v => v.Id = _nextId++)
|
||||
.With(v => v.Priority = priority)
|
||||
.Build());
|
||||
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
@ -51,13 +52,14 @@ namespace NzbDrone.Core.Test.Download
|
|||
return mock;
|
||||
}
|
||||
|
||||
private Mock<IDownloadClient> WithTorrentClient()
|
||||
private Mock<IDownloadClient> WithTorrentClient(int priority = 0)
|
||||
{
|
||||
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
|
||||
mock.SetupGet(s => s.Definition)
|
||||
.Returns(Builder<DownloadClientDefinition>
|
||||
.CreateNew()
|
||||
.With(v => v.Id = _nextId++)
|
||||
.With(v => v.Priority = priority)
|
||||
.Build());
|
||||
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
@ -181,5 +183,47 @@ namespace NzbDrone.Core.Test.Download
|
|||
client3.Definition.Id.Should().Be(4);
|
||||
client4.Definition.Id.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_skip_secondary_prio_torrent_client()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithTorrentClient(2);
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
|
||||
client1.Definition.Id.Should().Be(3);
|
||||
client2.Definition.Id.Should().Be(4);
|
||||
client3.Definition.Id.Should().Be(3);
|
||||
client4.Definition.Id.Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_skip_secondary_prio_torrent_client_if_primary_blocked()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithTorrentClient(2);
|
||||
WithTorrentClient(2);
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(4);
|
||||
|
||||
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
|
||||
|
||||
client1.Definition.Id.Should().Be(2);
|
||||
client2.Definition.Id.Should().Be(3);
|
||||
client3.Definition.Id.Should().Be(2);
|
||||
client4.Definition.Id.Should().Be(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(036)]
|
||||
public class add_download_client_priority : NzbDroneMigrationBase
|
||||
{
|
||||
// Need snapshot in time without having to instantiate.
|
||||
private static HashSet<string> _usenetImplementations = new HashSet<string>
|
||||
{
|
||||
"Sabnzbd", "NzbGet", "NzbVortex", "UsenetBlackhole", "UsenetDownloadStation"
|
||||
};
|
||||
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("DownloadClients").AddColumn("Priority").AsInt32().WithDefaultValue(1);
|
||||
Execute.WithConnection(InitPriorityForBackwardCompatibility);
|
||||
|
||||
}
|
||||
|
||||
private void InitPriorityForBackwardCompatibility(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tran;
|
||||
cmd.CommandText = "SELECT Id, Implementation FROM DownloadClients WHERE Enable = 1";
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
int nextUsenet = 1;
|
||||
int nextTorrent = 1;
|
||||
while (reader.Read())
|
||||
{
|
||||
var id = reader.GetInt32(0);
|
||||
var implName = reader.GetString(1);
|
||||
|
||||
var isUsenet = _usenetImplementations.Contains(implName);
|
||||
|
||||
using (var updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE DownloadClients SET Priority = ? WHERE Id = ?";
|
||||
updateCmd.AddParameter(isUsenet ? nextUsenet++ : nextTorrent++);
|
||||
updateCmd.AddParameter(id);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@ namespace NzbDrone.Core.Download
|
|||
public class DownloadClientDefinition : ProviderDefinition
|
||||
{
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public int Priority { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,11 @@ namespace NzbDrone.Core.Download
|
|||
}
|
||||
}
|
||||
|
||||
// Use the first priority clients first
|
||||
availableProviders = availableProviders.GroupBy(v => (v.Definition as DownloadClientDefinition).Priority)
|
||||
.OrderBy(v => v.Key)
|
||||
.First().OrderBy(v => v.Definition.Id).ToList();
|
||||
|
||||
var lastId = _lastUsedDownloadClient.Find(downloadProtocol.ToString());
|
||||
|
||||
var provider = availableProviders.FirstOrDefault(v => v.Definition.Id > lastId) ?? availableProviders.First();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue