1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Mime;
using System.Text.Json;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Models.ConfigurationDtos;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Api;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Branding;
using MediaBrowser.Model.Configuration;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api.Controllers;
/// <summary>
/// Configuration Controller.
/// </summary>
[Route("System")]
[Authorize]
public class ConfigurationController : BaseJellyfinApiController
{
private readonly IServerConfigurationManager _configurationManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.Options;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationController"/> class.
/// </summary>
/// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
public ConfigurationController(
IServerConfigurationManager configurationManager,
IMediaEncoder mediaEncoder)
{
_configurationManager = configurationManager;
_mediaEncoder = mediaEncoder;
}
/// <summary>
/// Gets application configuration.
/// </summary>
/// <response code="200">Application configuration returned.</response>
/// <returns>Application configuration.</returns>
[HttpGet("Configuration")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<ServerConfiguration> GetConfiguration()
{
return _configurationManager.Configuration;
}
/// <summary>
/// Updates application configuration.
/// </summary>
/// <param name="configuration">Configuration.</param>
/// <response code="204">Configuration updated.</response>
/// <returns>Update status.</returns>
[HttpPost("Configuration")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateConfiguration([FromBody, Required] ServerConfiguration configuration)
{
_configurationManager.ReplaceConfiguration(configuration);
return NoContent();
}
/// <summary>
/// Gets a named configuration.
/// </summary>
/// <param name="key">Configuration key.</param>
/// <response code="200">Configuration returned.</response>
/// <returns>Configuration.</returns>
[HttpGet("Configuration/{key}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesFile(MediaTypeNames.Application.Json)]
public ActionResult<object> GetNamedConfiguration([FromRoute, Required] string key)
{
return _configurationManager.GetConfiguration(key);
}
/// <summary>
/// Updates named configuration.
/// </summary>
/// <param name="key">Configuration key.</param>
/// <param name="configuration">Configuration.</param>
/// <response code="204">Named configuration updated.</response>
/// <returns>Update status.</returns>
[HttpPost("Configuration/{key}")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateNamedConfiguration([FromRoute, Required] string key, [FromBody, Required] JsonDocument configuration)
{
var configurationType = _configurationManager.GetConfigurationType(key);
var deserializedConfiguration = configuration.Deserialize(configurationType, _serializerOptions);
if (deserializedConfiguration is null)
{
throw new ArgumentException("Body doesn't contain a valid configuration");
}
_configurationManager.SaveConfiguration(key, deserializedConfiguration);
return NoContent();
}
/// <summary>
/// Gets a default MetadataOptions object.
/// </summary>
/// <response code="200">Metadata options returned.</response>
/// <returns>Default MetadataOptions.</returns>
[HttpGet("Configuration/MetadataOptions/Default")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<MetadataOptions> GetDefaultMetadataOptions()
{
return new MetadataOptions();
}
/// <summary>
/// Updates branding configuration.
/// </summary>
/// <param name="configuration">Branding configuration.</param>
/// <response code="204">Branding configuration updated.</response>
/// <returns>Update status.</returns>
[HttpPost("Configuration/Branding")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateBrandingConfiguration([FromBody, Required] BrandingOptionsDto configuration)
{
// Get the current branding configuration to preserve SplashscreenLocation
var currentBranding = (BrandingOptions)_configurationManager.GetConfiguration("branding");
// Update only the properties from BrandingOptionsDto
currentBranding.LoginDisclaimer = configuration.LoginDisclaimer;
currentBranding.CustomCss = configuration.CustomCss;
currentBranding.SplashscreenEnabled = configuration.SplashscreenEnabled;
_configurationManager.SaveConfiguration("branding", currentBranding);
return NoContent();
}
/// <summary>
/// Updates the path to the media encoder.
/// </summary>
/// <param name="mediaEncoderPath">Media encoder path form body.</param>
/// <response code="204">Media encoder path updated.</response>
/// <returns>Status.</returns>
[Obsolete("This endpoint is obsolete.")]
[ApiExplorerSettings(IgnoreApi = true)]
[HttpPost("MediaEncoder/Path")]
[Authorize(Policy = Policies.FirstTimeSetupOrElevated)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateMediaEncoderPath([FromBody, Required] MediaEncoderPathDto mediaEncoderPath)
{
// API ENDPOINT DISABLED (NOOP) FOR SECURITY PURPOSES
// _mediaEncoder.UpdateEncoderPath(mediaEncoderPath.Path, mediaEncoderPath.PathType);
return NoContent();
}
}
|