diff --git a/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs
new file mode 100644
index 0000000000..3adb700eb5
--- /dev/null
+++ b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs
@@ -0,0 +1,18 @@
+namespace Jellyfin.Api.Attributes
+{
+ ///
+ /// Produces file attribute of "image/*".
+ ///
+ public class ProducesAudioFileAttribute : ProducesFileAttribute
+ {
+ private const string ContentType = "audio/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesAudioFileAttribute()
+ : base(ContentType)
+ {
+ }
+ }
+}
diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs
new file mode 100644
index 0000000000..62a576ede2
--- /dev/null
+++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Jellyfin.Api.Attributes
+{
+ ///
+ /// Internal produces image attribute.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ public class ProducesFileAttribute : Attribute
+ {
+ private readonly string[] _contentTypes;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Content types this endpoint produces.
+ public ProducesFileAttribute(params string[] contentTypes)
+ {
+ _contentTypes = contentTypes;
+ }
+
+ ///
+ /// Gets the configured content types.
+ ///
+ /// the configured content types.
+ public string[] GetContentTypes() => _contentTypes;
+ }
+}
diff --git a/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs
new file mode 100644
index 0000000000..e158136762
--- /dev/null
+++ b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs
@@ -0,0 +1,18 @@
+namespace Jellyfin.Api.Attributes
+{
+ ///
+ /// Produces file attribute of "image/*".
+ ///
+ public class ProducesImageFileAttribute : ProducesFileAttribute
+ {
+ private const string ContentType = "image/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesImageFileAttribute()
+ : base(ContentType)
+ {
+ }
+ }
+}
diff --git a/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs
new file mode 100644
index 0000000000..5d928ab914
--- /dev/null
+++ b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs
@@ -0,0 +1,18 @@
+namespace Jellyfin.Api.Attributes
+{
+ ///
+ /// Produces file attribute of "image/*".
+ ///
+ public class ProducesPlaylistFileAttribute : ProducesFileAttribute
+ {
+ private const string ContentType = "application/x-mpegURL";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesPlaylistFileAttribute()
+ : base(ContentType)
+ {
+ }
+ }
+}
diff --git a/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs
new file mode 100644
index 0000000000..d8b2856dca
--- /dev/null
+++ b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs
@@ -0,0 +1,18 @@
+namespace Jellyfin.Api.Attributes
+{
+ ///
+ /// Produces file attribute of "video/*".
+ ///
+ public class ProducesVideoFileAttribute : ProducesFileAttribute
+ {
+ private const string ContentType = "video/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesVideoFileAttribute()
+ : base(ContentType)
+ {
+ }
+ }
+}
diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index 802cd026e0..48fd198b5d 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Controller.MediaEncoding;
@@ -88,6 +89,7 @@ namespace Jellyfin.Api.Controllers
[HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")]
[HttpHead("{itemId}/stream", Name = "HeadAudioStream")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesAudioFile]
public async Task GetAudioStream(
[FromRoute] Guid itemId,
[FromRoute] string? container,
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index 20fb0ec875..606e27970a 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -1,6 +1,8 @@
using System.ComponentModel.DataAnnotations;
+using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
+using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Models.ConfigurationDtos;
using MediaBrowser.Common.Json;
@@ -73,6 +75,7 @@ namespace Jellyfin.Api.Controllers
/// Configuration.
[HttpGet("Configuration/{key}")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesFile(MediaTypeNames.Application.Json)]
public ActionResult