aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/th.json5
-rw-r--r--Emby.Server.Implementations/Plugins/PluginManager.cs4
-rw-r--r--Jellyfin.Api/Controllers/AudioController.cs8
-rw-r--r--Jellyfin.Api/Controllers/DashboardController.cs4
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs48
-rw-r--r--Jellyfin.Api/Controllers/HlsSegmentController.cs4
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs16
-rw-r--r--Jellyfin.Api/Controllers/ItemUpdateController.cs2
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs2
-rw-r--r--Jellyfin.Api/Controllers/LibraryStructureController.cs13
-rw-r--r--Jellyfin.Api/Controllers/PlaystateController.cs20
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs2
-rw-r--r--Jellyfin.Api/Controllers/VideoHlsController.cs8
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs16
-rw-r--r--Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs3
-rw-r--r--Jellyfin.Api/Models/LibraryStructureDto/UpdateMediaPathRequestDto.cs23
-rw-r--r--Jellyfin.Networking/Manager/NetworkManager.cs21
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs1
-rw-r--r--Jellyfin.Server/Program.cs2
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs23
-rw-r--r--MediaBrowser.Common/Json/JsonDefaults.cs1
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj2
-rw-r--r--MediaBrowser.Common/Plugins/IPluginManager.cs2
-rw-r--r--MediaBrowser.Model/Entities/ProviderIdsExtensions.cs12
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs9
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs3
-rw-r--r--RSSDP/SsdpDeviceLocator.cs14
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs36
-rw-r--r--tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs29
34 files changed, 235 insertions, 112 deletions
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index e4923b9eb0..5abc1bc134 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -132,7 +132,7 @@ namespace Emby.Dlna.PlayTo
private async void OnDeviceMediaChanged(object sender, MediaChangedEventArgs e)
{
- if (_disposed)
+ if (_disposed || string.IsNullOrEmpty(e.OldMediaInfo.Url))
{
return;
}
diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json
index 71dd2c7a30..5bf58baf8c 100644
--- a/Emby.Server.Implementations/Localization/Core/th.json
+++ b/Emby.Server.Implementations/Localization/Core/th.json
@@ -50,7 +50,7 @@
"HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
"HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
"HeaderContinueWatching": "ดูต่อ",
- "HeaderAlbumArtists": "อัลบั้มศิลปิน",
+ "HeaderAlbumArtists": "ศิลปินอัลบั้ม",
"Genres": "ประเภท",
"Folders": "โฟลเดอร์",
"Favorites": "รายการโปรด",
@@ -112,5 +112,6 @@
"System": "ระบบ",
"Sync": "ซิงค์",
"SubtitleDownloadFailureFromForItem": "ไม่สามารถดาวน์โหลดคำบรรยายจาก {0} สำหรับ {1} ได้",
- "StartupEmbyServerIsLoading": "กำลังโหลดเซิร์ฟเวอร์ Jellyfin โปรดลองอีกครั้งในอีกสักครู่"
+ "StartupEmbyServerIsLoading": "กำลังโหลดเซิร์ฟเวอร์ Jellyfin โปรดลองอีกครั้งในอีกสักครู่",
+ "Default": "ค่าเริ่มต้น"
}
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 7bc9f0a7e2..c579fc8cba 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.Plugins
private readonly ILogger<PluginManager> _logger;
private readonly IApplicationHost _appHost;
private readonly ServerConfiguration _config;
- private readonly IList<LocalPlugin> _plugins;
+ private readonly List<LocalPlugin> _plugins;
private readonly Version _minimumVersion;
private IHttpClientFactory? _httpClientFactory;
@@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.Plugins
/// <summary>
/// Gets the Plugins.
/// </summary>
- public IList<LocalPlugin> Plugins => _plugins;
+ public IReadOnlyList<LocalPlugin> Plugins => _plugins;
/// <summary>
/// Returns all the assemblies.
diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index 616fe5b91f..8b1813b200 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -122,7 +122,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -174,7 +174,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -287,7 +287,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -339,7 +339,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs
index a2c2ecd666..445733c24d 100644
--- a/Jellyfin.Api/Controllers/DashboardController.cs
+++ b/Jellyfin.Api/Controllers/DashboardController.cs
@@ -95,9 +95,9 @@ namespace Jellyfin.Api.Controllers
return GetPluginPages(plugin).Select(i => new ConfigurationPageInfo(plugin.Instance, i.Item1));
}
- private IEnumerable<Tuple<PluginPageInfo, IPlugin>> GetPluginPages(LocalPlugin? plugin)
+ private IEnumerable<Tuple<PluginPageInfo, IPlugin>> GetPluginPages(LocalPlugin plugin)
{
- if (plugin?.Instance is not IHasWebPages hasWebPages)
+ if (plugin.Instance is not IHasWebPages hasWebPages)
{
return Enumerable.Empty<Tuple<PluginPageInfo, IPlugin>>();
}
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index e375645cf0..f6c23c5aad 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -203,7 +203,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -218,7 +218,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] bool enableAdaptiveBitrateStreaming = true)
{
@@ -255,7 +255,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -270,7 +270,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions,
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
};
@@ -370,7 +370,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -385,7 +385,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] bool enableAdaptiveBitrateStreaming = true)
{
@@ -422,7 +422,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -437,7 +437,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions,
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
};
@@ -533,7 +533,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -548,7 +548,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
var cancellationTokenSource = new CancellationTokenSource();
@@ -585,7 +585,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -600,7 +600,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
};
@@ -698,7 +698,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -713,7 +713,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
var cancellationTokenSource = new CancellationTokenSource();
@@ -750,7 +750,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -765,7 +765,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
};
@@ -868,7 +868,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -883,7 +883,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
var streamingRequest = new VideoRequestDto
@@ -920,7 +920,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -935,7 +935,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
};
@@ -1040,7 +1040,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -1055,7 +1055,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
var streamingRequest = new StreamingRequestDto
@@ -1092,7 +1092,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -1107,7 +1107,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
};
diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs
index 25abe73ed0..d0ed45acb4 100644
--- a/Jellyfin.Api/Controllers/HlsSegmentController.cs
+++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs
@@ -96,7 +96,9 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("Videos/ActiveEncodings")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult StopEncodingProcess([FromQuery] string deviceId, [FromQuery] string playSessionId)
+ public ActionResult StopEncodingProcess(
+ [FromQuery, Required] string deviceId,
+ [FromQuery, Required] string playSessionId)
{
_transcodingJobHelper.KillTranscodingJobs(deviceId, playSessionId, path => true);
return NoContent();
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index a50d6e46bf..cfc038f237 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -392,7 +392,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] Guid itemId,
[FromRoute, Required] ImageType imageType,
[FromRoute, Required] int imageIndex,
- [FromQuery] int newIndex)
+ [FromQuery, Required] int newIndex)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -741,7 +741,7 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> GetArtistImage(
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -820,7 +820,7 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> GetGenreImage(
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -900,7 +900,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromRoute, Required] int imageIndex,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -978,7 +978,7 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> GetMusicGenreImage(
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -1058,7 +1058,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromRoute, Required] int imageIndex,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -1136,7 +1136,7 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> GetPersonImage(
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -1216,7 +1216,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string name,
[FromRoute, Required] ImageType imageType,
[FromRoute, Required] int imageIndex,
- [FromQuery] string tag,
+ [FromQuery] string? tag,
[FromQuery] ImageFormat? format,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs
index 9e1a398538..a9f4a5a58c 100644
--- a/Jellyfin.Api/Controllers/ItemUpdateController.cs
+++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs
@@ -195,7 +195,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Items/{itemId}/ContentType")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery] string contentType)
+ public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery] string? contentType)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index db4aa96681..3443ebd72f 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -777,7 +777,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<LibraryOptionsResultDto> GetLibraryOptionsInfo(
[FromQuery] string? libraryContentType,
- [FromQuery] bool isNewLibrary)
+ [FromQuery] bool isNewLibrary = false)
{
var result = new LibraryOptionsResultDto();
diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs
index 328efea26e..be9127dd39 100644
--- a/Jellyfin.Api/Controllers/LibraryStructureController.cs
+++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs
@@ -241,23 +241,20 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Updates a media path.
/// </summary>
- /// <param name="name">The name of the library.</param>
- /// <param name="pathInfo">The path info.</param>
+ /// <param name="mediaPathRequestDto">The name of the library and path infos.</param>
/// <returns>A <see cref="NoContentResult"/>.</returns>
/// <response code="204">Media path updated.</response>
/// <exception cref="ArgumentNullException">The name of the library may not be empty.</exception>
[HttpPost("Paths/Update")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult UpdateMediaPath(
- [FromQuery] string? name,
- [FromBody] MediaPathInfo? pathInfo)
+ public ActionResult UpdateMediaPath([FromBody, Required] UpdateMediaPathRequestDto mediaPathRequestDto)
{
- if (string.IsNullOrWhiteSpace(name))
+ if (string.IsNullOrWhiteSpace(mediaPathRequestDto.Name))
{
- throw new ArgumentNullException(nameof(name));
+ throw new ArgumentNullException(nameof(mediaPathRequestDto), "Name must not be null or empty");
}
- _libraryManager.UpdateMediaPath(name, pathInfo);
+ _libraryManager.UpdateMediaPath(mediaPathRequestDto.Name, mediaPathRequestDto.PathInfo);
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs
index ec7b84ff60..f256c8c25c 100644
--- a/Jellyfin.Api/Controllers/PlaystateController.cs
+++ b/Jellyfin.Api/Controllers/PlaystateController.cs
@@ -152,7 +152,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("Sessions/Playing/Ping")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult PingPlaybackSession([FromQuery] string playSessionId)
+ public ActionResult PingPlaybackSession([FromQuery, Required] string playSessionId)
{
_transcodingJobHelper.PingTranscodingJob(playSessionId, null);
return NoContent();
@@ -202,9 +202,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? mediaSourceId,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] PlayMethod playMethod,
+ [FromQuery] PlayMethod? playMethod,
[FromQuery] string? liveStreamId,
- [FromQuery] string playSessionId,
+ [FromQuery] string? playSessionId,
[FromQuery] bool canSeek = false)
{
var playbackStartInfo = new PlaybackStartInfo
@@ -214,7 +214,7 @@ namespace Jellyfin.Api.Controllers
MediaSourceId = mediaSourceId,
AudioStreamIndex = audioStreamIndex,
SubtitleStreamIndex = subtitleStreamIndex,
- PlayMethod = playMethod,
+ PlayMethod = playMethod ?? PlayMethod.Transcode,
PlaySessionId = playSessionId,
LiveStreamId = liveStreamId
};
@@ -254,10 +254,10 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex,
[FromQuery] int? volumeLevel,
- [FromQuery] PlayMethod playMethod,
+ [FromQuery] PlayMethod? playMethod,
[FromQuery] string? liveStreamId,
- [FromQuery] string playSessionId,
- [FromQuery] RepeatMode repeatMode,
+ [FromQuery] string? playSessionId,
+ [FromQuery] RepeatMode? repeatMode,
[FromQuery] bool isPaused = false,
[FromQuery] bool isMuted = false)
{
@@ -271,10 +271,10 @@ namespace Jellyfin.Api.Controllers
AudioStreamIndex = audioStreamIndex,
SubtitleStreamIndex = subtitleStreamIndex,
VolumeLevel = volumeLevel,
- PlayMethod = playMethod,
+ PlayMethod = playMethod ?? PlayMethod.Transcode,
PlaySessionId = playSessionId,
LiveStreamId = liveStreamId,
- RepeatMode = repeatMode
+ RepeatMode = repeatMode ?? RepeatMode.RepeatNone
};
playbackProgressInfo.PlayMethod = ValidatePlayMethod(playbackProgressInfo.PlayMethod, playbackProgressInfo.PlaySessionId);
@@ -352,7 +352,7 @@ namespace Jellyfin.Api.Controllers
return _userDataRepository.GetUserDataDto(item, user);
}
- private PlayMethod ValidatePlayMethod(PlayMethod method, string playSessionId)
+ private PlayMethod ValidatePlayMethod(PlayMethod method, string? playSessionId)
{
if (method == PlayMethod.Transcode)
{
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index 5aa033ccf4..0c2e6f19f1 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -112,7 +112,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? maxAudioSampleRate,
[FromQuery] int? maxAudioBitDepth,
[FromQuery] bool? enableRemoteMedia,
- [FromQuery] bool breakOnNonKeyFrames,
+ [FromQuery] bool breakOnNonKeyFrames = false,
[FromQuery] bool enableRedirection = true)
{
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs
index ba51aa43e2..620eef5680 100644
--- a/Jellyfin.Api/Controllers/VideoHlsController.cs
+++ b/Jellyfin.Api/Controllers/VideoHlsController.cs
@@ -198,7 +198,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -213,7 +213,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
@@ -253,7 +253,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -268,7 +268,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions,
MaxHeight = maxHeight,
MaxWidth = maxWidth,
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 44dc639523..99654e7b0d 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -217,9 +217,7 @@ namespace Jellyfin.Api.Controllers
return BadRequest("Please supply at least two videos to merge.");
}
- var videosWithVersions = items.Where(i => i.MediaSourceCount > 1).ToList();
-
- var primaryVersion = videosWithVersions.FirstOrDefault();
+ var primaryVersion = items.FirstOrDefault(i => i.MediaSourceCount > 1 && string.IsNullOrEmpty(i.PrimaryVersionId));
if (primaryVersion == null)
{
primaryVersion = items
@@ -364,7 +362,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -379,7 +377,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
var isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
@@ -418,7 +416,7 @@ namespace Jellyfin.Api.Controllers
Height = height,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
RequireAvc = requireAvc ?? true,
@@ -433,7 +431,7 @@ namespace Jellyfin.Api.Controllers
TranscodeReasons = transcodeReasons,
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
- Context = context,
+ Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
};
@@ -620,7 +618,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? height,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod subtitleMethod,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
[FromQuery] int? maxRefFrames,
[FromQuery] int? maxVideoBitDepth,
[FromQuery] bool? requireAvc,
@@ -635,7 +633,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext context,
+ [FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
return GetVideoStream(
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index 89d36ab09f..f828b1d9d6 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -107,7 +107,8 @@ namespace Jellyfin.Api.Helpers
// Headers only
if (isHeadRequest)
{
- return new FileContentResult(Array.Empty<byte>(), contentType);
+ httpContext.Response.Headers[HeaderNames.ContentType] = contentType;
+ return new OkResult();
}
var transcodingLock = transcodingJobHelper.GetTranscodingLock(outputPath);
diff --git a/Jellyfin.Api/Models/LibraryStructureDto/UpdateMediaPathRequestDto.cs b/Jellyfin.Api/Models/LibraryStructureDto/UpdateMediaPathRequestDto.cs
new file mode 100644
index 0000000000..fbd4985f9c
--- /dev/null
+++ b/Jellyfin.Api/Models/LibraryStructureDto/UpdateMediaPathRequestDto.cs
@@ -0,0 +1,23 @@
+using System.ComponentModel.DataAnnotations;
+using MediaBrowser.Model.Configuration;
+
+namespace Jellyfin.Api.Models.LibraryStructureDto
+{
+ /// <summary>
+ /// Update library options dto.
+ /// </summary>
+ public class UpdateMediaPathRequestDto
+ {
+ /// <summary>
+ /// Gets or sets the library name.
+ /// </summary>
+ [Required]
+ public string Name { get; set; } = null!;
+
+ /// <summary>
+ /// Gets or sets library folder path information.
+ /// </summary>
+ [Required]
+ public MediaPathInfo PathInfo { get; set; } = null!;
+ }
+}
diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs
index 51fcb6d9a0..d2e9dcf9e6 100644
--- a/Jellyfin.Networking/Manager/NetworkManager.cs
+++ b/Jellyfin.Networking/Manager/NetworkManager.cs
@@ -285,14 +285,25 @@ namespace Jellyfin.Networking.Manager
// No bind address and no exclusions, so listen on all interfaces.
Collection<IPObject> result = new Collection<IPObject>();
- if (IsIP4Enabled)
+ if (IsIP6Enabled && IsIP4Enabled)
+ {
+ // Kestrel source code shows it uses Sockets.DualMode - so this also covers IPAddress.Any
+ result.AddItem(IPAddress.IPv6Any);
+ }
+ else if (IsIP4Enabled)
{
result.AddItem(IPAddress.Any);
}
-
- if (IsIP6Enabled)
+ else if (IsIP6Enabled)
{
- result.AddItem(IPAddress.IPv6Any);
+ // Cannot use IPv6Any as Kestrel will bind to IPv4 addresses.
+ foreach (var iface in _interfaceAddresses)
+ {
+ if (iface.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ result.AddItem(iface.Address);
+ }
+ }
}
return result;
@@ -414,7 +425,7 @@ namespace Jellyfin.Networking.Manager
}
// There isn't any others, so we'll use the loopback.
- result = IsIP6Enabled ? "::" : "127.0.0.1";
+ result = IsIP6Enabled ? "::1" : "127.0.0.1";
_logger.LogWarning("{Source}: GetBindInterface: Loopback {Result} returned.", source, result);
return result;
}
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 77f6695bb7..1828f1a7eb 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -232,7 +232,6 @@ namespace Jellyfin.Server.Extensions
options.JsonSerializerOptions.WriteIndented = jsonOptions.WriteIndented;
options.JsonSerializerOptions.DefaultIgnoreCondition = jsonOptions.DefaultIgnoreCondition;
options.JsonSerializerOptions.NumberHandling = jsonOptions.NumberHandling;
- options.JsonSerializerOptions.PropertyNameCaseInsensitive = jsonOptions.PropertyNameCaseInsensitive;
options.JsonSerializerOptions.Converters.Clear();
foreach (var converter in jsonOptions.Converters)
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index edbb843574..4b0cf70e3c 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -280,7 +280,7 @@ namespace Jellyfin.Server
bool flagged = false;
foreach (IPObject netAdd in addresses)
{
- _logger.LogInformation("Kestrel listening on {0}", netAdd);
+ _logger.LogInformation("Kestrel listening on {Address}", netAdd.Address == IPAddress.IPv6Any ? "All Addresses" : netAdd);
options.Listen(netAdd.Address, appHost.HttpPort);
if (appHost.ListenWithHttps)
{
diff --git a/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs b/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
new file mode 100644
index 0000000000..f69e868cc4
--- /dev/null
+++ b/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Common.Json.Converters
+{
+ /// <summary>
+ /// Converts a Version object or value to/from JSON.
+ /// </summary>
+ /// <remarks>
+ /// Required to send <see cref="Version"/> as a string instead of an object.
+ /// </remarks>
+ public class JsonVersionConverter : JsonConverter<Version>
+ {
+ /// <inheritdoc />
+ public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => new Version(reader.GetString());
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options)
+ => writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs
index a3999e7e25..2ef24a884a 100644
--- a/MediaBrowser.Common/Json/JsonDefaults.cs
+++ b/MediaBrowser.Common/Json/JsonDefaults.cs
@@ -35,6 +35,7 @@ namespace MediaBrowser.Common.Json
{
new JsonGuidConverter(),
new JsonNullableGuidConverter(),
+ new JsonVersionConverter(),
new JsonStringEnumConverter(),
new JsonNullableStructConverterFactory(),
new JsonBoolNumberConverter(),
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index e469436a93..8bb30c565b 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -14,7 +14,7 @@
</PropertyGroup>
<ItemGroup>
- <FrameworkReference Include="Microsoft.AspNetCore.App"/>
+ <FrameworkReference Include="Microsoft.AspNetCore.App" />
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
</ItemGroup>
diff --git a/MediaBrowser.Common/Plugins/IPluginManager.cs b/MediaBrowser.Common/Plugins/IPluginManager.cs
index fc2fcb5179..f9a8fb6f7a 100644
--- a/MediaBrowser.Common/Plugins/IPluginManager.cs
+++ b/MediaBrowser.Common/Plugins/IPluginManager.cs
@@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Plugins
/// <summary>
/// Gets the Plugins.
/// </summary>
- IList<LocalPlugin> Plugins { get; }
+ IReadOnlyList<LocalPlugin> Plugins { get; }
/// <summary>
/// Creates the plugins.
diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
index bde5a1da19..09d14dc6a4 100644
--- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
+++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Model.Entities
throw new ArgumentNullException(nameof(instance));
}
- return instance.ProviderIds?.ContainsKey(name) ?? false;
+ return instance.TryGetProviderId(name, out _);
}
/// <summary>
@@ -56,7 +56,15 @@ namespace MediaBrowser.Model.Entities
return false;
}
- return instance.ProviderIds.TryGetValue(name, out id);
+ var foundProviderId = instance.ProviderIds.TryGetValue(name, out id);
+ // This occurs when searching with Identify (and possibly in other places)
+ if (string.IsNullOrEmpty(id))
+ {
+ id = null;
+ foundProviderId = false;
+ }
+
+ return foundProviderId;
}
/// <summary>
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 913f14d9b8..d581dd4341 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -242,6 +242,7 @@ namespace MediaBrowser.Providers.Manager
languages.Add(preferredLanguage);
}
+ // TODO include [query.IncludeAllLanguages] as an argument to the providers
var tasks = providers.Select(i => GetImages(item, i, languages, cancellationToken, query.ImageType));
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
@@ -869,14 +870,14 @@ namespace MediaBrowser.Providers.Manager
}
}
}
- catch (Exception)
+#pragma warning disable CA1031 // do not catch general exception types
+ catch (Exception ex)
+#pragma warning restore CA1031 // do not catch general exception types
{
- // Logged at lower levels
+ _logger.LogError(ex, "Provider {ProviderName} failed to retrieve search results", provider.Name);
}
}
- // _logger.LogDebug("Returning search results {0}", _json.SerializeToString(resultList));
-
return resultList;
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
index df1e12240d..5ad61c567f 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
@@ -58,7 +58,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
var language = item.GetPreferredMetadataLanguage();
- var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken).ConfigureAwait(false);
+ // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
+ var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, null, null, cancellationToken).ConfigureAwait(false);
if (collection?.Images == null)
{
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs
index dac9e961c6..f34d689c1a 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs
@@ -73,8 +73,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
return Enumerable.Empty<RemoteImageInfo>();
}
+ // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var movie = await _tmdbClientManager
- .GetMovieAsync(movieTmdbId, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken)
+ .GetMovieAsync(movieTmdbId, null, null, cancellationToken)
.ConfigureAwait(false);
if (movie?.Images == null)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
index 3b7a0b254e..d923366242 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
@@ -63,8 +63,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var language = item.GetPreferredMetadataLanguage();
+ // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken)
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, null, null, cancellationToken)
.ConfigureAwait(false);
var stills = episodeResult?.Images?.Stills;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
index f4ed480aef..0d23c7872f 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
@@ -52,8 +52,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var language = item.GetPreferredMetadataLanguage();
+ // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var seasonResult = await _tmdbClientManager
- .GetSeasonAsync(seriesTmdbId, season.IndexNumber.Value, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken)
+ .GetSeasonAsync(seriesTmdbId, season.IndexNumber.Value, null, null, cancellationToken)
.ConfigureAwait(false);
var posters = seasonResult?.Images?.Posters;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
index d0c6b8b886..a96fc8ed63 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
@@ -59,8 +59,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var language = item.GetPreferredMetadataLanguage();
+ // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var series = await _tmdbClientManager
- .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken)
+ .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), null, null, cancellationToken)
.ConfigureAwait(false);
if (series?.Images == null)
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index bfad6de97a..0cdc5ce3db 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -97,6 +97,11 @@ namespace Rssdp.Infrastructure
private async void OnBroadcastTimerCallback(object state)
{
+ if (IsDisposed)
+ {
+ return;
+ }
+
StartListeningForNotifications();
RemoveExpiredDevicesFromCache();
@@ -180,8 +185,6 @@ namespace Rssdp.Infrastructure
/// <exception cref="ObjectDisposedException">Throw if the <see cref="DisposableManagedObjectBase.IsDisposed"/> ty is true.</exception>
public void StartListeningForNotifications()
{
- ThrowIfDisposed();
-
_CommunicationsServer.RequestReceived -= CommsServer_RequestReceived;
_CommunicationsServer.RequestReceived += CommsServer_RequestReceived;
_CommunicationsServer.BeginListeningForBroadcasts();
@@ -353,7 +356,7 @@ namespace Rssdp.Infrastructure
{
return;
}
-
+
var location = GetFirstHeaderUriValue("Location", message);
if (location != null)
{
@@ -515,11 +518,6 @@ namespace Rssdp.Infrastructure
private void RemoveExpiredDevicesFromCache()
{
- if (this.IsDisposed)
- {
- return;
- }
-
DiscoveredSsdpDevice[] expiredDevices = null;
lock (_Devices)
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs
new file mode 100644
index 0000000000..f2cefdbf8e
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Text.Json;
+using MediaBrowser.Common.Json.Converters;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Json
+{
+ public class JsonVersionConverterTests
+ {
+ private readonly JsonSerializerOptions _options;
+
+ public JsonVersionConverterTests()
+ {
+ _options = new JsonSerializerOptions();
+ _options.Converters.Add(new JsonVersionConverter());
+ }
+
+ [Fact]
+ public void Deserialize_Version_Success()
+ {
+ var input = "\"1.025.222\"";
+ var output = new Version(1, 25, 222);
+ var deserializedInput = JsonSerializer.Deserialize<Version>(input, _options);
+ Assert.Equal(output, deserializedInput);
+ }
+
+ [Fact]
+ public void Serialize_Version_Success()
+ {
+ var input = new Version(1, 09, 59);
+ var output = "\"1.9.59\"";
+ var serializedInput = JsonSerializer.Serialize(input, _options);
+ Assert.Equal(output, serializedInput);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs b/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs
index 2b2414ef1b..a1ace84769 100644
--- a/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs
+++ b/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs
@@ -18,7 +18,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void HasProviderId_NullProvider_False()
{
- var nullProvider = new ProviderIdsExtensionsTestsObject()
+ var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -48,6 +48,15 @@ namespace Jellyfin.Model.Tests.Entities
}
[Fact]
+ public void HasProviderId_FoundNameEmptyValue_False()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.ProviderIds[MetadataProvider.Imdb.ToString()] = string.Empty;
+
+ Assert.False(provider.HasProviderId(MetadataProvider.Imdb));
+ }
+
+ [Fact]
public void GetProviderId_NullInstance_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ProviderIdsExtensions.GetProviderId(null!, MetadataProvider.Imdb));
@@ -68,7 +77,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void GetProviderId_NullProvider_Null()
{
- var nullProvider = new ProviderIdsExtensionsTestsObject()
+ var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -85,7 +94,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void TryGetProviderId_NullProvider_False()
{
- var nullProvider = new ProviderIdsExtensionsTestsObject()
+ var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -113,6 +122,16 @@ namespace Jellyfin.Model.Tests.Entities
}
[Fact]
+ public void TryGetProviderId_FoundNameEmptyValue_False()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.ProviderIds[MetadataProvider.Imdb.ToString()] = string.Empty;
+
+ Assert.False(provider.TryGetProviderId(MetadataProvider.Imdb, out var id));
+ Assert.Null(id);
+ }
+
+ [Fact]
public void SetProviderId_NullInstance_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ProviderIdsExtensions.SetProviderId(null!, MetadataProvider.Imdb, ExampleImdbId));
@@ -146,7 +165,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void SetProviderId_NullProvider_Success()
{
- var nullProvider = new ProviderIdsExtensionsTestsObject()
+ var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -158,7 +177,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void SetProviderId_NullProviderAndEmptyName_Success()
{
- var nullProvider = new ProviderIdsExtensionsTestsObject()
+ var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};