aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrobibero <cody@robibe.ro>2020-09-06 14:34:31 -0600
committercrobibero <cody@robibe.ro>2020-09-06 14:34:31 -0600
commiteab92a0b0124c2e89a8e11d4d6a8031f17834e36 (patch)
treed86b3903849cbff19c3a11198bc2e14a6607c18e
parentd5eb246557f9c943d8e3c5ddcc357ef351425deb (diff)
parent99bbbea9e24d3e34041fdd97f9f9efa0dad58c9a (diff)
Merge remote-tracking branch 'upstream/master' into api-stream-return
-rw-r--r--.ci/azure-pipelines-main.yml8
-rw-r--r--.ci/azure-pipelines-test.yml9
-rw-r--r--.vscode/tasks.json2
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Emby.Naming/Common/NamingOptions.cs4
-rw-r--r--Jellyfin.Api/Controllers/AlbumsController.cs5
-rw-r--r--Jellyfin.Api/Controllers/ArtistsController.cs3
-rw-r--r--Jellyfin.Api/Controllers/AudioController.cs5
-rw-r--r--Jellyfin.Api/Controllers/ChannelsController.cs5
-rw-r--r--Jellyfin.Api/Controllers/CollectionController.cs4
-rw-r--r--Jellyfin.Api/Controllers/ConfigurationController.cs4
-rw-r--r--Jellyfin.Api/Controllers/DisplayPreferencesController.cs4
-rw-r--r--Jellyfin.Api/Controllers/DlnaController.cs7
-rw-r--r--Jellyfin.Api/Controllers/DlnaServerController.cs19
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs32
-rw-r--r--Jellyfin.Api/Controllers/GenresController.cs3
-rw-r--r--Jellyfin.Api/Controllers/HlsSegmentController.cs13
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs157
-rw-r--r--Jellyfin.Api/Controllers/InstantMixController.cs12
-rw-r--r--Jellyfin.Api/Controllers/ItemLookupController.cs4
-rw-r--r--Jellyfin.Api/Controllers/ItemRefreshController.cs3
-rw-r--r--Jellyfin.Api/Controllers/ItemUpdateController.cs6
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs5
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs16
-rw-r--r--Jellyfin.Api/Controllers/LiveTvController.cs27
-rw-r--r--Jellyfin.Api/Controllers/MediaInfoController.cs4
-rw-r--r--Jellyfin.Api/Controllers/MusicGenresController.cs3
-rw-r--r--Jellyfin.Api/Controllers/PackageController.cs6
-rw-r--r--Jellyfin.Api/Controllers/PersonsController.cs3
-rw-r--r--Jellyfin.Api/Controllers/PlaylistsController.cs28
-rw-r--r--Jellyfin.Api/Controllers/PlaystateController.cs19
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs10
-rw-r--r--Jellyfin.Api/Controllers/RemoteImageController.cs6
-rw-r--r--Jellyfin.Api/Controllers/ScheduledTasksController.cs2
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs6
-rw-r--r--Jellyfin.Api/Controllers/StudiosController.cs3
-rw-r--r--Jellyfin.Api/Controllers/SubtitleController.cs16
-rw-r--r--Jellyfin.Api/Controllers/SuggestionsController.cs3
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs5
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs14
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs21
-rw-r--r--Jellyfin.Api/Controllers/UserViewsController.cs5
-rw-r--r--Jellyfin.Api/Controllers/VideoHlsController.cs3
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs8
-rw-r--r--Jellyfin.Api/Controllers/YearsController.cs3
-rw-r--r--Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs2
-rw-r--r--Jellyfin.Api/Helpers/StreamingHelpers.cs3
-rw-r--r--Jellyfin.Data/Entities/ActivityLog.cs78
-rw-r--r--Jellyfin.Data/Entities/DisplayPreferences.cs4
-rw-r--r--Jellyfin.Data/Entities/Group.cs61
-rw-r--r--Jellyfin.Data/Entities/ImageInfo.cs45
-rw-r--r--Jellyfin.Data/Entities/ItemDisplayPreferences.cs7
-rw-r--r--Jellyfin.Data/Entities/Libraries/Artwork.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Book.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/BookMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Chapter.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Collection.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CollectionItem.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Company.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CustomItem.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Episode.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Genre.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/ItemMetadata.cs (renamed from Jellyfin.Data/Entities/Libraries/Metadata.cs)12
-rw-r--r--Jellyfin.Data/Entities/Libraries/MediaFile.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/Movie.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MovieMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbum.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Person.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/PersonRole.cs12
-rw-r--r--Jellyfin.Data/Entities/Libraries/Photo.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Rating.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/Release.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Season.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Series.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Track.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/TrackMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Permission.cs36
-rw-r--r--Jellyfin.Data/Entities/Preference.cs26
-rw-r--r--Jellyfin.Data/Entities/ProviderMapping.cs129
-rw-r--r--Jellyfin.Data/Entities/User.cs49
-rw-r--r--Jellyfin.Data/Enums/ArtKind.cs34
-rw-r--r--Jellyfin.Data/Enums/DynamicDayOfWeek.cs44
-rw-r--r--Jellyfin.Data/Enums/IndexingKind.cs7
-rw-r--r--Jellyfin.Data/Enums/MediaFileKind.cs34
-rw-r--r--Jellyfin.Data/Enums/PersonRoleType.cs76
-rw-r--r--Jellyfin.Data/Enums/SubtitlePlaybackMode.cs26
-rw-r--r--Jellyfin.Data/Enums/UnratedItem.cs58
-rw-r--r--Jellyfin.Data/Jellyfin.Data.csproj6
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj5
-rw-r--r--Jellyfin.Server/wwwroot/api-docs/banner-dark.svg34
-rw-r--r--Jellyfin.Server/wwwroot/api-docs/swagger/custom.css15
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs7
-rw-r--r--MediaBrowser.sln6
-rw-r--r--tests/Jellyfin.Api.Tests/BrandingServiceTests.cs (renamed from tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs)2
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj1
-rw-r--r--tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs (renamed from tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs)2
-rw-r--r--tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs42
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs4
-rw-r--r--tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj34
-rw-r--r--tests/jellyfin-tests.ruleset4
108 files changed, 810 insertions, 715 deletions
diff --git a/.ci/azure-pipelines-main.yml b/.ci/azure-pipelines-main.yml
index 2a1c0e6f2..7617f0f5a 100644
--- a/.ci/azure-pipelines-main.yml
+++ b/.ci/azure-pipelines-main.yml
@@ -64,28 +64,28 @@ jobs:
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: false
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Naming'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/Emby.Naming.dll'
artifactName: 'Jellyfin.Naming'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Controller'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/MediaBrowser.Controller.dll'
artifactName: 'Jellyfin.Controller'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Model'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/MediaBrowser.Model.dll'
artifactName: 'Jellyfin.Model'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Common'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
diff --git a/.ci/azure-pipelines-test.yml b/.ci/azure-pipelines-test.yml
index a3c7f8526..eca8aa90f 100644
--- a/.ci/azure-pipelines-test.yml
+++ b/.ci/azure-pipelines-test.yml
@@ -74,7 +74,6 @@ jobs:
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
displayName: 'Run ReportGenerator'
- enabled: false
inputs:
reports: "$(Agent.TempDirectory)/**/coverage.cobertura.xml"
targetdir: "$(Agent.TempDirectory)/merged/"
@@ -84,10 +83,16 @@ jobs:
- task: PublishCodeCoverageResults@1
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
displayName: 'Publish Code Coverage'
- enabled: false
inputs:
codeCoverageTool: "cobertura"
#summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' # !!THIS IS FOR V2
summaryFileLocation: "$(Agent.TempDirectory)/merged/**.xml"
pathToSources: $(Build.SourcesDirectory)
failIfCoverageEmpty: true
+
+ - task: PublishPipelineArtifact@1
+ displayName: 'Publish OpenAPI Artifact'
+ condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+ inputs:
+ targetPath: "tests/Jellyfin.Api.Tests/bin/Release/netcoreapp3.1/openapi.json"
+ artifactName: 'OpenAPI Spec'
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 7ddc49d5c..09c523eb2 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -17,7 +17,7 @@
"type": "process",
"args": [
"test",
- "${workspaceFolder}/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj"
+ "${workspaceFolder}/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj"
],
"problemMatcher": "$msCompile"
}
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index e383d02b7..f0724b412 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -57,6 +57,7 @@
- [Larvitar](https://github.com/Larvitar)
- [LeoVerto](https://github.com/LeoVerto)
- [Liggy](https://github.com/Liggy)
+ - [lmaonator](https://github.com/lmaonator)
- [LogicalPhallacy](https://github.com/LogicalPhallacy)
- [loli10K](https://github.com/loli10K)
- [lostmypillow](https://github.com/lostmypillow)
diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index d1e17f416..fd4244f64 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/Emby.Naming/Common/NamingOptions.cs
@@ -136,8 +136,8 @@ namespace Emby.Naming.Common
CleanDateTimes = new[]
{
- @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*",
- @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*"
+ @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*",
+ @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*"
};
CleanStrings = new[]
diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs
index 190d4bd07..357f646a2 100644
--- a/Jellyfin.Api/Controllers/AlbumsController.cs
+++ b/Jellyfin.Api/Controllers/AlbumsController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
@@ -52,7 +53,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Albums/{albumId}/Similar")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSimilarAlbums(
- [FromRoute] string albumId,
+ [FromRoute, Required] string albumId,
[FromQuery] Guid? userId,
[FromQuery] string? excludeArtistIds,
[FromQuery] int? limit)
@@ -84,7 +85,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Artists/{artistId}/Similar")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSimilarArtists(
- [FromRoute] string artistId,
+ [FromRoute, Required] string artistId,
[FromQuery] Guid? userId,
[FromQuery] string? excludeArtistIds,
[FromQuery] int? limit)
diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs
index 3f72830cd..d38214116 100644
--- a/Jellyfin.Api/Controllers/ArtistsController.cs
+++ b/Jellyfin.Api/Controllers/ArtistsController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
@@ -469,7 +470,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the artist.</returns>
[HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<BaseItemDto> GetArtistByName([FromRoute] string name, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
var dtoOptions = new DtoOptions().AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index 48fd198b5..4efd45031 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
@@ -91,8 +92,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesAudioFile]
public async Task<ActionResult> GetAudioStream(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs
index bdd7dfd96..33a969f85 100644
--- a/Jellyfin.Api/Controllers/ChannelsController.cs
+++ b/Jellyfin.Api/Controllers/ChannelsController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -90,7 +91,7 @@ namespace Jellyfin.Api.Controllers
/// <response code="200">Channel features returned.</response>
/// <returns>An <see cref="OkResult"/> containing the channel features.</returns>
[HttpGet("{channelId}/Features")]
- public ActionResult<ChannelFeatures> GetChannelFeatures([FromRoute] string channelId)
+ public ActionResult<ChannelFeatures> GetChannelFeatures([FromRoute, Required] string channelId)
{
return _channelManager.GetChannelFeatures(channelId);
}
@@ -114,7 +115,7 @@ namespace Jellyfin.Api.Controllers
/// </returns>
[HttpGet("{channelId}/Items")]
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetChannelItems(
- [FromRoute] Guid channelId,
+ [FromRoute, Required] Guid channelId,
[FromQuery] Guid? folderId,
[FromQuery] Guid? userId,
[FromQuery] int? startIndex,
diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs
index c5910d6e8..f78690b06 100644
--- a/Jellyfin.Api/Controllers/CollectionController.cs
+++ b/Jellyfin.Api/Controllers/CollectionController.cs
@@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
[HttpPost("{collectionId}/Items")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> AddToCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds)
+ public async Task<ActionResult> AddToCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string? itemIds)
{
await _collectionManager.AddToCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(true);
return NoContent();
@@ -103,7 +103,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
[HttpDelete("{collectionId}/Items")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds)
+ public async Task<ActionResult> RemoveFromCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string? itemIds)
{
await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(false);
return NoContent();
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index 606e27970..8c8c29078 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -76,7 +76,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Configuration/{key}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesFile(MediaTypeNames.Application.Json)]
- public ActionResult<object> GetNamedConfiguration([FromRoute] string? key)
+ public ActionResult<object> GetNamedConfiguration([FromRoute, Required] string? key)
{
return _configurationManager.GetConfiguration(key);
}
@@ -90,7 +90,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Configuration/{key}")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> UpdateNamedConfiguration([FromRoute] string? key)
+ public async Task<ActionResult> UpdateNamedConfiguration([FromRoute, Required] string? key)
{
var configurationType = _configurationManager.GetConfigurationType(key);
var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false);
diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index c3b67eec3..6bb7b1910 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -43,7 +43,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
public ActionResult<DisplayPreferencesDto> GetDisplayPreferences(
- [FromRoute] string? displayPreferencesId,
+ [FromRoute, Required] string? displayPreferencesId,
[FromQuery] [Required] Guid userId,
[FromQuery] [Required] string? client)
{
@@ -97,7 +97,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
public ActionResult UpdateDisplayPreferences(
- [FromRoute] string? displayPreferencesId,
+ [FromRoute, Required] string? displayPreferencesId,
[FromQuery, Required] Guid userId,
[FromQuery, Required] string? client,
[FromBody, Required] DisplayPreferencesDto displayPreferences)
diff --git a/Jellyfin.Api/Controllers/DlnaController.cs b/Jellyfin.Api/Controllers/DlnaController.cs
index 397299a73..052a6aff2 100644
--- a/Jellyfin.Api/Controllers/DlnaController.cs
+++ b/Jellyfin.Api/Controllers/DlnaController.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Constants;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Model.Dlna;
@@ -59,7 +60,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Profiles/{profileId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<DeviceProfile> GetProfile([FromRoute] string profileId)
+ public ActionResult<DeviceProfile> GetProfile([FromRoute, Required] string profileId)
{
var profile = _dlnaManager.GetProfile(profileId);
if (profile == null)
@@ -80,7 +81,7 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("Profiles/{profileId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult DeleteProfile([FromRoute] string profileId)
+ public ActionResult DeleteProfile([FromRoute, Required] string profileId)
{
var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
if (existingDeviceProfile == null)
@@ -117,7 +118,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Profiles/{profileId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult UpdateProfile([FromRoute] string profileId, [FromBody] DeviceProfile deviceProfile)
+ public ActionResult UpdateProfile([FromRoute, Required] string profileId, [FromBody] DeviceProfile deviceProfile)
{
var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
if (existingDeviceProfile == null)
diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs
index 1b139000d..271ae293b 100644
--- a/Jellyfin.Api/Controllers/DlnaServerController.cs
+++ b/Jellyfin.Api/Controllers/DlnaServerController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Mime;
@@ -46,7 +47,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
- public ActionResult GetDescriptionXml([FromRoute] string serverId)
+ public ActionResult GetDescriptionXml([FromRoute, Required] string serverId)
{
var url = GetAbsoluteUri();
var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
@@ -67,7 +68,7 @@ namespace Jellyfin.Api.Controllers
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
- public ActionResult GetContentDirectory([FromRoute] string serverId)
+ public ActionResult GetContentDirectory([FromRoute, Required] string serverId)
{
return Ok(_contentDirectory.GetServiceXml());
}
@@ -84,7 +85,7 @@ namespace Jellyfin.Api.Controllers
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
- public ActionResult GetMediaReceiverRegistrar([FromRoute] string serverId)
+ public ActionResult GetMediaReceiverRegistrar([FromRoute, Required] string serverId)
{
return Ok(_mediaReceiverRegistrar.GetServiceXml());
}
@@ -101,7 +102,7 @@ namespace Jellyfin.Api.Controllers
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
- public ActionResult GetConnectionManager([FromRoute] string serverId)
+ public ActionResult GetConnectionManager([FromRoute, Required] string serverId)
{
return Ok(_connectionManager.GetServiceXml());
}
@@ -112,7 +113,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="serverId">Server UUID.</param>
/// <returns>Control response.</returns>
[HttpPost("{serverId}/ContentDirectory/Control")]
- public async Task<ActionResult<ControlResponse>> ProcessContentDirectoryControlRequest([FromRoute] string serverId)
+ public async Task<ActionResult<ControlResponse>> ProcessContentDirectoryControlRequest([FromRoute, Required] string serverId)
{
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _contentDirectory).ConfigureAwait(false);
}
@@ -123,7 +124,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="serverId">Server UUID.</param>
/// <returns>Control response.</returns>
[HttpPost("{serverId}/ConnectionManager/Control")]
- public async Task<ActionResult<ControlResponse>> ProcessConnectionManagerControlRequest([FromRoute] string serverId)
+ public async Task<ActionResult<ControlResponse>> ProcessConnectionManagerControlRequest([FromRoute, Required] string serverId)
{
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _connectionManager).ConfigureAwait(false);
}
@@ -134,7 +135,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="serverId">Server UUID.</param>
/// <returns>Control response.</returns>
[HttpPost("{serverId}/MediaReceiverRegistrar/Control")]
- public async Task<ActionResult<ControlResponse>> ProcessMediaReceiverRegistrarControlRequest([FromRoute] string serverId)
+ public async Task<ActionResult<ControlResponse>> ProcessMediaReceiverRegistrarControlRequest([FromRoute, Required] string serverId)
{
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _mediaReceiverRegistrar).ConfigureAwait(false);
}
@@ -191,7 +192,7 @@ namespace Jellyfin.Api.Controllers
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesImageFile]
- public ActionResult GetIconId([FromRoute] string serverId, [FromRoute] string fileName)
+ public ActionResult GetIconId([FromRoute, Required] string serverId, [FromRoute, Required] string fileName)
{
return GetIconInternal(fileName);
}
@@ -203,7 +204,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>Icon stream.</returns>
[HttpGet("icons/{fileName}")]
[ProducesImageFile]
- public ActionResult GetIcon([FromRoute] string fileName)
+ public ActionResult GetIcon([FromRoute, Required] string fileName)
{
return GetIconInternal(fileName);
}
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index 759a574b8..a0bd68d8c 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -169,8 +169,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
public async Task<ActionResult> GetMasterHlsVideoPlaylist(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -337,8 +337,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
public async Task<ActionResult> GetMasterHlsAudioPlaylist(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -503,8 +503,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
public async Task<ActionResult> GetVariantHlsVideoPlaylist(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -669,8 +669,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
public async Task<ActionResult> GetVariantHlsAudioPlaylist(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -838,10 +838,10 @@ namespace Jellyfin.Api.Controllers
[ProducesVideoFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")]
public async Task<ActionResult> GetHlsVideoSegment(
- [FromRoute] Guid itemId,
- [FromRoute] string playlistId,
- [FromRoute] int segmentId,
- [FromRoute] string container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string playlistId,
+ [FromRoute, Required] int segmentId,
+ [FromRoute, Required] string container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -1008,10 +1008,10 @@ namespace Jellyfin.Api.Controllers
[ProducesAudioFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")]
public async Task<ActionResult> GetHlsAudioSegment(
- [FromRoute] Guid itemId,
- [FromRoute] string playlistId,
- [FromRoute] int segmentId,
- [FromRoute] string container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string playlistId,
+ [FromRoute, Required] int segmentId,
+ [FromRoute, Required] string container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs
index 55ad71200..de6aa86c9 100644
--- a/Jellyfin.Api/Controllers/GenresController.cs
+++ b/Jellyfin.Api/Controllers/GenresController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Constants;
@@ -260,7 +261,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the genre.</returns>
[HttpGet("{genreName}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<BaseItemDto> GetGenre([FromRoute] string genreName, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{
var dtoOptions = new DtoOptions()
.AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs
index e534be50a..054e586ce 100644
--- a/Jellyfin.Api/Controllers/HlsSegmentController.cs
+++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
@@ -57,7 +58,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesAudioFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
- public ActionResult GetHlsAudioSegmentLegacy([FromRoute] string itemId, [FromRoute] string segmentId)
+ public ActionResult GetHlsAudioSegmentLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string segmentId)
{
// TODO: Deprecate with new iOS app
var file = segmentId + Path.GetExtension(Request.Path);
@@ -78,7 +79,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
- public ActionResult GetHlsPlaylistLegacy([FromRoute] string itemId, [FromRoute] string playlistId)
+ public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
{
var file = playlistId + Path.GetExtension(Request.Path);
file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
@@ -118,10 +119,10 @@ namespace Jellyfin.Api.Controllers
[ProducesVideoFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
public ActionResult GetHlsVideoSegmentLegacy(
- [FromRoute] string itemId,
- [FromRoute] string playlistId,
- [FromRoute] string segmentId,
- [FromRoute] string segmentContainer)
+ [FromRoute, Required] string itemId,
+ [FromRoute, Required] string playlistId,
+ [FromRoute, Required] string segmentId,
+ [FromRoute, Required] string segmentContainer)
{
var file = segmentId + Path.GetExtension(Request.Path);
var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index c012acef3..3006918ca 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
@@ -91,9 +92,9 @@ namespace Jellyfin.Api.Controllers
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
public async Task<ActionResult> PostUserImage(
- [FromRoute] Guid userId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? index = null)
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? index = null)
{
if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
{
@@ -138,9 +139,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public ActionResult DeleteUserImage(
- [FromRoute] Guid userId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? index = null)
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? index = null)
{
if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
{
@@ -176,9 +177,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> DeleteItemImage(
- [FromRoute] Guid itemId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -206,9 +207,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
public async Task<ActionResult> SetItemImage(
- [FromRoute] Guid itemId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -239,9 +240,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> UpdateItemImageIndex(
- [FromRoute] Guid itemId,
- [FromRoute] ImageType imageType,
- [FromRoute] int imageIndex,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int imageIndex,
[FromQuery] int newIndex)
{
var item = _libraryManager.GetItemById(itemId);
@@ -265,7 +266,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult<IEnumerable<ImageInfo>>> GetItemImageInfos([FromRoute] Guid itemId)
+ public async Task<ActionResult<IEnumerable<ImageInfo>>> GetItemImageInfos([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -354,10 +355,10 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetItemImage(
- [FromRoute] Guid itemId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -370,7 +371,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -433,23 +434,23 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetItemImage2(
- [FromRoute] Guid itemId,
- [FromRoute] ImageType imageType,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
- [FromRoute] string tag,
+ [FromRoute, Required] string tag,
[FromQuery] bool? cropWhitespace,
- [FromRoute] string format,
+ [FromRoute, Required] string format,
[FromQuery] bool? addPlayedIndicator,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -512,14 +513,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetArtistImage(
- [FromRoute] string name,
- [FromRoute] ImageType imageType,
- [FromRoute] string tag,
- [FromRoute] string format,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] string name,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] string tag,
+ [FromRoute, Required] string format,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -528,7 +529,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetArtist(name);
if (item == null)
@@ -591,14 +592,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetGenreImage(
- [FromRoute] string name,
- [FromRoute] ImageType imageType,
- [FromRoute] string tag,
- [FromRoute] string format,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] string name,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] string tag,
+ [FromRoute, Required] string format,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -607,7 +608,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetGenre(name);
if (item == null)
@@ -670,14 +671,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetMusicGenreImage(
- [FromRoute] string name,
- [FromRoute] ImageType imageType,
- [FromRoute] string tag,
- [FromRoute] string format,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] string name,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] string tag,
+ [FromRoute, Required] string format,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -686,7 +687,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetMusicGenre(name);
if (item == null)
@@ -749,14 +750,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetPersonImage(
- [FromRoute] string name,
- [FromRoute] ImageType imageType,
- [FromRoute] string tag,
- [FromRoute] string format,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] string name,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] string tag,
+ [FromRoute, Required] string format,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -765,7 +766,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetPerson(name);
if (item == null)
@@ -828,14 +829,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetStudioImage(
- [FromRoute] string name,
- [FromRoute] ImageType imageType,
- [FromRoute] string tag,
- [FromRoute] string format,
- [FromRoute] int? maxWidth,
- [FromRoute] int? maxHeight,
- [FromRoute] double? percentPlayed,
- [FromRoute] int? unplayedCount,
+ [FromRoute, Required] string name,
+ [FromRoute, Required] ImageType imageType,
+ [FromRoute, Required] string tag,
+ [FromRoute, Required] string format,
+ [FromRoute, Required] int? maxWidth,
+ [FromRoute, Required] int? maxHeight,
+ [FromRoute, Required] double? percentPlayed,
+ [FromRoute, Required] int? unplayedCount,
[FromQuery] int? width,
[FromQuery] int? height,
[FromQuery] int? quality,
@@ -844,7 +845,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var item = _libraryManager.GetStudio(name);
if (item == null)
@@ -907,8 +908,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetUserImage(
- [FromRoute] Guid userId,
- [FromRoute] ImageType imageType,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] ImageType imageType,
[FromQuery] string? tag,
[FromQuery] string? format,
[FromQuery] int? maxWidth,
@@ -923,7 +924,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute] int? imageIndex = null)
+ [FromRoute, Required] int? imageIndex = null)
{
var user = _userManager.GetUserById(userId);
if (user == null)
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index 73bd30c4d..01bfbba4e 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Songs/{id}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromSong(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
@@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Albums/{id}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromAlbum(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
@@ -138,7 +138,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Playlists/{id}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromPlaylist(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
@@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Artists/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
@@ -248,7 +248,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("MusicGenres/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
@@ -285,7 +285,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Items/{id}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromItem(
- [FromRoute] Guid id,
+ [FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] string? fields,
diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs
index 6eaa61dfe..cf7038650 100644
--- a/Jellyfin.Api/Controllers/ItemLookupController.cs
+++ b/Jellyfin.Api/Controllers/ItemLookupController.cs
@@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<IEnumerable<ExternalIdInfo>> GetExternalIdInfos([FromRoute] Guid itemId)
+ public ActionResult<IEnumerable<ExternalIdInfo>> GetExternalIdInfos([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -296,7 +296,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> ApplySearchCriteria(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromBody, Required] RemoteSearchResult searchResult,
[FromQuery] bool replaceAllImages = true)
{
diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs
index 3f5d305c1..49865eb5e 100644
--- a/Jellyfin.Api/Controllers/ItemRefreshController.cs
+++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Constants;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -53,7 +54,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult Post(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] MetadataRefreshMode metadataRefreshMode = MetadataRefreshMode.None,
[FromQuery] MetadataRefreshMode imageRefreshMode = MetadataRefreshMode.None,
[FromQuery] bool replaceAllMetadata = false,
diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs
index ec52f4996..4308a434d 100644
--- a/Jellyfin.Api/Controllers/ItemUpdateController.cs
+++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs
@@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Items/{itemId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult> UpdateItem([FromRoute] Guid itemId, [FromBody, Required] BaseItemDto request)
+ public async Task<ActionResult> UpdateItem([FromRoute, Required] Guid itemId, [FromBody, Required] BaseItemDto request)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -141,7 +141,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Items/{itemId}/MetadataEditor")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<MetadataEditorInfo> GetMetadataEditorInfo([FromRoute] Guid itemId)
+ public ActionResult<MetadataEditorInfo> GetMetadataEditorInfo([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
@@ -195,7 +195,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Items/{itemId}/ContentType")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult UpdateItemContentType([FromRoute] Guid itemId, [FromQuery, Required] string? contentType)
+ public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery, Required] string? contentType)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index f9273bad6..06ab176b2 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Constants;
@@ -144,7 +145,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{uId}/Items", Name = "GetItems_2")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetItems(
- [FromRoute] Guid? uId,
+ [FromRoute, Required] Guid? uId,
[FromQuery] Guid? userId,
[FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong,
@@ -529,7 +530,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{userId}/Items/Resume")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetResumeItems(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] string? searchTerm,
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 4f48e5dbd..78d70b04e 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -106,7 +106,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesFile("video/*", "audio/*")]
- public ActionResult GetFile([FromRoute] Guid itemId)
+ public ActionResult GetFile([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ThemeMediaResult> GetThemeSongs(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false)
{
@@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ThemeMediaResult> GetThemeVideos(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false)
{
@@ -276,7 +276,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<AllThemeMediaResult> GetThemeMedia(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false)
{
@@ -439,7 +439,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute] Guid itemId, [FromQuery] Guid? userId)
+ public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{
var item = _libraryManager.GetItemById(itemId);
@@ -556,7 +556,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Library/Movies/Updated")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult PostUpdatedMovies([FromRoute] string? tmdbId, [FromRoute] string? imdbId)
+ public ActionResult PostUpdatedMovies([FromRoute, Required] string? tmdbId, [FromRoute, Required] string? imdbId)
{
var movies = _libraryManager.GetItemList(new InternalItemsQuery
{
@@ -620,7 +620,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesFile("video/*", "audio/*")]
- public async Task<ActionResult> GetDownload([FromRoute] Guid itemId)
+ public async Task<ActionResult> GetDownload([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -689,7 +689,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSimilarItems(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] string? excludeArtistIds,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index 7d720a5c5..bbae42157 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
@@ -210,7 +211,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Channels/{channelId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)]
- public ActionResult<BaseItemDto> GetChannel([FromRoute] Guid channelId, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId)
{
var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
@@ -407,7 +408,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Recordings/{recordingId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)]
- public ActionResult<BaseItemDto> GetRecording([FromRoute] Guid recordingId, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId)
{
var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
@@ -429,7 +430,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Tuners/{tunerId}/Reset")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[Authorize(Policy = Policies.DefaultAuthorization)]
- public ActionResult ResetTuner([FromRoute] string tunerId)
+ public ActionResult ResetTuner([FromRoute, Required] string tunerId)
{
AssertUserCanManageLiveTv();
_liveTvManager.ResetTuner(tunerId, CancellationToken.None);
@@ -745,7 +746,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<BaseItemDto>> GetProgram(
- [FromRoute] string programId,
+ [FromRoute, Required] string programId,
[FromQuery] Guid? userId)
{
var user = userId.HasValue && !userId.Equals(Guid.Empty)
@@ -766,7 +767,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult DeleteRecording([FromRoute] Guid recordingId)
+ public ActionResult DeleteRecording([FromRoute, Required] Guid recordingId)
{
AssertUserCanManageLiveTv();
@@ -793,7 +794,7 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("Timers/{timerId}")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> CancelTimer([FromRoute] string timerId)
+ public async Task<ActionResult> CancelTimer([FromRoute, Required] string timerId)
{
AssertUserCanManageLiveTv();
await _liveTvManager.CancelTimer(timerId).ConfigureAwait(false);
@@ -811,7 +812,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "timerId", Justification = "Imported from ServiceStack")]
- public async Task<ActionResult> UpdateTimer([FromRoute] string timerId, [FromBody] TimerInfoDto timerInfo)
+ public async Task<ActionResult> UpdateTimer([FromRoute, Required] string timerId, [FromBody] TimerInfoDto timerInfo)
{
AssertUserCanManageLiveTv();
await _liveTvManager.UpdateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false);
@@ -845,7 +846,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult<SeriesTimerInfoDto>> GetSeriesTimer([FromRoute] string timerId)
+ public async Task<ActionResult<SeriesTimerInfoDto>> GetSeriesTimer([FromRoute, Required] string timerId)
{
var timer = await _liveTvManager.GetSeriesTimer(timerId, CancellationToken.None).ConfigureAwait(false);
if (timer == null)
@@ -885,7 +886,7 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("SeriesTimers/{timerId}")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> CancelSeriesTimer([FromRoute] string timerId)
+ public async Task<ActionResult> CancelSeriesTimer([FromRoute, Required] string timerId)
{
AssertUserCanManageLiveTv();
await _liveTvManager.CancelSeriesTimer(timerId).ConfigureAwait(false);
@@ -903,7 +904,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "timerId", Justification = "Imported from ServiceStack")]
- public async Task<ActionResult> UpdateSeriesTimer([FromRoute] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo)
+ public async Task<ActionResult> UpdateSeriesTimer([FromRoute, Required] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo)
{
AssertUserCanManageLiveTv();
await _liveTvManager.UpdateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false);
@@ -935,7 +936,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("This endpoint is obsolete.")]
- public ActionResult<BaseItemDto> GetRecordingGroup([FromRoute] Guid? groupId)
+ public ActionResult<BaseItemDto> GetRecordingGroup([FromRoute, Required] Guid? groupId)
{
return NotFound();
}
@@ -1179,7 +1180,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesVideoFile]
- public async Task<ActionResult> GetLiveRecordingFile([FromRoute] string recordingId)
+ public async Task<ActionResult> GetLiveRecordingFile([FromRoute, Required] string recordingId)
{
var path = _liveTvManager.GetEmbyTvActiveRecordingPath(recordingId);
@@ -1210,7 +1211,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesVideoFile]
- public async Task<ActionResult> GetLiveStreamFile([FromRoute] string streamId, [FromRoute] string container)
+ public async Task<ActionResult> GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container)
{
var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false);
if (liveStreamInfo == null)
diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs
index 2a204e650..ee171e856 100644
--- a/Jellyfin.Api/Controllers/MediaInfoController.cs
+++ b/Jellyfin.Api/Controllers/MediaInfoController.cs
@@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="Task"/> containing a <see cref="PlaybackInfoResponse"/> with the playback information.</returns>
[HttpGet("Items/{itemId}/PlaybackInfo")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery, Required] Guid? userId)
+ public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute, Required] Guid itemId, [FromQuery, Required] Guid? userId)
{
return await _mediaInfoHelper.GetPlaybackInfo(
itemId,
@@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Items/{itemId}/PlaybackInfo")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<PlaybackInfoResponse>> GetPostedPlaybackInfo(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
[FromQuery] long? maxStreamingBitrate,
[FromQuery] long? startTimeTicks,
diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs
index 0d319137a..570ae8fdc 100644
--- a/Jellyfin.Api/Controllers/MusicGenresController.cs
+++ b/Jellyfin.Api/Controllers/MusicGenresController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Constants;
@@ -258,7 +259,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns>
[HttpGet("{genreName}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<BaseItemDto> GetMusicGenre([FromRoute] string genreName, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{
var dtoOptions = new DtoOptions().AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs
index 3d6a87909..7e406b418 100644
--- a/Jellyfin.Api/Controllers/PackageController.cs
+++ b/Jellyfin.Api/Controllers/PackageController.cs
@@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Packages/{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<PackageInfo>> GetPackageInfo(
- [FromRoute] [Required] string? name,
+ [FromRoute, Required] string? name,
[FromQuery] string? assemblyGuid)
{
var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
@@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.RequiresElevation)]
public async Task<ActionResult> InstallPackage(
- [FromRoute] [Required] string? name,
+ [FromRoute, Required] string? name,
[FromQuery] string? assemblyGuid,
[FromQuery] string? version)
{
@@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult CancelPackageInstallation(
- [FromRoute] [Required] Guid packageId)
+ [FromRoute, Required] Guid packageId)
{
_installationManager.CancelInstallation(packageId);
return NoContent();
diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs
index b6ccec666..8bd610dad 100644
--- a/Jellyfin.Api/Controllers/PersonsController.cs
+++ b/Jellyfin.Api/Controllers/PersonsController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Constants;
@@ -262,7 +263,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<BaseItemDto> GetPerson([FromRoute] string name, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
var dtoOptions = new DtoOptions()
.AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs
index f4c6a9253..69e0b8e07 100644
--- a/Jellyfin.Api/Controllers/PlaylistsController.cs
+++ b/Jellyfin.Api/Controllers/PlaylistsController.cs
@@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("{playlistId}/Items")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> AddToPlaylist(
- [FromRoute] Guid playlistId,
+ [FromRoute, Required] Guid playlistId,
[FromQuery] string? ids,
[FromQuery] Guid? userId)
{
@@ -103,9 +103,9 @@ namespace Jellyfin.Api.Controllers
[HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> MoveItem(
- [FromRoute] string? playlistId,
- [FromRoute] string? itemId,
- [FromRoute] int newIndex)
+ [FromRoute, Required] string? playlistId,
+ [FromRoute, Required] string? itemId,
+ [FromRoute, Required] int newIndex)
{
await _playlistManager.MoveItemAsync(playlistId, itemId, newIndex).ConfigureAwait(false);
return NoContent();
@@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="NoContentResult"/> on success.</returns>
[HttpDelete("{playlistId}/Items")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task<ActionResult> RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds)
+ public async Task<ActionResult> RemoveFromPlaylist([FromRoute, Required] string? playlistId, [FromQuery] string? entryIds)
{
await _playlistManager.RemoveFromPlaylistAsync(playlistId, RequestHelpers.Split(entryIds, ',', true)).ConfigureAwait(false);
return NoContent();
@@ -143,15 +143,15 @@ namespace Jellyfin.Api.Controllers
/// <returns>The original playlist items.</returns>
[HttpGet("{playlistId}/Items")]
public ActionResult<QueryResult<BaseItemDto>> GetPlaylistItems(
- [FromRoute] Guid playlistId,
- [FromRoute] Guid userId,
- [FromRoute] int? startIndex,
- [FromRoute] int? limit,
- [FromRoute] string? fields,
- [FromRoute] bool? enableImages,
- [FromRoute] bool? enableUserData,
- [FromRoute] int? imageTypeLimit,
- [FromRoute] string? enableImageTypes)
+ [FromRoute, Required] Guid playlistId,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] int? startIndex,
+ [FromRoute, Required] int? limit,
+ [FromRoute, Required] string? fields,
+ [FromRoute, Required] bool? enableImages,
+ [FromRoute, Required] bool? enableUserData,
+ [FromRoute, Required] int? imageTypeLimit,
+ [FromRoute, Required] string? enableImageTypes)
{
var playlist = (Playlist)_libraryManager.GetItemById(playlistId);
if (playlist == null)
diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs
index 22f2ca5c3..5c15e9a0d 100644
--- a/Jellyfin.Api/Controllers/PlaystateController.cs
+++ b/Jellyfin.Api/Controllers/PlaystateController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
@@ -71,8 +72,8 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Users/{userId}/PlayedItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<UserItemDataDto> MarkPlayedItem(
- [FromRoute] Guid userId,
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] DateTime? datePlayed)
{
var user = _userManager.GetUserById(userId);
@@ -96,7 +97,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpDelete("Users/{userId}/PlayedItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> MarkUnplayedItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<UserItemDataDto> MarkUnplayedItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
var session = RequestHelpers.GetSession(_sessionManager, _authContext, Request);
@@ -195,8 +196,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
public async Task<ActionResult> OnPlaybackStart(
- [FromRoute] Guid userId,
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] string? mediaSourceId,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex,
@@ -245,8 +246,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
public async Task<ActionResult> OnPlaybackProgress(
- [FromRoute] Guid userId,
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] string? mediaSourceId,
[FromQuery] long? positionTicks,
[FromQuery] int? audioStreamIndex,
@@ -297,8 +298,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
public async Task<ActionResult> OnPlaybackStopped(
- [FromRoute] Guid userId,
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid userId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] string? mediaSourceId,
[FromQuery] string? nextMediaType,
[FromQuery] long? positionTicks,
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index a82f2621a..342b0328d 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult UninstallPlugin([FromRoute] Guid pluginId)
+ public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId)
{
var plugin = _appHost.Plugins.FirstOrDefault(p => p.Id == pluginId);
if (plugin == null)
@@ -86,7 +86,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{pluginId}/Configuration")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute] Guid pluginId)
+ public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute, Required] Guid pluginId)
{
if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
{
@@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("{pluginId}/Configuration")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult> UpdatePluginConfiguration([FromRoute] Guid pluginId)
+ public async Task<ActionResult> UpdatePluginConfiguration([FromRoute, Required] Guid pluginId)
{
if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
{
@@ -172,7 +172,7 @@ namespace Jellyfin.Api.Controllers
[Obsolete("This endpoint should not be used.")]
[HttpPost("RegistrationRecords/{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute] string? name)
+ public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute, Required] string? name)
{
return new MBRegistrationRecord
{
@@ -194,7 +194,7 @@ namespace Jellyfin.Api.Controllers
[Obsolete("Paid plugins are not supported")]
[HttpGet("Registrations/{name}")]
[ProducesResponseType(StatusCodes.Status501NotImplemented)]
- public ActionResult GetRegistration([FromRoute] string? name)
+ public ActionResult GetRegistration([FromRoute, Required] string? name)
{
// TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,
// delete all these registration endpoints. They are only kept for compatibility.
diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs
index 597596422..5f095443b 100644
--- a/Jellyfin.Api/Controllers/RemoteImageController.cs
+++ b/Jellyfin.Api/Controllers/RemoteImageController.cs
@@ -71,7 +71,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<RemoteImageResult>> GetRemoteImages(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] ImageType? type,
[FromQuery] int? startIndex,
[FromQuery] int? limit,
@@ -134,7 +134,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute] Guid itemId)
+ public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute, Required] Guid itemId)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> DownloadRemoteImage(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery, Required] ImageType type,
[FromQuery] string? imageUrl)
{
diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs
index e672070c0..3206f2734 100644
--- a/Jellyfin.Api/Controllers/ScheduledTasksController.cs
+++ b/Jellyfin.Api/Controllers/ScheduledTasksController.cs
@@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Running/{taskId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult StartTask([FromRoute] string? taskId)
+ public ActionResult StartTask([FromRoute, Required] string? taskId)
{
var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
index ba8d51598..cff7c1501 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -336,7 +336,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult AddUserToSession(
[FromRoute, Required] string? sessionId,
- [FromRoute] Guid userId)
+ [FromRoute, Required] Guid userId)
{
_sessionManager.AddAdditionalUser(sessionId, userId);
return NoContent();
@@ -353,8 +353,8 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult RemoveUserFromSession(
- [FromRoute] string? sessionId,
- [FromRoute] Guid userId)
+ [FromRoute, Required] string? sessionId,
+ [FromRoute, Required] Guid userId)
{
_sessionManager.RemoveAdditionalUser(sessionId, userId);
return NoContent();
diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs
index 6f2787d93..cdd5f958e 100644
--- a/Jellyfin.Api/Controllers/StudiosController.cs
+++ b/Jellyfin.Api/Controllers/StudiosController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
@@ -259,7 +260,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the studio.</returns>
[HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<BaseItemDto> GetStudio([FromRoute] string name, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
var dtoOptions = new DtoOptions().AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs
index a19e49f11..ff26ca921 100644
--- a/Jellyfin.Api/Controllers/SubtitleController.cs
+++ b/Jellyfin.Api/Controllers/SubtitleController.cs
@@ -87,8 +87,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Task> DeleteSubtitle(
- [FromRoute] Guid itemId,
- [FromRoute] int index)
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] int index)
{
var item = _libraryManager.GetItemById(itemId);
@@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<IEnumerable<RemoteSubtitleInfo>>> SearchRemoteSubtitles(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromRoute, Required] string? language,
[FromQuery] bool? isPerfectMatch)
{
@@ -133,7 +133,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> DownloadRemoteSubtitles(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromRoute, Required] string? subtitleId)
{
var video = (Video)_libraryManager.GetItemById(itemId);
@@ -196,7 +196,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] long? endPositionTicks,
[FromQuery] bool copyTimestamps = false,
[FromQuery] bool addVttTimeMap = false,
- [FromRoute] long startPositionTicks = 0)
+ [FromRoute, Required] long startPositionTicks = 0)
{
if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase))
{
@@ -256,9 +256,9 @@ namespace Jellyfin.Api.Controllers
[ProducesPlaylistFile]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
public async Task<ActionResult> GetSubtitlePlaylist(
- [FromRoute] Guid itemId,
- [FromRoute] int index,
- [FromRoute] string? mediaSourceId,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] int index,
+ [FromRoute, Required] string? mediaSourceId,
[FromQuery, Required] int segmentLength)
{
var item = (Video)_libraryManager.GetItemById(itemId);
diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs
index 42db6b6a1..d7c81a3ab 100644
--- a/Jellyfin.Api/Controllers/SuggestionsController.cs
+++ b/Jellyfin.Api/Controllers/SuggestionsController.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
@@ -53,7 +54,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{userId}/Suggestions")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSuggestions(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromQuery] string? mediaType,
[FromQuery] string? type,
[FromQuery] int? startIndex,
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index b00653d9b..6bbdbc613 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
@@ -94,8 +95,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesAudioFile]
public async Task<ActionResult> GetUniversalAudioStream(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
[FromQuery] Guid? userId,
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index 746710475..435588146 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -108,7 +108,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.IgnoreParentalControl)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<UserDto> GetUserById([FromRoute] Guid userId)
+ public ActionResult<UserDto> GetUserById([FromRoute, Required] Guid userId)
{
var user = _userManager.GetUserById(userId);
@@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult DeleteUser([FromRoute] Guid userId)
+ public ActionResult DeleteUser([FromRoute, Required] Guid userId)
{
var user = _userManager.GetUserById(userId);
_sessionManager.RevokeUserTokens(user.Id, null);
@@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> UpdateUserPassword(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromBody] UpdateUserPassword request)
{
if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
@@ -323,7 +323,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult UpdateUserEasyPassword(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromBody] UpdateUserEasyPassword request)
{
if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
@@ -365,7 +365,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult> UpdateUser(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromBody] UserDto updateUser)
{
if (updateUser == null)
@@ -409,7 +409,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public ActionResult UpdateUserPolicy(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromBody] UserPolicy newPolicy)
{
if (newPolicy == null)
@@ -464,7 +464,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public ActionResult UpdateUserConfiguration(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromBody] UserConfiguration userConfig)
{
if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false))
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index f55ff6f3d..48262f062 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -70,7 +71,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the d item.</returns>
[HttpGet("Users/{userId}/Items/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
@@ -93,7 +94,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the user's root folder.</returns>
[HttpGet("Users/{userId}/Items/Root")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<BaseItemDto> GetRootFolder([FromRoute] Guid userId)
+ public ActionResult<BaseItemDto> GetRootFolder([FromRoute, Required] Guid userId)
{
var user = _userManager.GetUserById(userId);
var item = _libraryManager.GetUserRootFolder();
@@ -110,7 +111,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the intros to play.</returns>
[HttpGet("Users/{userId}/Items/{itemId}/Intros")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task<ActionResult<QueryResult<BaseItemDto>>> GetIntros([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public async Task<ActionResult<QueryResult<BaseItemDto>>> GetIntros([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
@@ -138,7 +139,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpPost("Users/{userId}/FavoriteItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
return MarkFavorite(userId, itemId, true);
}
@@ -152,7 +153,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpDelete("Users/{userId}/FavoriteItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
return MarkFavorite(userId, itemId, false);
}
@@ -166,7 +167,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpDelete("Users/{userId}/Items/{itemId}/Rating")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
return UpdateUserItemRatingInternal(userId, itemId, null);
}
@@ -181,7 +182,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpPost("Users/{userId}/Items/{itemId}/Rating")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool? likes)
+ public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] bool? likes)
{
return UpdateUserItemRatingInternal(userId, itemId, likes);
}
@@ -195,7 +196,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>The items local trailers.</returns>
[HttpGet("Users/{userId}/Items/{itemId}/LocalTrailers")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<IEnumerable<BaseItemDto>> GetLocalTrailers([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<IEnumerable<BaseItemDto>> GetLocalTrailers([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
@@ -230,7 +231,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the special features.</returns>
[HttpGet("Users/{userId}/Items/{itemId}/SpecialFeatures")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<IEnumerable<BaseItemDto>> GetSpecialFeatures([FromRoute] Guid userId, [FromRoute] Guid itemId)
+ public ActionResult<IEnumerable<BaseItemDto>> GetSpecialFeatures([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
{
var user = _userManager.GetUserById(userId);
@@ -264,7 +265,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{userId}/Items/Latest")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<IEnumerable<BaseItemDto>> GetLatestMedia(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromQuery] Guid? parentId,
[FromQuery] string? fields,
[FromQuery] string? includeItemTypes,
diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs
index 6df7cc779..d575bfc3b 100644
--- a/Jellyfin.Api/Controllers/UserViewsController.cs
+++ b/Jellyfin.Api/Controllers/UserViewsController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Extensions;
@@ -64,7 +65,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{userId}/Views")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetUserViews(
- [FromRoute] Guid userId,
+ [FromRoute, Required] Guid userId,
[FromQuery] bool? includeExternalContent,
[FromQuery] string? presetViews,
[FromQuery] bool includeHidden = false)
@@ -126,7 +127,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Users/{userId}/GroupingOptions")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptions([FromRoute] Guid userId)
+ public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptions([FromRoute, Required] Guid userId)
{
var user = _userManager.GetUserById(userId);
if (user == null)
diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs
index 92e82727e..2afa878f4 100644
--- a/Jellyfin.Api/Controllers/VideoHlsController.cs
+++ b/Jellyfin.Api/Controllers/VideoHlsController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Threading;
@@ -164,7 +165,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesPlaylistFile]
public async Task<ActionResult> GetLiveHlsStream(
- [FromRoute] Guid itemId,
+ [FromRoute, Required] Guid itemId,
[FromQuery] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 2bf5b4856..c07ee5a9c 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -116,7 +116,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{itemId}/AdditionalParts")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid? userId)
+ public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{
var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
@@ -163,7 +163,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult> DeleteAlternateSources([FromRoute] Guid itemId)
+ public async Task<ActionResult> DeleteAlternateSources([FromRoute, Required] Guid itemId)
{
var video = (Video)_libraryManager.GetItemById(itemId);
@@ -333,8 +333,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesVideoFile]
public async Task<ActionResult> GetVideoStream(
- [FromRoute] Guid itemId,
- [FromRoute] string? container,
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs
index eb91ac23e..4ecf0407b 100644
--- a/Jellyfin.Api/Controllers/YearsController.cs
+++ b/Jellyfin.Api/Controllers/YearsController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
@@ -179,7 +180,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{year}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<BaseItemDto> GetYear([FromRoute] int year, [FromQuery] Guid? userId)
+ public ActionResult<BaseItemDto> GetYear([FromRoute, Required] int year, [FromQuery] Guid? userId)
{
var item = _libraryManager.GetYear(year);
if (item == null)
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index deb54dbe6..884bfbe44 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -72,7 +72,7 @@ namespace Jellyfin.Api.Helpers
return new NoContentResult();
}
- return new PhysicalFileResult(path, contentType);
+ return new PhysicalFileResult(path, contentType) { EnableRangeProcessing = true };
}
/// <summary>
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index b12590080..c11799bc8 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -92,6 +92,7 @@ namespace Jellyfin.Api.Helpers
}
var enableDlnaHeaders = !string.IsNullOrWhiteSpace(streamingRequest.Params) ||
+ streamingRequest.StreamOptions.ContainsKey("dlnaheaders") ||
string.Equals(httpRequest.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase);
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs
index 3858916d1..620e82830 100644
--- a/Jellyfin.Data/Entities/ActivityLog.cs
+++ b/Jellyfin.Data/Entities/ActivityLog.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -11,7 +9,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity referencing an activity log entry.
/// </summary>
- public partial class ActivityLog : IHasConcurrencyToken
+ public class ActivityLog : IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="ActivityLog"/> class.
@@ -32,13 +30,11 @@ namespace Jellyfin.Data.Entities
throw new ArgumentNullException(nameof(type));
}
- this.Name = name;
- this.Type = type;
- this.UserId = userId;
- this.DateCreated = DateTime.UtcNow;
- this.LogSeverity = LogLevel.Trace;
-
- Init();
+ Name = name;
+ Type = type;
+ UserId = userId;
+ DateCreated = DateTime.UtcNow;
+ LogSeverity = LogLevel.Trace;
}
/// <summary>
@@ -47,38 +43,21 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected ActivityLog()
{
- Init();
- }
-
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="type">The type.</param>
- /// <param name="userId">The user's id.</param>
- /// <returns>The new <see cref="ActivityLog"/> instance.</returns>
- public static ActivityLog Create(string name, string type, Guid userId)
- {
- return new ActivityLog(name, type, userId);
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the identity of this instance.
/// This is the key in the backing database.
/// </summary>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
/// <summary>
/// Gets or sets the name.
- /// Required, Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Required, Max length = 512.
+ /// </remarks>
[Required]
[MaxLength(512)]
[StringLength(512)]
@@ -86,24 +65,30 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// Gets or sets the overview.
- /// Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Max length = 512.
+ /// </remarks>
[MaxLength(512)]
[StringLength(512)]
public string Overview { get; set; }
/// <summary>
/// Gets or sets the short overview.
- /// Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Max length = 512.
+ /// </remarks>
[MaxLength(512)]
[StringLength(512)]
public string ShortOverview { get; set; }
/// <summary>
/// Gets or sets the type.
- /// Required, Max length = 256.
/// </summary>
+ /// <remarks>
+ /// Required, Max length = 256.
+ /// </remarks>
[Required]
[MaxLength(256)]
[StringLength(256)]
@@ -111,43 +96,42 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// Gets or sets the user id.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the item id.
- /// Max length = 256.
/// </summary>
+ /// <remarks>
+ /// Max length = 256.
+ /// </remarks>
[MaxLength(256)]
[StringLength(256)]
public string ItemId { get; set; }
/// <summary>
/// Gets or sets the date created. This should be in UTC.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public DateTime DateCreated { get; set; }
/// <summary>
/// Gets or sets the log severity. Default is <see cref="LogLevel.Trace"/>.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public LogLevel LogSeverity { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// Required, ConcurrencyToken.
- /// </summary>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- partial void Init();
-
/// <inheritdoc />
public void OnSavingChanges()
{
diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs
index cda83f6bb..701e4df00 100644
--- a/Jellyfin.Data/Entities/DisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/DisplayPreferences.cs
@@ -1,4 +1,6 @@
-using System;
+#pragma warning disable CA2227
+
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs
index ca12ba421..878811e59 100644
--- a/Jellyfin.Data/Entities/Group.cs
+++ b/Jellyfin.Data/Entities/Group.cs
@@ -1,9 +1,8 @@
-#pragma warning disable CS1591
+#pragma warning disable CA2227
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Interfaces;
@@ -13,11 +12,10 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing a group.
/// </summary>
- public partial class Group : IHasPermissions, IHasConcurrencyToken
+ public class Group : IHasPermissions, IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="Group"/> class.
- /// Public constructor with required data.
/// </summary>
/// <param name="name">The name of the group.</param>
public Group(string name)
@@ -31,33 +29,25 @@ namespace Jellyfin.Data.Entities
Id = Guid.NewGuid();
Permissions = new HashSet<Permission>();
- ProviderMappings = new HashSet<ProviderMapping>();
Preferences = new HashSet<Preference>();
-
- Init();
}
/// <summary>
/// Initializes a new instance of the <see cref="Group"/> class.
- /// Default constructor. Protected due to required properties, but present because EF needs it.
/// </summary>
+ /// <remarks>
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// </remarks>
protected Group()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this group.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
public Guid Id { get; protected set; }
/// <summary>
@@ -71,42 +61,19 @@ namespace Jellyfin.Data.Entities
[StringLength(255)]
public string Name { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, Concurrency Token.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- public void OnSavingChanges()
- {
- RowVersion++;
- }
-
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
-
- [ForeignKey("Permission_GroupPermissions_Id")]
+ /// <summary>
+ /// Gets or sets a collection containing the group's permissions.
+ /// </summary>
public virtual ICollection<Permission> Permissions { get; protected set; }
- [ForeignKey("ProviderMapping_ProviderMappings_Id")]
- public virtual ICollection<ProviderMapping> ProviderMappings { get; protected set; }
-
- [ForeignKey("Preference_Preferences_Id")]
- public virtual ICollection<Preference> Preferences { get; protected set; }
-
/// <summary>
- /// Static create function (for use in LINQ queries, etc.)
+ /// Gets or sets a collection containing the group's preferences.
/// </summary>
- /// <param name="name">The name of this group.</param>
- public static Group Create(string name)
- {
- return new Group(name);
- }
+ public virtual ICollection<Preference> Preferences { get; protected set; }
/// <inheritdoc/>
public bool HasPermission(PermissionKind kind)
@@ -120,6 +87,10 @@ namespace Jellyfin.Data.Entities
Permissions.First(p => p.Kind == kind).Value = value;
}
- partial void Init();
+ /// <inheritdoc />
+ public void OnSavingChanges()
+ {
+ RowVersion++;
+ }
}
}
diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs
index cf0895ad4..ab8452e62 100644
--- a/Jellyfin.Data/Entities/ImageInfo.cs
+++ b/Jellyfin.Data/Entities/ImageInfo.cs
@@ -1,32 +1,65 @@
-#pragma warning disable CS1591
-
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Jellyfin.Data.Entities
{
+ /// <summary>
+ /// An entity representing an image.
+ /// </summary>
public class ImageInfo
{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImageInfo"/> class.
+ /// </summary>
+ /// <param name="path">The path.</param>
public ImageInfo(string path)
{
Path = path;
LastModified = DateTime.UtcNow;
}
- [Key]
- [Required]
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImageInfo"/> class.
+ /// </summary>
+ /// <remarks>
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// </remarks>
+ protected ImageInfo()
+ {
+ }
+
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <remarks>
+ /// Identity, Indexed, Required.
+ /// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
public Guid? UserId { get; protected set; }
+ /// <summary>
+ /// Gets or sets the path of the image.
+ /// </summary>
+ /// <remarks>
+ /// Required.
+ /// </remarks>
[Required]
[MaxLength(512)]
[StringLength(512)]
public string Path { get; set; }
- [Required]
+ /// <summary>
+ /// Gets or sets the date last modified.
+ /// </summary>
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public DateTime LastModified { get; set; }
}
}
diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
index 023cdc740..d81e4a31c 100644
--- a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
@@ -1,12 +1,13 @@
-#pragma warning disable CS1591
-
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Jellyfin.Data.Enums;
namespace Jellyfin.Data.Entities
{
+ /// <summary>
+ /// An entity that represents a user's display preferences for a specific item.
+ /// </summary>
public class ItemDisplayPreferences
{
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs
index 7be22af25..06cd33330 100644
--- a/Jellyfin.Data/Entities/Libraries/Artwork.cs
+++ b/Jellyfin.Data/Entities/Libraries/Artwork.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/Book.cs b/Jellyfin.Data/Entities/Libraries/Book.cs
index 8337788dd..2e63f75bd 100644
--- a/Jellyfin.Data/Entities/Libraries/Book.cs
+++ b/Jellyfin.Data/Entities/Libraries/Book.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
index bd716712b..4a3d290f0 100644
--- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
@@ -8,7 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for a book.
/// </summary>
- public class BookMetadata : Metadata, IHasCompanies
+ public class BookMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="BookMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs
index d9293c3cc..f503de379 100644
--- a/Jellyfin.Data/Entities/Libraries/Chapter.cs
+++ b/Jellyfin.Data/Entities/Libraries/Chapter.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs
index 2e1bbcfb6..39eded752 100644
--- a/Jellyfin.Data/Entities/Libraries/Collection.cs
+++ b/Jellyfin.Data/Entities/Libraries/Collection.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
index c9306f630..4467c9bbd 100644
--- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
@@ -73,7 +73,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// Gets or sets the next item in the collection.
/// </summary>
/// <remarks>
- /// TODO check if this properly updated dependant and has the proper principal relationship
+ /// TODO check if this properly updated dependant and has the proper principal relationship.
/// </remarks>
public virtual CollectionItem Next { get; set; }
@@ -81,7 +81,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// Gets or sets the previous item in the collection.
/// </summary>
/// <remarks>
- /// TODO check if this properly updated dependant and has the proper principal relationship
+ /// TODO check if this properly updated dependant and has the proper principal relationship.
/// </remarks>
public virtual CollectionItem Previous { get; set; }
diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs
index 02da26bc2..3b6ed3309 100644
--- a/Jellyfin.Data/Entities/Libraries/Company.cs
+++ b/Jellyfin.Data/Entities/Libraries/Company.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
index 60cc96a34..8aa0486af 100644
--- a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding metadata for a <see cref="Company"/>.
/// </summary>
- public class CompanyMetadata : Metadata
+ public class CompanyMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="CompanyMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/CustomItem.cs b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
index 6a4f0a537..115489c78 100644
--- a/Jellyfin.Data/Entities/Libraries/CustomItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
index bc1835528..f0daedfbe 100644
--- a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for a custom item.
/// </summary>
- public class CustomItemMetadata : Metadata
+ public class CustomItemMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="CustomItemMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Episode.cs b/Jellyfin.Data/Entities/Libraries/Episode.cs
index 430a11e3c..0bdc2d764 100644
--- a/Jellyfin.Data/Entities/Libraries/Episode.cs
+++ b/Jellyfin.Data/Entities/Libraries/Episode.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
index 348100cb4..7efb840f0 100644
--- a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for an <see cref="Episode"/>.
/// </summary>
- public class EpisodeMetadata : Metadata
+ public class EpisodeMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="EpisodeMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs
index aeedd7bfd..2a2dbd1a5 100644
--- a/Jellyfin.Data/Entities/Libraries/Genre.cs
+++ b/Jellyfin.Data/Entities/Libraries/Genre.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="Genre"/> class.
/// </summary>
/// <param name="name">The name.</param>
- /// <param name="metadata">The metadata.</param>
- public Genre(string name, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public Genre(string name, ItemMetadata itemMetadata)
{
if (string.IsNullOrEmpty(name))
{
@@ -24,12 +24,12 @@ namespace Jellyfin.Data.Entities.Libraries
Name = name;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Genres.Add(this);
+ itemMetadata.Genres.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Metadata.cs b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
index 877bb5fbd..1d2dc0f66 100644
--- a/Jellyfin.Data/Entities/Libraries/Metadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -9,14 +11,14 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An abstract class that holds metadata.
/// </summary>
- public abstract class Metadata : IHasArtwork, IHasConcurrencyToken
+ public abstract class ItemMetadata : IHasArtwork, IHasConcurrencyToken
{
/// <summary>
- /// Initializes a new instance of the <see cref="Metadata"/> class.
+ /// Initializes a new instance of the <see cref="ItemMetadata"/> class.
/// </summary>
/// <param name="title">The title or name of the object.</param>
/// <param name="language">ISO-639-3 3-character language codes.</param>
- protected Metadata(string title, string language)
+ protected ItemMetadata(string title, string language)
{
if (string.IsNullOrEmpty(title))
{
@@ -41,12 +43,12 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Initializes a new instance of the <see cref="Metadata"/> class.
+ /// Initializes a new instance of the <see cref="ItemMetadata"/> class.
/// </summary>
/// <remarks>
/// Default constructor. Protected due to being abstract.
/// </remarks>
- protected Metadata()
+ protected ItemMetadata()
{
}
diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
index 8bc649c98..9924d5728 100644
--- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs
+++ b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
index 6e6de598e..fcfb35bfa 100644
--- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
+++ b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="MetadataProviderId"/> class.
/// </summary>
/// <param name="providerId">The provider id.</param>
- /// <param name="metadata">The metadata entity.</param>
- public MetadataProviderId(string providerId, Metadata metadata)
+ /// <param name="itemMetadata">The metadata entity.</param>
+ public MetadataProviderId(string providerId, ItemMetadata itemMetadata)
{
if (string.IsNullOrEmpty(providerId))
{
@@ -24,12 +24,12 @@ namespace Jellyfin.Data.Entities.Libraries
ProviderId = providerId;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Sources.Add(this);
+ itemMetadata.Sources.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Movie.cs b/Jellyfin.Data/Entities/Libraries/Movie.cs
index 0a8cc83dd..08db904fa 100644
--- a/Jellyfin.Data/Entities/Libraries/Movie.cs
+++ b/Jellyfin.Data/Entities/Libraries/Movie.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
index 31102bf13..aa1501a5c 100644
--- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -8,7 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding the metadata for a movie.
/// </summary>
- public class MovieMetadata : Metadata, IHasCompanies
+ public class MovieMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="MovieMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
index 2ed1f78c5..06aff6f45 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
namespace Jellyfin.Data.Entities.Libraries
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
index cc5919bfe..05c0b0374 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -6,7 +8,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding the metadata for a music album.
/// </summary>
- public class MusicAlbumMetadata : Metadata
+ public class MusicAlbumMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="MusicAlbumMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs
index 8beb3dd08..af4c87b73 100644
--- a/Jellyfin.Data/Entities/Libraries/Person.cs
+++ b/Jellyfin.Data/Entities/Libraries/Person.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
index 5290228d6..cd38ee83d 100644
--- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs
+++ b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -16,17 +18,17 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="PersonRole"/> class.
/// </summary>
/// <param name="type">The role type.</param>
- /// <param name="metadata">The metadata.</param>
- public PersonRole(PersonRoleType type, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public PersonRole(PersonRoleType type, ItemMetadata itemMetadata)
{
Type = type;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.PersonRoles.Add(this);
+ itemMetadata.PersonRoles.Add(this);
Sources = new HashSet<MetadataProviderId>();
}
diff --git a/Jellyfin.Data/Entities/Libraries/Photo.cs b/Jellyfin.Data/Entities/Libraries/Photo.cs
index 44338a4ce..25562ec96 100644
--- a/Jellyfin.Data/Entities/Libraries/Photo.cs
+++ b/Jellyfin.Data/Entities/Libraries/Photo.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
index 1ef9dd5f9..ffc790b57 100644
--- a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity that holds metadata for a photo.
/// </summary>
- public class PhotoMetadata : Metadata
+ public class PhotoMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="PhotoMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs
index ba054a39e..98226cd80 100644
--- a/Jellyfin.Data/Entities/Libraries/Rating.cs
+++ b/Jellyfin.Data/Entities/Libraries/Rating.cs
@@ -14,17 +14,17 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="Rating"/> class.
/// </summary>
/// <param name="value">The value.</param>
- /// <param name="metadata">The metadata.</param>
- public Rating(double value, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public Rating(double value, ItemMetadata itemMetadata)
{
Value = value;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Ratings.Add(this);
+ itemMetadata.Ratings.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs
index 43c7080d7..b633e08fb 100644
--- a/Jellyfin.Data/Entities/Libraries/Release.cs
+++ b/Jellyfin.Data/Entities/Libraries/Release.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/Season.cs b/Jellyfin.Data/Entities/Libraries/Season.cs
index eef788bad..eb6674dbc 100644
--- a/Jellyfin.Data/Entities/Libraries/Season.cs
+++ b/Jellyfin.Data/Entities/Libraries/Season.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
diff --git a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
index eedeb089e..7ce79756b 100644
--- a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity that holds metadata for seasons.
/// </summary>
- public class SeasonMetadata : Metadata
+ public class SeasonMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="SeasonMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Series.cs b/Jellyfin.Data/Entities/Libraries/Series.cs
index e959c1fe0..8c8317d14 100644
--- a/Jellyfin.Data/Entities/Libraries/Series.cs
+++ b/Jellyfin.Data/Entities/Libraries/Series.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
index 898f3006d..877dbfc69 100644
--- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -9,7 +11,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity representing series metadata.
/// </summary>
- public class SeriesMetadata : Metadata, IHasCompanies
+ public class SeriesMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="SeriesMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Track.cs b/Jellyfin.Data/Entities/Libraries/Track.cs
index 09ce82a9b..782bfb5ce 100644
--- a/Jellyfin.Data/Entities/Libraries/Track.cs
+++ b/Jellyfin.Data/Entities/Libraries/Track.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
index 048068a1a..321f93bf2 100644
--- a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding metadata for a track.
/// </summary>
- public class TrackMetadata : Metadata
+ public class TrackMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="TrackMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs
index c0f67f836..d92e5d9d2 100644
--- a/Jellyfin.Data/Entities/Permission.cs
+++ b/Jellyfin.Data/Entities/Permission.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Jellyfin.Data.Enums;
@@ -10,7 +8,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing whether the associated user has a specific permission.
/// </summary>
- public partial class Permission : IHasConcurrencyToken
+ public class Permission : IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="Permission"/> class.
@@ -22,8 +20,6 @@ namespace Jellyfin.Data.Entities
{
Kind = kind;
Value = value;
-
- Init();
}
/// <summary>
@@ -32,21 +28,14 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected Permission()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this permission.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
@@ -56,7 +45,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public PermissionKind Kind { get; protected set; }
/// <summary>
@@ -65,36 +53,16 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool Value { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, ConcurrencyToken.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="kind">The permission kind.</param>
- /// <param name="value">The value of this permission.</param>
- /// <returns>The newly created instance.</returns>
- public static Permission Create(PermissionKind kind, bool value)
- {
- return new Permission(kind, value);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
RowVersion++;
}
-
- partial void Init();
}
}
diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs
index 1797f0a40..4efddf2a4 100644
--- a/Jellyfin.Data/Entities/Preference.cs
+++ b/Jellyfin.Data/Entities/Preference.cs
@@ -31,18 +31,12 @@ namespace Jellyfin.Data.Entities
{
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this preference.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
@@ -52,7 +46,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public PreferenceKind Kind { get; protected set; }
/// <summary>
@@ -66,27 +59,10 @@ namespace Jellyfin.Data.Entities
[StringLength(65535)]
public string Value { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, ConcurrencyToken.
- /// </remarks>
+ /// <inheritdoc/>
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="kind">The preference kind.</param>
- /// <param name="value">The value.</param>
- /// <returns>The new instance.</returns>
- public static Preference Create(PreferenceKind kind, string value)
- {
- return new Preference(kind, value);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
diff --git a/Jellyfin.Data/Entities/ProviderMapping.cs b/Jellyfin.Data/Entities/ProviderMapping.cs
deleted file mode 100644
index 44ebfba76..000000000
--- a/Jellyfin.Data/Entities/ProviderMapping.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace Jellyfin.Data.Entities
-{
- public partial class ProviderMapping
- {
- partial void Init();
-
- /// <summary>
- /// Default constructor. Protected due to required properties, but present because EF needs it.
- /// </summary>
- protected ProviderMapping()
- {
- Init();
- }
-
- /// <summary>
- /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
- /// </summary>
- public static ProviderMapping CreateProviderMappingUnsafe()
- {
- return new ProviderMapping();
- }
-
- /// <summary>
- /// Public constructor with required data.
- /// </summary>
- /// <param name="providername"></param>
- /// <param name="providersecrets"></param>
- /// <param name="providerdata"></param>
- /// <param name="_user0"></param>
- /// <param name="_group1"></param>
- public ProviderMapping(string providername, string providersecrets, string providerdata, User _user0, Group _group1)
- {
- if (string.IsNullOrEmpty(providername))
- {
- throw new ArgumentNullException(nameof(providername));
- }
-
- this.ProviderName = providername;
-
- if (string.IsNullOrEmpty(providersecrets))
- {
- throw new ArgumentNullException(nameof(providersecrets));
- }
-
- this.ProviderSecrets = providersecrets;
-
- if (string.IsNullOrEmpty(providerdata))
- {
- throw new ArgumentNullException(nameof(providerdata));
- }
-
- this.ProviderData = providerdata;
-
- Init();
- }
-
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="providername"></param>
- /// <param name="providersecrets"></param>
- /// <param name="providerdata"></param>
- /// <param name="_user0"></param>
- /// <param name="_group1"></param>
- public static ProviderMapping Create(string providername, string providersecrets, string providerdata, User _user0, Group _group1)
- {
- return new ProviderMapping(providername, providersecrets, providerdata, _user0, _group1);
- }
-
- /*************************************************************************
- * Properties
- *************************************************************************/
-
- /// <summary>
- /// Identity, Indexed, Required.
- /// </summary>
- [Key]
- [Required]
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
-
- /// <summary>
- /// Required, Max length = 255
- /// </summary>
- [Required]
- [MaxLength(255)]
- [StringLength(255)]
- public string ProviderName { get; set; }
-
- /// <summary>
- /// Required, Max length = 65535
- /// </summary>
- [Required]
- [MaxLength(65535)]
- [StringLength(65535)]
- public string ProviderSecrets { get; set; }
-
- /// <summary>
- /// Required, Max length = 65535
- /// </summary>
- [Required]
- [MaxLength(65535)]
- [StringLength(65535)]
- public string ProviderData { get; set; }
-
- /// <summary>
- /// Required, ConcurrenyToken.
- /// </summary>
- [ConcurrencyCheck]
- [Required]
- public uint RowVersion { get; set; }
-
- public void OnSavingChanges()
- {
- RowVersion++;
- }
-
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
- }
-}
-
diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs
index 7ea1f4498..f7ab57a1b 100644
--- a/Jellyfin.Data/Entities/User.cs
+++ b/Jellyfin.Data/Entities/User.cs
@@ -1,4 +1,4 @@
-#pragma warning disable CS1591
+#pragma warning disable CA2227
using System;
using System.Collections.Generic;
@@ -15,7 +15,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing a user.
/// </summary>
- public partial class User : IHasPermissions, IHasConcurrencyToken
+ public class User : IHasPermissions, IHasConcurrencyToken
{
/// <summary>
/// The values being delimited here are Guids, so commas work as they do not appear in Guids.
@@ -75,7 +75,6 @@ namespace Jellyfin.Data.Entities
AddDefaultPermissions();
AddDefaultPreferences();
- Init();
}
/// <summary>
@@ -84,21 +83,14 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected User()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the Id of the user.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[JsonIgnore]
public Guid Id { get; set; }
@@ -139,7 +131,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool MustUpdatePassword { get; set; }
/// <summary>
@@ -180,7 +171,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public int InvalidLoginAttemptCount { get; set; }
/// <summary>
@@ -204,7 +194,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public SubtitlePlaybackMode SubtitleMode { get; set; }
/// <summary>
@@ -213,7 +202,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool PlayDefaultAudioTrack { get; set; }
/// <summary>
@@ -232,7 +220,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool DisplayMissingEpisodes { get; set; }
/// <summary>
@@ -241,7 +228,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool DisplayCollectionsView { get; set; }
/// <summary>
@@ -250,7 +236,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableLocalPassword { get; set; }
/// <summary>
@@ -259,7 +244,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool HidePlayedInLatest { get; set; }
/// <summary>
@@ -268,7 +252,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool RememberAudioSelections { get; set; }
/// <summary>
@@ -277,7 +260,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool RememberSubtitleSelections { get; set; }
/// <summary>
@@ -286,7 +268,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableNextEpisodeAutoPlay { get; set; }
/// <summary>
@@ -295,7 +276,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableAutoLogin { get; set; }
/// <summary>
@@ -304,7 +284,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableUserPreferenceAccess { get; set; }
/// <summary>
@@ -322,7 +301,6 @@ namespace Jellyfin.Data.Entities
/// This is a temporary stopgap for until the library db is migrated.
/// This corresponds to the value of the index of this user in the library db.
/// </summary>
- [Required]
public long InternalId { get; set; }
/// <summary>
@@ -340,7 +318,9 @@ namespace Jellyfin.Data.Entities
[Required]
public virtual DisplayPreferences DisplayPreferences { get; set; }
- [Required]
+ /// <summary>
+ /// Gets or sets the level of sync play permissions this user has.
+ /// </summary>
public SyncPlayAccess SyncPlayAccess { get; set; }
/// <summary>
@@ -350,13 +330,8 @@ namespace Jellyfin.Data.Entities
/// Required, Concurrency Token.
/// </remarks>
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the list of access schedules this user has.
/// </summary>
@@ -395,18 +370,6 @@ namespace Jellyfin.Data.Entities
[ForeignKey("Preference_Preferences_Guid")]
public virtual ICollection<Preference> Preferences { get; protected set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="username">The username for the created user.</param>
- /// <param name="authenticationProviderId">The Id of the user's authentication provider.</param>
- /// <param name="passwordResetProviderId">The Id of the user's password reset provider.</param>
- /// <returns>The created instance.</returns>
- public static User Create(string username, string authenticationProviderId, string passwordResetProviderId)
- {
- return new User(username, authenticationProviderId, passwordResetProviderId);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
@@ -519,7 +482,5 @@ namespace Jellyfin.Data.Entities
Preferences.Add(new Preference(val, string.Empty));
}
}
-
- partial void Init();
}
}
diff --git a/Jellyfin.Data/Enums/ArtKind.cs b/Jellyfin.Data/Enums/ArtKind.cs
index 71b4db6f2..f7a73848c 100644
--- a/Jellyfin.Data/Enums/ArtKind.cs
+++ b/Jellyfin.Data/Enums/ArtKind.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing types of art.
+ /// </summary>
public enum ArtKind
{
- Other,
- Poster,
- Banner,
- Thumbnail,
- Logo
+ /// <summary>
+ /// Another type of art, not covered by the other members.
+ /// </summary>
+ Other = 0,
+
+ /// <summary>
+ /// A poster.
+ /// </summary>
+ Poster = 1,
+
+ /// <summary>
+ /// A banner.
+ /// </summary>
+ Banner = 2,
+
+ /// <summary>
+ /// A thumbnail.
+ /// </summary>
+ Thumbnail = 3,
+
+ /// <summary>
+ /// A logo.
+ /// </summary>
+ Logo = 4
}
}
diff --git a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
index a33cd9d1c..d3d8dd822 100644
--- a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
+++ b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
@@ -1,18 +1,58 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum that represents a day of the week, weekdays, weekends, or all days.
+ /// </summary>
public enum DynamicDayOfWeek
{
+ /// <summary>
+ /// Sunday.
+ /// </summary>
Sunday = 0,
+
+ /// <summary>
+ /// Monday.
+ /// </summary>
Monday = 1,
+
+ /// <summary>
+ /// Tuesday.
+ /// </summary>
Tuesday = 2,
+
+ /// <summary>
+ /// Wednesday.
+ /// </summary>
Wednesday = 3,
+
+ /// <summary>
+ /// Thursday.
+ /// </summary>
Thursday = 4,
+
+ /// <summary>
+ /// Friday.
+ /// </summary>
Friday = 5,
+
+ /// <summary>
+ /// Saturday.
+ /// </summary>
Saturday = 6,
+
+ /// <summary>
+ /// All days of the week.
+ /// </summary>
Everyday = 7,
+
+ /// <summary>
+ /// A week day, or Monday-Friday.
+ /// </summary>
Weekday = 8,
+
+ /// <summary>
+ /// Saturday and Sunday.
+ /// </summary>
Weekend = 9
}
}
diff --git a/Jellyfin.Data/Enums/IndexingKind.cs b/Jellyfin.Data/Enums/IndexingKind.cs
index fafe47e0c..c0df07714 100644
--- a/Jellyfin.Data/Enums/IndexingKind.cs
+++ b/Jellyfin.Data/Enums/IndexingKind.cs
@@ -1,7 +1,8 @@
-#pragma warning disable CS1591
-
-namespace Jellyfin.Data.Enums
+namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a type of indexing in a user's display preferences.
+ /// </summary>
public enum IndexingKind
{
/// <summary>
diff --git a/Jellyfin.Data/Enums/MediaFileKind.cs b/Jellyfin.Data/Enums/MediaFileKind.cs
index b03591fb8..797c26ec2 100644
--- a/Jellyfin.Data/Enums/MediaFileKind.cs
+++ b/Jellyfin.Data/Enums/MediaFileKind.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing the type of media file.
+ /// </summary>
public enum MediaFileKind
{
- Main,
- Sidecar,
- AdditionalPart,
- AlternativeFormat,
- AdditionalStream
+ /// <summary>
+ /// The main file.
+ /// </summary>
+ Main = 0,
+
+ /// <summary>
+ /// A sidecar file.
+ /// </summary>
+ Sidecar = 1,
+
+ /// <summary>
+ /// An additional part to the main file.
+ /// </summary>
+ AdditionalPart = 2,
+
+ /// <summary>
+ /// An alternative format to the main file.
+ /// </summary>
+ AlternativeFormat = 3,
+
+ /// <summary>
+ /// An additional stream for the main file.
+ /// </summary>
+ AdditionalStream = 4
}
}
diff --git a/Jellyfin.Data/Enums/PersonRoleType.cs b/Jellyfin.Data/Enums/PersonRoleType.cs
index 2d80eaa4c..1e619f5ee 100644
--- a/Jellyfin.Data/Enums/PersonRoleType.cs
+++ b/Jellyfin.Data/Enums/PersonRoleType.cs
@@ -1,20 +1,68 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a person's role in a specific media item.
+ /// </summary>
public enum PersonRoleType
{
- Other,
- Director,
- Artist,
- OriginalArtist,
- Actor,
- VoiceActor,
- Producer,
- Remixer,
- Conductor,
- Composer,
- Author,
- Editor
+ /// <summary>
+ /// Another role, not covered by the other types.
+ /// </summary>
+ Other = 0,
+
+ /// <summary>
+ /// The director of the media.
+ /// </summary>
+ Director = 1,
+
+ /// <summary>
+ /// An artist.
+ /// </summary>
+ Artist = 2,
+
+ /// <summary>
+ /// The original artist.
+ /// </summary>
+ OriginalArtist = 3,
+
+ /// <summary>
+ /// An actor.
+ /// </summary>
+ Actor = 4,
+
+ /// <summary>
+ /// A voice actor.
+ /// </summary>
+ VoiceActor = 5,
+
+ /// <summary>
+ /// A producer.
+ /// </summary>
+ Producer = 6,
+
+ /// <summary>
+ /// A remixer.
+ /// </summary>
+ Remixer = 7,
+
+ /// <summary>
+ /// A conductor.
+ /// </summary>
+ Conductor = 8,
+
+ /// <summary>
+ /// A composer.
+ /// </summary>
+ Composer = 9,
+
+ /// <summary>
+ /// An author.
+ /// </summary>
+ Author = 10,
+
+ /// <summary>
+ /// An editor.
+ /// </summary>
+ Editor = 11
}
}
diff --git a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
index c8fc21159..ca41300ed 100644
--- a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
+++ b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
-namespace Jellyfin.Data.Enums
+namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a subtitle playback mode.
+ /// </summary>
public enum SubtitlePlaybackMode
{
+ /// <summary>
+ /// The default subtitle playback mode.
+ /// </summary>
Default = 0,
+
+ /// <summary>
+ /// Always show subtitles.
+ /// </summary>
Always = 1,
+
+ /// <summary>
+ /// Only show forced subtitles.
+ /// </summary>
OnlyForced = 2,
+
+ /// <summary>
+ /// Don't show subtitles.
+ /// </summary>
None = 3,
+
+ /// <summary>
+ /// Only show subtitles when the current audio stream is in a different language.
+ /// </summary>
Smart = 4
}
}
diff --git a/Jellyfin.Data/Enums/UnratedItem.cs b/Jellyfin.Data/Enums/UnratedItem.cs
index 5259e7739..871794086 100644
--- a/Jellyfin.Data/Enums/UnratedItem.cs
+++ b/Jellyfin.Data/Enums/UnratedItem.cs
@@ -1,17 +1,53 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing an unrated item.
+ /// </summary>
public enum UnratedItem
{
- Movie,
- Trailer,
- Series,
- Music,
- Book,
- LiveTvChannel,
- LiveTvProgram,
- ChannelContent,
- Other
+ /// <summary>
+ /// A movie.
+ /// </summary>
+ Movie = 0,
+
+ /// <summary>
+ /// A trailer.
+ /// </summary>
+ Trailer = 1,
+
+ /// <summary>
+ /// A series.
+ /// </summary>
+ Series = 2,
+
+ /// <summary>
+ /// Music.
+ /// </summary>
+ Music = 3,
+
+ /// <summary>
+ /// A book.
+ /// </summary>
+ Book = 4,
+
+ /// <summary>
+ /// A live TV channel
+ /// </summary>
+ LiveTvChannel = 5,
+
+ /// <summary>
+ /// A live TV program.
+ /// </summary>
+ LiveTvProgram = 6,
+
+ /// <summary>
+ /// Channel content.
+ /// </summary>
+ ChannelContent = 7,
+
+ /// <summary>
+ /// Another type, not covered by the other fields.
+ /// </summary>
+ Other = 8
}
}
diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj
index 203eeaf3b..95343f91b 100644
--- a/Jellyfin.Data/Jellyfin.Data.csproj
+++ b/Jellyfin.Data/Jellyfin.Data.csproj
@@ -4,7 +4,7 @@
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
- <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
@@ -45,4 +45,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SharedVersion.cs" />
+ </ItemGroup>
+
</Project>
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 85d5f2a3f..c3bec1c71 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -66,10 +66,13 @@
</ItemGroup>
<ItemGroup>
+ <None Update="wwwroot\api-docs\redoc\custom.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
<None Update="wwwroot\api-docs\swagger\custom.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Update="wwwroot\api-docs\redoc\custom.css">
+ <None Update="wwwroot\api-docs\banner-dark.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
diff --git a/Jellyfin.Server/wwwroot/api-docs/banner-dark.svg b/Jellyfin.Server/wwwroot/api-docs/banner-dark.svg
new file mode 100644
index 000000000..b62b7545c
--- /dev/null
+++ b/Jellyfin.Server/wwwroot/api-docs/banner-dark.svg
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Part of the Jellyfin project (https://jellyfin.media)
+ -
+ - All copyright belongs to the Jellyfin contributors; a full list can
+ - be found in the file CONTRIBUTORS.md
+ -
+ - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
+ - To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
+- ***** END LICENSE BLOCK ***** -->
+<svg id="banner-dark" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1536 512">
+ <defs>
+ <linearGradient id="linear-gradient" x1="110.25" y1="213.3" x2="496.14" y2="436.09" gradientUnits="userSpaceOnUse">
+ <stop offset="0" stop-color="#aa5cc3"/>
+ <stop offset="1" stop-color="#00a4dc"/>
+ </linearGradient>
+ </defs>
+ <title>banner-dark</title>
+ <g id="banner-dark">
+ <g id="banner-dark-icon">
+ <path id="inner-shape" d="M261.42,201.62c-20.44,0-86.24,119.29-76.2,139.43s142.48,19.92,152.4,0S281.86,201.63,261.42,201.62Z" fill="url(#linear-gradient)"/>
+ <path id="outer-shape" d="M261.42,23.3C199.83,23.3,1.57,382.73,31.8,443.43s429.34,60,459.24,0S323,23.3,261.42,23.3ZM411.9,390.76c-19.59,39.33-281.08,39.77-300.9,0S221.1,115.48,261.45,115.48,431.49,351.42,411.9,390.76Z" fill="url(#linear-gradient)"/>
+ </g>
+ <g id="jellyfin-light-outlines" style="isolation:isolate" transform="translate(43.8)">
+ <path d="M556.64,350.75a67,67,0,0,1-22.87-27.47,8.91,8.91,0,0,1-1.49-4.75,7.42,7.42,0,0,1,2.83-5.94,9.25,9.25,0,0,1,6.09-2.38c3.16,0,5.94,1.69,8.31,5.05a48.09,48.09,0,0,0,16.34,20.34,40.59,40.59,0,0,0,24,7.58q20.51,0,33.27-12.62t12.77-33.12V159a8.44,8.44,0,0,1,2.67-6.39,9.56,9.56,0,0,1,6.83-2.52,9,9,0,0,1,6.68,2.52,8.7,8.7,0,0,1,2.53,6.39v138.4a64.7,64.7,0,0,1-8.32,32.67,59,59,0,0,1-23,22.72Q608.62,361,589.9,361A57.21,57.21,0,0,1,556.64,350.75Z" fill="#fff"/>
+ <path d="M831.66,279.47a8.77,8.77,0,0,1-6.24,2.53H713.16q0,17.82,7.27,31.92a54.91,54.91,0,0,0,20.79,22.28q13.51,8.18,31.93,8.17a54,54,0,0,0,25.54-5.94,52.7,52.7,0,0,0,18.12-15.15,10,10,0,0,1,6.24-2.67,8.14,8.14,0,0,1,7.72,7.72,8.81,8.81,0,0,1-3,6.24,74.7,74.7,0,0,1-23.91,19A65.56,65.56,0,0,1,773.45,361q-22.87,0-40.4-9.8a69.51,69.51,0,0,1-27.32-27.48q-9.79-17.66-9.8-40.83,0-24.36,9.65-42.62t25.69-27.92a65.2,65.2,0,0,1,34.16-9.65A70,70,0,0,1,798.84,211a65.78,65.78,0,0,1,25.39,24.36q9.81,16,10.1,38A8.07,8.07,0,0,1,831.66,279.47ZM733.5,231.8Q718.8,243.68,714.64,266H815.92v-2.38A46.91,46.91,0,0,0,807,240.27a48.47,48.47,0,0,0-18.56-15.15,54,54,0,0,0-23-5.2Q748.2,219.92,733.5,231.8Z" fill="#fff"/>
+ <path d="M888.24,355.5a8.92,8.92,0,0,1-15.3-6.38v-202a8.91,8.91,0,1,1,17.82,0v202A8.65,8.65,0,0,1,888.24,355.5Z" fill="#fff"/>
+ <path d="M956.55,355.5a8.92,8.92,0,0,1-15.3-6.38v-202a8.91,8.91,0,1,1,17.82,0v202A8.65,8.65,0,0,1,956.55,355.5Z" fill="#fff"/>
+ <path d="M1122.86,206.11a8.7,8.7,0,0,1,2.53,6.39v131q0,23.44-9.21,40.09a61.58,61.58,0,0,1-25.54,25.25q-16.34,8.61-36.83,8.61a96.73,96.73,0,0,1-23.31-2.68,61.72,61.72,0,0,1-18-7.12q-6.24-3.87-6.24-8.62a17.94,17.94,0,0,1,.6-3,8.06,8.06,0,0,1,3-4.45,7.49,7.49,0,0,1,4.45-1.49,7.91,7.91,0,0,1,3.56.89q19,10.39,36.24,10.4,24.65,0,39.06-15.44t14.4-42.18V333.38a54.37,54.37,0,0,1-21.38,20,62.55,62.55,0,0,1-30.3,7.58q-25.83,0-39.2-15.45t-13.37-41.87V212.5a8.91,8.91,0,1,1,17.82,0V301q0,21.39,9.36,32.38t29.25,11a48,48,0,0,0,23.32-6.09,49.88,49.88,0,0,0,17.82-16,37.44,37.44,0,0,0,6.68-21.24V212.5a9,9,0,0,1,15.29-6.39Z" fill="#fff"/>
+ <path d="M1210.18,161.41q-5.21,6.24-5.2,17.23v30.59h33.27a8.19,8.19,0,0,1,5.79,2.38,8.26,8.26,0,0,1,0,11.88,8.22,8.22,0,0,1-5.79,2.37H1205V349.12a8.91,8.91,0,1,1-17.82,0V225.86h-21.68a7.83,7.83,0,0,1-5.94-2.52,8.21,8.21,0,0,1-2.37-5.79,8,8,0,0,1,2.37-6.09,8.33,8.33,0,0,1,5.94-2.23h21.68V178.64q0-18.7,10.84-29t29-10.24a46.1,46.1,0,0,1,15.45,2.52q7.13,2.53,7.12,8.17a8.07,8.07,0,0,1-2.37,5.94,7.37,7.37,0,0,1-5.35,2.37,18.81,18.81,0,0,1-6.53-1.48,42,42,0,0,0-10.4-1.78Q1215.37,155.18,1210.18,161.41ZM1276,180.87c-2.19-1.88-3.27-4.61-3.27-8.17v-3q0-5.34,3.41-8.17t9.36-2.82q11.88,0,11.88,11v3c0,3.56-1,6.29-3.12,8.17s-5.1,2.82-9.06,2.82S1278.14,182.75,1276,180.87Zm15.59,174.63a8.92,8.92,0,0,1-15.3-6.38V212.5a8.91,8.91,0,1,1,17.82,0V349.12A8.65,8.65,0,0,1,1291.56,355.5Z" fill="#fff"/>
+ <path d="M1452.53,218.88q12.92,16.2,12.92,42.92v87.32a8.4,8.4,0,0,1-2.67,6.38,8.8,8.8,0,0,1-6.24,2.53,8.64,8.64,0,0,1-8.91-8.91V262.69q0-19.31-9.65-31.33t-29.85-12a53.28,53.28,0,0,0-42.77,21.83,36.24,36.24,0,0,0-7.13,21.53v86.43a8.91,8.91,0,1,1-17.82,0V216.06a8.91,8.91,0,1,1,17.82,0V232.4q8-12.77,23-21.24A61.84,61.84,0,0,1,1412,202.7Q1439.61,202.7,1452.53,218.88Z" fill="#fff"/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css b/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css
index e69de29bb..acb59888e 100644
--- a/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css
+++ b/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css
@@ -0,0 +1,15 @@
+/* logo */
+.topbar-wrapper img[alt="Swagger UI"], .topbar-wrapper span {
+ visibility: collapse;
+}
+
+.topbar-wrapper .link:after {
+ content: url(../banner-dark.svg);
+ display: block;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ max-width: 100%;
+ max-height: 100%;
+ width: 150px;
+}
+/* end logo */
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
index 07167bda6..c088d8cec 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
@@ -154,6 +154,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
item.IndexNumber = Convert.ToInt32(episode.DvdEpisodeNumber ?? episode.AiredEpisodeNumber);
item.ParentIndexNumber = episode.DvdSeason ?? episode.AiredSeason;
}
+ else if (string.Equals(id.SeriesDisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase))
+ {
+ if (episode.AbsoluteNumber.GetValueOrDefault() != 0)
+ {
+ item.IndexNumber = episode.AbsoluteNumber;
+ }
+ }
else if (episode.AiredEpisodeNumber.HasValue)
{
item.IndexNumber = episode.AiredEpisodeNumber;
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 75587da1f..fd45dca2a 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -66,8 +66,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Data", "Jellyfin.D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server.Implementations", "Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj", "{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.Api.Tests", "tests\MediaBrowser.Api.Tests\MediaBrowser.Api.Tests.csproj", "{7C93C84F-105C-48E5-A878-406FA0A5B296}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -178,10 +176,6 @@ Global
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.Build.0 = Release|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
index 5d7f7765c..6fc287420 100644
--- a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs
+++ b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Branding;
using Xunit;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
public sealed class BrandingServiceTests : IClassFixture<JellyfinApplicationFactory>
{
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 368b6bf0b..bcba3a203 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -16,6 +16,7 @@
<PackageReference Include="AutoFixture" Version="4.13.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
diff --git a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
index 2029f88e9..77f1640fa 100644
--- a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs
+++ b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
/// <summary>
/// Factory for bootstrapping the Jellyfin application in memory for functional end to end tests.
diff --git a/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
new file mode 100644
index 000000000..3a85b5514
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using System.Reflection;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Branding;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Jellyfin.Api.Tests
+{
+ public sealed class OpenApiSpecTests : IClassFixture<JellyfinApplicationFactory>
+ {
+ private readonly JellyfinApplicationFactory _factory;
+ private readonly ITestOutputHelper _outputHelper;
+
+ public OpenApiSpecTests(JellyfinApplicationFactory factory, ITestOutputHelper outputHelper)
+ {
+ _factory = factory;
+ _outputHelper = outputHelper;
+ }
+
+ [Fact]
+ public async Task GetSpec_ReturnsCorrectResponse()
+ {
+ // Arrange
+ var client = _factory.CreateClient();
+
+ // Act
+ var response = await client.GetAsync("/api-docs/openapi.json");
+
+ // Assert
+ response.EnsureSuccessStatusCode();
+ Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
+
+ // Write out for publishing
+ var responseBody = await response.Content.ReadAsStringAsync();
+ string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
+ _outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
+ File.WriteAllText(outputPath, responseBody);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs b/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
index 917d8fb3a..ed971eed7 100644
--- a/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
@@ -47,6 +47,10 @@ namespace Jellyfin.Naming.Tests.Video
// FIXME: [InlineData("Robin Hood [Multi-Subs] [2018].mkv", "Robin Hood", 2018)]
[InlineData(@"3.Days.to.Kill.2014.720p.BluRay.x264.YIFY.mkv", "3.Days.to.Kill", 2014)] // In this test case, running CleanDateTime first produces no date, so it will attempt to run CleanString first and then CleanDateTime again
[InlineData("3 days to kill (2005).mkv", "3 days to kill", 2005)]
+ [InlineData("My Movie 2013.12.09", "My Movie 2013.12.09", null)]
+ [InlineData("My Movie 2013-12-09", "My Movie 2013-12-09", null)]
+ [InlineData("My Movie 20131209", "My Movie 20131209", null)]
+ [InlineData("My Movie 2013-12-09 2013", "My Movie 2013-12-09", 2013)]
public void CleanDateTimeTest(string input, string expectedName, int? expectedYear)
{
input = Path.GetFileName(input);
diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
deleted file mode 100644
index b3fd853e2..000000000
--- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
+++ /dev/null
@@ -1,34 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>netcoreapp3.1</TargetFramework>
- <IsPackable>false</IsPackable>
- <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
- <Nullable>enable</Nullable>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.7" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="1.3.0" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\Jellyfin.Server\Jellyfin.Server.csproj" />
- </ItemGroup>
-
- <!-- Code Analyzers -->
- <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
- <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
- <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
- </ItemGroup>
-
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
-
-</Project>
diff --git a/tests/jellyfin-tests.ruleset b/tests/jellyfin-tests.ruleset
index 5a113e955..e2abaf5bb 100644
--- a/tests/jellyfin-tests.ruleset
+++ b/tests/jellyfin-tests.ruleset
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<RuleSet Name="Rules for MediaBrowser.Api.Tests" Description="Code analysis rules for MediaBrowser.Api.Tests.csproj" ToolsVersion="14.0">
+<RuleSet Name="Rules for Jellyfin.Api.Tests" Description="Code analysis rules for Jellyfin.Api.Tests.csproj" ToolsVersion="14.0">
<!-- Include the solution default RuleSet. The rules in this file will override the defaults. -->
<Include Path="../jellyfin.ruleset" Action="Default" />
@@ -17,6 +17,6 @@
<!-- CA2007: Consider calling ConfigureAwait on the awaited task -->
<Rule Id="CA2007" Action="None" />
<!-- CA2234: Pass system uri objects instead of strings -->
- <Rule Id="CA2234" Action="Info" />
+ <Rule Id="CA2234" Action="Info" />
</Rules>
</RuleSet>