aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs15
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj4
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs4
-rw-r--r--Jellyfin.Api/Controllers/LibraryStructureController.cs12
-rw-r--r--Jellyfin.Api/Models/LibraryStructureDto/AddVirtualFolderDto.cs (renamed from Jellyfin.Api/Models/LibraryStructureDto/LibraryOptionsDto.cs)6
-rw-r--r--Jellyfin.Api/Models/LibraryStructureDto/UpdateLibraryOptionsDto.cs21
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs18
-rw-r--r--Jellyfin.Server/Startup.cs26
-rw-r--r--MediaBrowser.Common/IApplicationHost.cs7
-rw-r--r--MediaBrowser.Common/Net/DefaultHttpClientHandler.cs20
-rw-r--r--MediaBrowser.Common/Net/NamedClient.cs18
11 files changed, 129 insertions, 22 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index cb63cc85e..a2d6e2c9e 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -97,6 +97,7 @@ using MediaBrowser.Providers.Plugins.TheTvdb;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Prometheus.DotNetRuntime;
@@ -1393,6 +1394,20 @@ namespace Emby.Server.Implementations
_plugins = list.ToArray();
}
+ public IEnumerable<Assembly> GetApiPluginAssemblies()
+ {
+ var assemblies = _allConcreteTypes
+ .Where(i => typeof(ControllerBase).IsAssignableFrom(i))
+ .Select(i => i.Assembly)
+ .Distinct();
+
+ foreach (var assembly in assemblies)
+ {
+ Logger.LogDebug("Found API endpoints in plugin {name}", assembly.FullName);
+ yield return assembly;
+ }
+ }
+
public virtual void LaunchUrl(string url)
{
if (!CanLaunchWebBrowser)
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 60564f700..56fc57327 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -22,7 +22,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="IPNetwork2" Version="2.5.211" />
+ <PackageReference Include="IPNetwork2" Version="2.5.224" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
@@ -37,7 +37,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" />
<PackageReference Include="Mono.Nat" Version="2.0.2" />
- <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" />
+ <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
<PackageReference Include="sharpcompress" Version="0.26.0" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index ca9c2fa46..a204fe35c 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -1281,9 +1281,9 @@ namespace Jellyfin.Api.Controllers
Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false)));
// if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified
- if (!(dateImageModified > ifModifiedSinceHeader))
+ if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue)
{
- if (ifModifiedSinceHeader.Add(cacheDuration!.Value) < DateTime.UtcNow)
+ if (ifModifiedSinceHeader.Add(cacheDuration.Value) < DateTime.UtcNow)
{
Response.StatusCode = StatusCodes.Status304NotModified;
return new ContentResult();
diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs
index cdab4f356..d290e3c5b 100644
--- a/Jellyfin.Api/Controllers/LibraryStructureController.cs
+++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs
@@ -76,7 +76,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? name,
[FromQuery] string? collectionType,
[FromQuery] string[] paths,
- [FromBody] LibraryOptionsDto? libraryOptionsDto,
+ [FromBody] AddVirtualFolderDto? libraryOptionsDto,
[FromQuery] bool refreshLibrary = false)
{
var libraryOptions = libraryOptionsDto?.LibraryOptions ?? new LibraryOptions();
@@ -312,19 +312,17 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Update library options.
/// </summary>
- /// <param name="id">The library name.</param>
- /// <param name="libraryOptions">The library options.</param>
+ /// <param name="request">The library name and options.</param>
/// <response code="204">Library updated.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("LibraryOptions")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateLibraryOptions(
- [FromQuery] string? id,
- [FromBody] LibraryOptions? libraryOptions)
+ [FromBody] UpdateLibraryOptionsDto request)
{
- var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(id);
+ var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id);
- collectionFolder.UpdateLibraryOptions(libraryOptions);
+ collectionFolder.UpdateLibraryOptions(request.LibraryOptions);
return NoContent();
}
}
diff --git a/Jellyfin.Api/Models/LibraryStructureDto/LibraryOptionsDto.cs b/Jellyfin.Api/Models/LibraryStructureDto/AddVirtualFolderDto.cs
index a13cb90db..ab68d5223 100644
--- a/Jellyfin.Api/Models/LibraryStructureDto/LibraryOptionsDto.cs
+++ b/Jellyfin.Api/Models/LibraryStructureDto/AddVirtualFolderDto.cs
@@ -3,13 +3,13 @@
namespace Jellyfin.Api.Models.LibraryStructureDto
{
/// <summary>
- /// Library options dto.
+ /// Add virtual folder dto.
/// </summary>
- public class LibraryOptionsDto
+ public class AddVirtualFolderDto
{
/// <summary>
/// Gets or sets library options.
/// </summary>
public LibraryOptions? LibraryOptions { get; set; }
}
-} \ No newline at end of file
+}
diff --git a/Jellyfin.Api/Models/LibraryStructureDto/UpdateLibraryOptionsDto.cs b/Jellyfin.Api/Models/LibraryStructureDto/UpdateLibraryOptionsDto.cs
new file mode 100644
index 000000000..c78ed51f7
--- /dev/null
+++ b/Jellyfin.Api/Models/LibraryStructureDto/UpdateLibraryOptionsDto.cs
@@ -0,0 +1,21 @@
+using System;
+using MediaBrowser.Model.Configuration;
+
+namespace Jellyfin.Api.Models.LibraryStructureDto
+{
+ /// <summary>
+ /// Update library options dto.
+ /// </summary>
+ public class UpdateLibraryOptionsDto
+ {
+ /// <summary>
+ /// Gets or sets the library item id.
+ /// </summary>
+ public Guid Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets library options.
+ /// </summary>
+ public LibraryOptions? LibraryOptions { get; set; }
+ }
+}
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 0fd599cfc..0160a05f9 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -18,6 +18,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Controllers;
using Jellyfin.Server.Formatters;
using Jellyfin.Server.Models;
+using MediaBrowser.Common;
using MediaBrowser.Common.Json;
using MediaBrowser.Model.Entities;
using Microsoft.AspNetCore.Authentication;
@@ -135,10 +136,11 @@ namespace Jellyfin.Server.Extensions
/// </summary>
/// <param name="serviceCollection">The service collection.</param>
/// <param name="baseUrl">The base url for the API.</param>
+ /// <param name="pluginAssemblies">An IEnumberable containing all plugin assemblies with API controllers.</param>
/// <returns>The MVC builder.</returns>
- public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl)
+ public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl, IEnumerable<Assembly> pluginAssemblies)
{
- return serviceCollection
+ IMvcBuilder mvcBuilder = serviceCollection
.AddCors(options =>
{
options.AddPolicy(ServerCorsPolicy.DefaultPolicyName, ServerCorsPolicy.DefaultPolicy);
@@ -179,8 +181,14 @@ namespace Jellyfin.Server.Extensions
// From JsonDefaults.PascalCase
options.JsonSerializerOptions.PropertyNamingPolicy = jsonOptions.PropertyNamingPolicy;
- })
- .AddControllersAsServices();
+ });
+
+ foreach (Assembly pluginAssembly in pluginAssemblies)
+ {
+ mvcBuilder.AddApplicationPart(pluginAssembly);
+ }
+
+ return mvcBuilder.AddControllersAsServices();
}
/// <summary>
@@ -197,7 +205,7 @@ namespace Jellyfin.Server.Extensions
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header,
- Name = "X-Emby-Token",
+ Name = "X-Emby-Authorization",
Description = "API key header parameter"
});
diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs
index d0dd183c6..cbc1c040c 100644
--- a/Jellyfin.Server/Startup.cs
+++ b/Jellyfin.Server/Startup.cs
@@ -1,9 +1,12 @@
using System;
using System.ComponentModel;
+using System.Net.Http.Headers;
using Jellyfin.Api.TypeConverters;
using Jellyfin.Server.Extensions;
using Jellyfin.Server.Middleware;
using Jellyfin.Server.Models;
+using MediaBrowser.Common;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Builder;
@@ -20,14 +23,17 @@ namespace Jellyfin.Server
public class Startup
{
private readonly IServerConfigurationManager _serverConfigurationManager;
+ private readonly IApplicationHost _applicationHost;
/// <summary>
/// Initializes a new instance of the <see cref="Startup" /> class.
/// </summary>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
- public Startup(IServerConfigurationManager serverConfigurationManager)
+ /// <param name="applicationHost">The application host.</param>
+ public Startup(IServerConfigurationManager serverConfigurationManager, IApplicationHost applicationHost)
{
_serverConfigurationManager = serverConfigurationManager;
+ _applicationHost = applicationHost;
}
/// <summary>
@@ -38,7 +44,7 @@ namespace Jellyfin.Server
{
services.AddResponseCompression();
services.AddHttpContextAccessor();
- services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'));
+ services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'), _applicationHost.GetApiPluginAssemblies());
services.AddJellyfinApiSwagger();
@@ -46,7 +52,21 @@ namespace Jellyfin.Server
services.AddCustomAuthentication();
services.AddJellyfinApiAuthorization();
- services.AddHttpClient();
+
+ var productHeader = new ProductInfoHeaderValue(_applicationHost.Name.Replace(' ', '-'), _applicationHost.ApplicationVersionString);
+ services
+ .AddHttpClient(NamedClient.Default, c =>
+ {
+ c.DefaultRequestHeaders.UserAgent.Add(productHeader);
+ })
+ .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler());
+
+ services.AddHttpClient(NamedClient.MusicBrainz, c =>
+ {
+ c.DefaultRequestHeaders.UserAgent.Add(productHeader);
+ c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_applicationHost.ApplicationUserAgentAddress})"));
+ })
+ .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler());
}
/// <summary>
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index 7a76be722..849037ac4 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Common.Plugins;
using Microsoft.Extensions.DependencyInjection;
@@ -77,6 +78,12 @@ namespace MediaBrowser.Common
IReadOnlyList<IPlugin> Plugins { get; }
/// <summary>
+ /// Gets all plugin assemblies which implement a custom rest api.
+ /// </summary>
+ /// <returns>An <see cref="IEnumerable{Assembly}"/> containing the plugin assemblies.</returns>
+ IEnumerable<Assembly> GetApiPluginAssemblies();
+
+ /// <summary>
/// Notifies the pending restart.
/// </summary>
void NotifyPendingRestart();
diff --git a/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs b/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs
new file mode 100644
index 000000000..e189d6e70
--- /dev/null
+++ b/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs
@@ -0,0 +1,20 @@
+using System.Net;
+using System.Net.Http;
+
+namespace MediaBrowser.Common.Net
+{
+ /// <summary>
+ /// Default http client handler.
+ /// </summary>
+ public class DefaultHttpClientHandler : HttpClientHandler
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DefaultHttpClientHandler"/> class.
+ /// </summary>
+ public DefaultHttpClientHandler()
+ {
+ // TODO change to DecompressionMethods.All with .NET5
+ AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
+ }
+ }
+}
diff --git a/MediaBrowser.Common/Net/NamedClient.cs b/MediaBrowser.Common/Net/NamedClient.cs
new file mode 100644
index 000000000..0f6161c32
--- /dev/null
+++ b/MediaBrowser.Common/Net/NamedClient.cs
@@ -0,0 +1,18 @@
+namespace MediaBrowser.Common.Net
+{
+ /// <summary>
+ /// Registered http client names.
+ /// </summary>
+ public static class NamedClient
+ {
+ /// <summary>
+ /// Gets the value for the default named http client.
+ /// </summary>
+ public const string Default = nameof(Default);
+
+ /// <summary>
+ /// Gets the value for the MusicBrainz named http client.
+ /// </summary>
+ public const string MusicBrainz = nameof(MusicBrainz);
+ }
+}