aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api')
-rw-r--r--Jellyfin.Api/Controllers/ActivityLogController.cs20
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs38
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs5
-rw-r--r--Jellyfin.Api/Helpers/MediaInfoHelper.cs2
-rw-r--r--Jellyfin.Api/Helpers/TranscodingJobHelper.cs5
-rw-r--r--Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs64
-rw-r--r--Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinderProvider.cs29
-rw-r--r--Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs14
-rw-r--r--Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs14
-rw-r--r--Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs9
10 files changed, 153 insertions, 47 deletions
diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs
index a07cea9c0..b429cebec 100644
--- a/Jellyfin.Api/Controllers/ActivityLogController.cs
+++ b/Jellyfin.Api/Controllers/ActivityLogController.cs
@@ -1,7 +1,7 @@
using System;
-using System.Linq;
+using System.Threading.Tasks;
using Jellyfin.Api.Constants;
-using Jellyfin.Data.Entities;
+using Jellyfin.Data.Queries;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
@@ -39,19 +39,19 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
[HttpGet("Entries")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<ActivityLogEntry>> GetLogEntries(
+ public async Task<ActionResult<QueryResult<ActivityLogEntry>>> GetLogEntries(
[FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] DateTime? minDate,
[FromQuery] bool? hasUserId)
{
- var filterFunc = new Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>>(
- entries => entries.Where(entry => entry.DateCreated >= minDate
- && (!hasUserId.HasValue || (hasUserId.Value
- ? entry.UserId != Guid.Empty
- : entry.UserId == Guid.Empty))));
-
- return _activityManager.GetPagedResult(filterFunc, startIndex, limit);
+ return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
+ {
+ StartIndex = startIndex,
+ Limit = limit,
+ MinDate = minDate,
+ HasUserId = hasUserId
+ }).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index 7afec1219..05efe2355 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -333,7 +333,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
/// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
- /// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
+ /// <param name="format">Optional. The <see cref="ImageFormat"/> of the returned image.</param>
/// <param name="addPlayedIndicator">Optional. Add a played indicator.</param>
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
@@ -364,7 +364,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? quality,
[FromQuery] string? tag,
[FromQuery] bool? cropWhitespace,
- [FromQuery] string? format,
+ [FromQuery] ImageFormat? format,
[FromQuery] bool? addPlayedIndicator,
[FromQuery] double? percentPlayed,
[FromQuery] int? unplayedCount,
@@ -443,7 +443,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? quality,
[FromRoute, Required] string tag,
[FromQuery] bool? cropWhitespace,
- [FromRoute, Required] string format,
+ [FromRoute, Required] ImageFormat format,
[FromQuery] bool? addPlayedIndicator,
[FromRoute, Required] double percentPlayed,
[FromRoute, Required] int unplayedCount,
@@ -516,7 +516,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromQuery] string tag,
- [FromQuery] string format,
+ [FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -595,7 +595,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromQuery] string tag,
- [FromQuery] string format,
+ [FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -674,7 +674,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromQuery] string tag,
- [FromQuery] string format,
+ [FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -753,7 +753,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromQuery] string tag,
- [FromQuery] string format,
+ [FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -832,7 +832,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromRoute, Required] string tag,
- [FromRoute, Required] string format,
+ [FromRoute, Required] ImageFormat format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -911,7 +911,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] Guid userId,
[FromRoute, Required] ImageType imageType,
[FromQuery] string? tag,
- [FromQuery] string? format,
+ [FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] double? percentPlayed,
@@ -1038,7 +1038,7 @@ namespace Jellyfin.Api.Controllers
ImageType imageType,
int? imageIndex,
string? tag,
- string? format,
+ ImageFormat? format,
int? maxWidth,
int? maxHeight,
double? percentPlayed,
@@ -1128,12 +1128,11 @@ namespace Jellyfin.Api.Controllers
isHeadRequest).ConfigureAwait(false);
}
- private ImageFormat[] GetOutputFormats(string? format)
+ private ImageFormat[] GetOutputFormats(ImageFormat? format)
{
- if (!string.IsNullOrWhiteSpace(format)
- && Enum.TryParse(format, true, out ImageFormat parsedFormat))
+ if (format.HasValue)
{
- return new[] { parsedFormat };
+ return new[] { format.Value };
}
return GetClientSupportedFormats();
@@ -1157,7 +1156,7 @@ namespace Jellyfin.Api.Controllers
var acceptParam = Request.Query[HeaderNames.Accept];
- var supportsWebP = SupportsFormat(supportedFormats, acceptParam, "webp", false);
+ var supportsWebP = SupportsFormat(supportedFormats, acceptParam, ImageFormat.Webp, false);
if (!supportsWebP)
{
@@ -1179,7 +1178,7 @@ namespace Jellyfin.Api.Controllers
formats.Add(ImageFormat.Jpg);
formats.Add(ImageFormat.Png);
- if (SupportsFormat(supportedFormats, acceptParam, "gif", true))
+ if (SupportsFormat(supportedFormats, acceptParam, ImageFormat.Gif, true))
{
formats.Add(ImageFormat.Gif);
}
@@ -1187,9 +1186,10 @@ namespace Jellyfin.Api.Controllers
return formats.ToArray();
}
- private bool SupportsFormat(IReadOnlyCollection<string> requestAcceptTypes, string acceptParam, string format, bool acceptAll)
+ private bool SupportsFormat(IReadOnlyCollection<string> requestAcceptTypes, string acceptParam, ImageFormat format, bool acceptAll)
{
- var mimeType = "image/" + format;
+ var normalized = format.ToString().ToLowerInvariant();
+ var mimeType = "image/" + normalized;
if (requestAcceptTypes.Contains(mimeType))
{
@@ -1201,7 +1201,7 @@ namespace Jellyfin.Api.Controllers
return true;
}
- return string.Equals(acceptParam, format, StringComparison.OrdinalIgnoreCase);
+ return string.Equals(acceptParam, normalized, StringComparison.OrdinalIgnoreCase);
}
private async Task<ActionResult> GetImageResult(
diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
index 39bf6e6dc..565670962 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
+using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library;
@@ -378,7 +379,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult PostCapabilities(
[FromQuery] string? id,
[FromQuery] string? playableMediaTypes,
- [FromQuery] string? supportedCommands,
+ [FromQuery] GeneralCommandType[] supportedCommands,
[FromQuery] bool supportsMediaControl = false,
[FromQuery] bool supportsSync = false,
[FromQuery] bool supportsPersistentIdentifier = true)
@@ -391,7 +392,7 @@ namespace Jellyfin.Api.Controllers
_sessionManager.ReportCapabilities(id, new ClientCapabilities
{
PlayableMediaTypes = RequestHelpers.Split(playableMediaTypes, ',', true),
- SupportedCommands = RequestHelpers.Split(supportedCommands, ',', true),
+ SupportedCommands = supportedCommands,
SupportsMediaControl = supportsMediaControl,
SupportsSync = supportsSync,
SupportsPersistentIdentifier = supportsPersistentIdentifier
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index 1207fb513..e78f63b25 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -554,7 +554,7 @@ namespace Jellyfin.Api.Helpers
private long? GetMaxBitrate(long? clientMaxBitrate, User user, string ipAddress)
{
var maxBitrate = clientMaxBitrate;
- var remoteClientMaxBitrate = user?.RemoteClientBitrateLimit ?? 0;
+ var remoteClientMaxBitrate = user.RemoteClientBitrateLimit ?? 0;
if (remoteClientMaxBitrate <= 0)
{
diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
index 64d1227f7..0db1fabff 100644
--- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
+++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
@@ -740,10 +740,7 @@ namespace Jellyfin.Api.Helpers
/// <param name="state">The state.</param>
private void OnFfMpegProcessExited(Process process, TranscodingJobDto job, StreamState state)
{
- if (job != null)
- {
- job.HasExited = true;
- }
+ job.HasExited = true;
_logger.LogDebug("Disposing stream resources");
state.Dispose();
diff --git a/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs b/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs
new file mode 100644
index 000000000..13469194a
--- /dev/null
+++ b/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs
@@ -0,0 +1,64 @@
+using System;
+using System.ComponentModel;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+
+namespace Jellyfin.Api.ModelBinders
+{
+ /// <summary>
+ /// Comma delimited array model binder.
+ /// Returns an empty array of specified type if there is no query parameter.
+ /// </summary>
+ public class CommaDelimitedArrayModelBinder : IModelBinder
+ {
+ /// <inheritdoc/>
+ public Task BindModelAsync(ModelBindingContext bindingContext)
+ {
+ var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
+ var elementType = bindingContext.ModelType.GetElementType();
+ var converter = TypeDescriptor.GetConverter(elementType);
+
+ if (valueProviderResult == ValueProviderResult.None)
+ {
+ return Task.CompletedTask;
+ }
+
+ if (valueProviderResult.Length > 1)
+ {
+ var result = Array.CreateInstance(elementType, valueProviderResult.Length);
+
+ for (int i = 0; i < valueProviderResult.Length; i++)
+ {
+ var value = converter.ConvertFromString(valueProviderResult.Values[i].Trim());
+
+ result.SetValue(value, i);
+ }
+
+ bindingContext.Result = ModelBindingResult.Success(result);
+ }
+ else
+ {
+ var value = valueProviderResult.FirstValue;
+
+ if (value != null)
+ {
+ var values = Array.ConvertAll(
+ value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries),
+ x => converter.ConvertFromString(x?.Trim()));
+
+ var typedValues = Array.CreateInstance(elementType, values.Length);
+ values.CopyTo(typedValues, 0);
+
+ bindingContext.Result = ModelBindingResult.Success(typedValues);
+ }
+ else
+ {
+ var emptyResult = Array.CreateInstance(elementType, 0);
+ bindingContext.Result = ModelBindingResult.Success(emptyResult);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinderProvider.cs b/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinderProvider.cs
new file mode 100644
index 000000000..b9785a73b
--- /dev/null
+++ b/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinderProvider.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+
+namespace Jellyfin.Api.ModelBinders
+{
+ /// <summary>
+ /// Comma delimited array model binder provider.
+ /// </summary>
+ public class CommaDelimitedArrayModelBinderProvider : IModelBinderProvider
+ {
+ private readonly IModelBinder _binder;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CommaDelimitedArrayModelBinderProvider"/> class.
+ /// </summary>
+ public CommaDelimitedArrayModelBinderProvider()
+ {
+ _binder = new CommaDelimitedArrayModelBinder();
+ }
+
+ /// <inheritdoc />
+ public IModelBinder? GetBinder(ModelBinderProviderContext context)
+ {
+ return context.Metadata.ModelType.IsArray ? _binder : null;
+ }
+ }
+}
diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
index 849b3b709..77d55828d 100644
--- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.WebSocketListeners
@@ -29,11 +30,14 @@ namespace Jellyfin.Api.WebSocketListeners
_activityManager.EntryCreated += OnEntryCreated;
}
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- protected override string Name => "ActivityLogEntry";
+ /// <inheritdoc />
+ protected override SessionMessageType Type => SessionMessageType.ActivityLogEntry;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StartType => SessionMessageType.ActivityLogEntryStart;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StopType => SessionMessageType.ActivityLogEntryStop;
/// <summary>
/// Gets the data to send.
diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
index 8a966c137..80314b923 100644
--- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Session;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
@@ -33,11 +34,14 @@ namespace Jellyfin.Api.WebSocketListeners
_taskManager.TaskCompleted += OnTaskCompleted;
}
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- protected override string Name => "ScheduledTasksInfo";
+ /// <inheritdoc />
+ protected override SessionMessageType Type => SessionMessageType.ScheduledTasksInfo;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StartType => SessionMessageType.ScheduledTasksInfoStart;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StopType => SessionMessageType.ScheduledTasksInfoStop;
/// <summary>
/// Gets the data to send.
diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
index 1fb5dc412..1cf43a005 100644
--- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.WebSocketListeners
@@ -34,7 +35,13 @@ namespace Jellyfin.Api.WebSocketListeners
}
/// <inheritdoc />
- protected override string Name => "Sessions";
+ protected override SessionMessageType Type => SessionMessageType.Sessions;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StartType => SessionMessageType.SessionsStart;
+
+ /// <inheritdoc />
+ protected override SessionMessageType StopType => SessionMessageType.SessionsStop;
/// <summary>
/// Gets the data to send.