diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index dea9b6682a..ff7ee085f8 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -17,7 +17,6 @@ namespace Emby.Server.Implementations
{
{ HostWebClientKey, bool.TrueString },
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" },
- { InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" },
{ PlaylistsAllowDuplicatesKey, bool.TrueString }
diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs
index 0b9f805389..e7e72c686b 100644
--- a/Emby.Server.Implementations/IStartupOptions.cs
+++ b/Emby.Server.Implementations/IStartupOptions.cs
@@ -36,11 +36,6 @@ namespace Emby.Server.Implementations
///
string RestartArgs { get; }
- ///
- /// Gets the value of the --plugin-manifest-url command line option.
- ///
- string PluginManifestUrl { get; }
-
///
/// Gets the value of the --published-server-url command line option.
///
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 178f32c313..bdd7c31d69 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -31,11 +31,6 @@ namespace Emby.Server.Implementations.Updates
///
public class InstallationManager : IInstallationManager
{
- ///
- /// The key for a setting that specifies a URL for the plugin repository JSON manifest.
- ///
- public const string PluginManifestUrlKey = "InstallationManager:PluginManifestUrl";
-
///
/// The logger.
///
@@ -122,16 +117,14 @@ namespace Emby.Server.Implementations.Updates
public IEnumerable CompletedInstallations => _completedInstallationsInternal;
///
- public async Task> GetAvailablePackages(CancellationToken cancellationToken = default)
+ public async Task> GetPackages(string manifest, CancellationToken cancellationToken = default)
{
- var manifestUrl = _appConfig.GetValue(PluginManifestUrlKey);
-
try
{
using (var response = await _httpClient.SendAsync(
new HttpRequestOptions
{
- Url = manifestUrl,
+ Url = manifest,
CancellationToken = cancellationToken,
CacheMode = CacheMode.Unconditional,
CacheLength = TimeSpan.FromMinutes(3)
@@ -145,25 +138,35 @@ namespace Emby.Server.Implementations.Updates
}
catch (SerializationException ex)
{
- const string LogTemplate =
- "Failed to deserialize the plugin manifest retrieved from {PluginManifestUrl}. If you " +
- "have specified a custom plugin repository manifest URL with --plugin-manifest-url or " +
- PluginManifestUrlKey + ", please ensure that it is correct.";
- _logger.LogError(ex, LogTemplate, manifestUrl);
+ _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest);
throw;
}
}
}
catch (UriFormatException ex)
{
- const string LogTemplate =
- "The URL configured for the plugin repository manifest URL is not valid: {PluginManifestUrl}. " +
- "Please check the URL configured by --plugin-manifest-url or " + PluginManifestUrlKey;
- _logger.LogError(ex, LogTemplate, manifestUrl);
+ _logger.LogError(ex, "The URL configured for the plugin repository manifest URL is not valid: {Manifest}", manifest);
throw;
}
}
+ ///
+ public async Task> GetAvailablePackages(CancellationToken cancellationToken = default)
+ {
+ var result = new List();
+ foreach (RepositoryInfo repository in _config.Configuration.PluginRepositories)
+ {
+ if (!repository.Enabled)
+ {
+ continue;
+ }
+
+ result.AddRange(await GetPackages(repository.Url, cancellationToken).ConfigureAwait(true));
+ }
+
+ return result.ToList().AsReadOnly();
+ }
+
///
public IEnumerable FilterPackages(
IEnumerable availablePackages,
diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs
index cc250b06e2..a26114e778 100644
--- a/Jellyfin.Server/StartupOptions.cs
+++ b/Jellyfin.Server/StartupOptions.cs
@@ -79,10 +79,6 @@ namespace Jellyfin.Server
[Option("restartargs", Required = false, HelpText = "Arguments for restart script.")]
public string? RestartArgs { get; set; }
- ///
- [Option("plugin-manifest-url", Required = false, HelpText = "A custom URL for the plugin repository JSON manifest")]
- public string? PluginManifestUrl { get; set; }
-
///
[Option("published-server-url", Required = false, HelpText = "Jellyfin Server URL to publish via auto discover process")]
public Uri? PublishedServerUrl { get; set; }
@@ -95,11 +91,6 @@ namespace Jellyfin.Server
{
var config = new Dictionary();
- if (PluginManifestUrl != null)
- {
- config.Add(InstallationManager.PluginManifestUrlKey, PluginManifestUrl);
- }
-
if (NoWebClient)
{
config.Add(ConfigurationExtensions.HostWebClientKey, bool.FalseString);
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
index dd3f3e738a..18860983ec 100644
--- a/MediaBrowser.Api/Devices/DeviceService.cs
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -92,7 +92,6 @@ namespace MediaBrowser.Api.Devices
var sessions = _authRepo.Get(new AuthenticationInfoQuery
{
DeviceId = request.Id
-
}).Items;
foreach (var session in sessions)
diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs
index 444354a992..31ca05759d 100644
--- a/MediaBrowser.Api/PackageService.cs
+++ b/MediaBrowser.Api/PackageService.cs
@@ -13,6 +13,18 @@ using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api
{
+ [Route("/Repositories", "GET", Summary = "Gets all package repositories")]
+ [Authenticated]
+ public class GetRepositories : IReturnVoid
+ {
+ }
+
+ [Route("/Repositories", "POST", Summary = "Sets the enabled and existing package repositories")]
+ [Authenticated]
+ public class SetRepositories : List, IReturnVoid
+ {
+ }
+
///
/// Class GetPackage
///
@@ -94,6 +106,7 @@ namespace MediaBrowser.Api
public class PackageService : BaseApiService
{
private readonly IInstallationManager _installationManager;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
public PackageService(
ILogger logger,
@@ -103,6 +116,18 @@ namespace MediaBrowser.Api
: base(logger, serverConfigurationManager, httpResultFactory)
{
_installationManager = installationManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
+
+ public object Get(GetRepositories request)
+ {
+ var result = _serverConfigurationManager.Configuration.PluginRepositories;
+ return ToOptimizedResult(result);
+ }
+
+ public void Post(SetRepositories request)
+ {
+ _serverConfigurationManager.Configuration.PluginRepositories = request;
}
///
diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs
index 965ffe0ec2..a5025aee96 100644
--- a/MediaBrowser.Common/Updates/IInstallationManager.cs
+++ b/MediaBrowser.Common/Updates/IInstallationManager.cs
@@ -40,6 +40,14 @@ namespace MediaBrowser.Common.Updates
///
IEnumerable CompletedInstallations { get; }
+ ///
+ /// Parses a plugin manifest at the supplied URL.
+ ///
+ /// The URL to query.
+ /// The cancellation token.
+ /// Task{IReadOnlyList{PackageInfo}}.
+ Task> GetPackages(string manifest, CancellationToken cancellationToken = default);
+
///
/// Gets all available packages.
///
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 60b1e6eae6..b8ec1c7108 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -2,7 +2,9 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Updates;
namespace MediaBrowser.Model.Configuration
{
@@ -229,6 +231,8 @@ namespace MediaBrowser.Model.Configuration
public string[] CodecsUsed { get; set; }
+ public List PluginRepositories { get; set; }
+
public bool IgnoreVirtualInterfaces { get; set; }
public bool EnableExternalContentInSuggestions { get; set; }
@@ -241,11 +245,13 @@ namespace MediaBrowser.Model.Configuration
public bool EnableNewOmdbSupport { get; set; }
public string[] RemoteIPFilter { get; set; }
+
public bool IsRemoteIPFilterBlacklist { get; set; }
public int ImageExtractionTimeoutMs { get; set; }
public PathSubstitution[] PathSubstitutions { get; set; }
+
public bool EnableSimpleArtistDetection { get; set; }
public string[] UninstalledPlugins { get; set; }
@@ -298,6 +304,17 @@ namespace MediaBrowser.Model.Configuration
SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
SortRemoveWords = new[] { "the", "a", "an" };
+ PluginRepositories = new List
+ {
+ new RepositoryInfo
+ {
+ Name = "Jellyfin Stable",
+ Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json",
+ Id = Guid.Parse("3721cd80-b10f-4b26-aecd-74c0f0defe97"),
+ Enabled = true
+ }
+ };
+
BaseUrl = string.Empty;
UICulture = "en-US";
@@ -355,6 +372,7 @@ namespace MediaBrowser.Model.Configuration
public class PathSubstitution
{
public string From { get; set; }
+
public string To { get; set; }
}
}
diff --git a/MediaBrowser.Model/Updates/RepositoryInfo.cs b/MediaBrowser.Model/Updates/RepositoryInfo.cs
new file mode 100644
index 0000000000..c07abc8093
--- /dev/null
+++ b/MediaBrowser.Model/Updates/RepositoryInfo.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace MediaBrowser.Model.Updates
+{
+ ///
+ /// Class RepositoryInfo.
+ ///
+ public class RepositoryInfo
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the URL.
+ ///
+ /// The URL.
+ public string Url { get; set; }
+
+ ///
+ /// Gets or sets the ID.
+ ///
+ /// The ID.
+ public Guid Id { get; set; }
+
+ ///
+ /// Gets or sets the enabled status of the repository.
+ ///
+ /// The enabled status.
+ public bool Enabled { get; set; }
+ }
+}