aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaus Vium <cvium@users.noreply.github.com>2021-12-15 08:38:39 +0100
committerGitHub <noreply@github.com>2021-12-15 08:38:39 +0100
commit9a0618552b87241537590e77c70cfdbac2b0b8ce (patch)
treeefc0d946cd6fc9db7b09e85cfa4185120e007c57
parentc3c4dc6839d19cda8b0ea3cdcdc84547a713506d (diff)
parent4a58582ad588eae0571eb6e7f1c830d5550709ea (diff)
Merge branch 'master' into what_could_go_wrong
-rw-r--r--.ci/azure-pipelines-package.yml20
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs46
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs2
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs18
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs2
-rw-r--r--Emby.Server.Implementations/Channels/ChannelPostScanTask.cs3
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs139
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs2
-rw-r--r--Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs16
-rw-r--r--Emby.Server.Implementations/Images/DynamicImageProvider.cs3
-rw-r--r--Emby.Server.Implementations/Images/GenreImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/MusicGenreImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs4
-rw-r--r--Emby.Server.Implementations/Library/PathExtensions.cs30
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs37
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs46
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs16
-rw-r--r--Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs3
-rw-r--r--Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs4
-rw-r--r--Emby.Server.Implementations/Library/Validators/PeopleValidator.cs3
-rw-r--r--Emby.Server.Implementations/Library/Validators/StudiosValidator.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs14
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs11
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs28
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/eo.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ja.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/lt-LT.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/mk.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/ro.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/zu.json30
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistsFolder.cs3
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs2
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs8
-rw-r--r--Jellyfin.Api/Controllers/ArtistsController.cs8
-rw-r--r--Jellyfin.Api/Controllers/FilterController.cs4
-rw-r--r--Jellyfin.Api/Controllers/GenresController.cs14
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs12
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs37
-rw-r--r--Jellyfin.Api/Controllers/MoviesController.cs26
-rw-r--r--Jellyfin.Api/Controllers/MusicGenresController.cs14
-rw-r--r--Jellyfin.Api/Controllers/SearchController.cs4
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs2
-rw-r--r--Jellyfin.Api/Controllers/StartupController.cs2
-rw-r--r--Jellyfin.Api/Controllers/StudiosController.cs4
-rw-r--r--Jellyfin.Api/Controllers/SuggestionsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/TvShowsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs2
-rw-r--r--Jellyfin.Api/Controllers/YearsController.cs4
-rw-r--r--Jellyfin.Api/Helpers/ClassMigrationHelper.cs71
-rw-r--r--Jellyfin.Api/Helpers/RequestHelpers.cs16
-rw-r--r--Jellyfin.Networking/Configuration/NetworkConfigurationFactory.cs6
-rw-r--r--Jellyfin.Networking/Configuration/NetworkConfigurationStore.cs24
-rw-r--r--Jellyfin.Networking/Manager/NetworkManager.cs2
-rw-r--r--Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj2
-rw-r--r--Jellyfin.Server/Migrations/MigrationRunner.cs65
-rw-r--r--Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs138
-rw-r--r--Jellyfin.Server/Program.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs3
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs10
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs12
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs12
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs40
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs7
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs27
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs23
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs222
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs4
-rw-r--r--MediaBrowser.Model/Querying/LatestItemsQuery.cs3
-rw-r--r--MediaBrowser.Model/Search/SearchQuery.cs9
-rw-r--r--MediaBrowser.Model/Session/BrowseRequest.cs5
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs3
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioResolver.cs176
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs22
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs32
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs3
-rwxr-xr-xbump_version22
-rw-r--r--debian/jellyfin.service15
-rw-r--r--fedora/Makefile59
-rw-r--r--fedora/jellyfin-server-lowports.conf4
-rw-r--r--fedora/jellyfin.spec20
-rw-r--r--tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs30
-rw-r--r--tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs7
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs12
96 files changed, 1036 insertions, 770 deletions
diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml
index 81693452f..89f7137fd 100644
--- a/.ci/azure-pipelines-package.yml
+++ b/.ci/azure-pipelines-package.yml
@@ -39,6 +39,14 @@ jobs:
vmImage: 'ubuntu-latest'
steps:
+ - script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
+ displayName: Set release version (stable)
+ condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+
+ - script: './bump-version $(JellyfinVersion)'
+ displayName: Bump internal version (stable)
+ condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-server-$(BuildConfiguration) deployment'
displayName: 'Build Dockerfile'
@@ -80,6 +88,14 @@ jobs:
vmImage: 'ubuntu-latest'
steps:
+ - script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
+ displayName: Set release version (stable)
+ condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+
+ - script: './bump-version $(JellyfinVersion)'
+ displayName: Bump internal version (stable)
+ condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+
- task: DownloadPipelineArtifact@2
displayName: 'Download OpenAPI Spec'
inputs:
@@ -127,6 +143,10 @@ jobs:
displayName: Set release version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+ - script: './bump-version $(JellyfinVersion)'
+ displayName: Bump internal version (stable)
+ condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
+
- task: Docker@2
displayName: 'Push Unstable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 5c4a031bc..d52e13324 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -150,6 +150,7 @@
- [ianjazz246](https://github.com/ianjazz246)
- [peterspenler](https://github.com/peterspenler)
- [MBR-0001](https://github.com/MBR-0001)
+ - [jonas-resch](https://github.com/jonas-resch)
# Emby Contributors
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 26a816107..b354421ea 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -539,7 +539,7 @@ namespace Emby.Dlna.ContentDirectory
User = user,
Recursive = true,
IsMissing = false,
- ExcludeItemTypes = new[] { nameof(Book) },
+ ExcludeItemTypes = new[] { BaseItemKind.Book },
IsFolder = isFolder,
MediaTypes = mediaTypes,
DtoOptions = GetDtoOptions()
@@ -619,7 +619,7 @@ namespace Emby.Dlna.ContentDirectory
Limit = limit,
StartIndex = startIndex,
IsVirtualItem = false,
- ExcludeItemTypes = new[] { nameof(Book) },
+ ExcludeItemTypes = new[] { BaseItemKind.Book },
IsPlaceHolder = false,
DtoOptions = GetDtoOptions(),
OrderBy = GetOrderBy(sort, folder.IsPreSorted)
@@ -644,7 +644,7 @@ namespace Emby.Dlna.ContentDirectory
{
StartIndex = startIndex,
Limit = limit,
- IncludeItemTypes = new[] { nameof(LiveTvChannel) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel },
OrderBy = GetOrderBy(sort, false)
};
@@ -675,23 +675,23 @@ namespace Emby.Dlna.ContentDirectory
switch (stubType)
{
case StubType.Latest:
- return GetLatest(item, query, nameof(Audio));
+ return GetLatest(item, query, BaseItemKind.Audio);
case StubType.Playlists:
return GetMusicPlaylists(query);
case StubType.Albums:
- return GetChildrenOfItem(item, query, nameof(MusicAlbum));
+ return GetChildrenOfItem(item, query, BaseItemKind.MusicAlbum);
case StubType.Artists:
return GetMusicArtists(item, query);
case StubType.AlbumArtists:
return GetMusicAlbumArtists(item, query);
case StubType.FavoriteAlbums:
- return GetChildrenOfItem(item, query, nameof(MusicAlbum), true);
+ return GetChildrenOfItem(item, query, BaseItemKind.MusicAlbum, true);
case StubType.FavoriteArtists:
return GetFavoriteArtists(item, query);
case StubType.FavoriteSongs:
- return GetChildrenOfItem(item, query, nameof(Audio), true);
+ return GetChildrenOfItem(item, query, BaseItemKind.Audio, true);
case StubType.Songs:
- return GetChildrenOfItem(item, query, nameof(Audio));
+ return GetChildrenOfItem(item, query, BaseItemKind.Audio);
case StubType.Genres:
return GetMusicGenres(item, query);
}
@@ -746,13 +746,13 @@ namespace Emby.Dlna.ContentDirectory
case StubType.ContinueWatching:
return GetMovieContinueWatching(item, query);
case StubType.Latest:
- return GetLatest(item, query, nameof(Movie));
+ return GetLatest(item, query, BaseItemKind.Movie);
case StubType.Movies:
- return GetChildrenOfItem(item, query, nameof(Movie));
+ return GetChildrenOfItem(item, query, BaseItemKind.Movie);
case StubType.Collections:
return GetMovieCollections(query);
case StubType.Favorites:
- return GetChildrenOfItem(item, query, nameof(Movie), true);
+ return GetChildrenOfItem(item, query, BaseItemKind.Movie, true);
case StubType.Genres:
return GetGenres(item, query);
}
@@ -831,13 +831,13 @@ namespace Emby.Dlna.ContentDirectory
case StubType.NextUp:
return GetNextUp(item, query);
case StubType.Latest:
- return GetLatest(item, query, nameof(Episode));
+ return GetLatest(item, query, BaseItemKind.Episode);
case StubType.Series:
- return GetChildrenOfItem(item, query, nameof(Series));
+ return GetChildrenOfItem(item, query, BaseItemKind.Series);
case StubType.FavoriteSeries:
- return GetChildrenOfItem(item, query, nameof(Series), true);
+ return GetChildrenOfItem(item, query, BaseItemKind.Series, true);
case StubType.FavoriteEpisodes:
- return GetChildrenOfItem(item, query, nameof(Episode), true);
+ return GetChildrenOfItem(item, query, BaseItemKind.Episode, true);
case StubType.Genres:
return GetGenres(item, query);
}
@@ -898,7 +898,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMovieCollections(InternalItemsQuery query)
{
query.Recursive = true;
- query.IncludeItemTypes = new[] { nameof(BoxSet) };
+ query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
var result = _libraryManager.GetItemsResult(query);
@@ -913,7 +913,7 @@ namespace Emby.Dlna.ContentDirectory
/// <param name="itemType">The item type.</param>
/// <param name="isFavorite">A value indicating whether to only fetch favorite items.</param>
/// <returns>The <see cref="QueryResult{ServerItem}"/>.</returns>
- private QueryResult<ServerItem> GetChildrenOfItem(BaseItem parent, InternalItemsQuery query, string itemType, bool isFavorite = false)
+ private QueryResult<ServerItem> GetChildrenOfItem(BaseItem parent, InternalItemsQuery query, BaseItemKind itemType, bool isFavorite = false)
{
query.Recursive = true;
query.Parent = parent;
@@ -1013,7 +1013,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMusicPlaylists(InternalItemsQuery query)
{
query.Parent = null;
- query.IncludeItemTypes = new[] { nameof(Playlist) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Playlist };
query.Recursive = true;
var result = _libraryManager.GetItemsResult(query);
@@ -1052,7 +1052,7 @@ namespace Emby.Dlna.ContentDirectory
/// <param name="query">The <see cref="InternalItemsQuery"/>.</param>
/// <param name="itemType">The item type.</param>
/// <returns>The <see cref="QueryResult{ServerItem}"/>.</returns>
- private QueryResult<ServerItem> GetLatest(BaseItem parent, InternalItemsQuery query, string itemType)
+ private QueryResult<ServerItem> GetLatest(BaseItem parent, InternalItemsQuery query, BaseItemKind itemType)
{
query.OrderBy = Array.Empty<(string, SortOrder)>();
@@ -1086,7 +1086,7 @@ namespace Emby.Dlna.ContentDirectory
{
Recursive = true,
ArtistIds = new[] { item.Id },
- IncludeItemTypes = new[] { nameof(MusicAlbum) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions(),
@@ -1115,8 +1115,8 @@ namespace Emby.Dlna.ContentDirectory
GenreIds = new[] { item.Id },
IncludeItemTypes = new[]
{
- nameof(Movie),
- nameof(Series)
+ BaseItemKind.Movie,
+ BaseItemKind.Series
},
Limit = limit,
StartIndex = startIndex,
@@ -1144,7 +1144,7 @@ namespace Emby.Dlna.ContentDirectory
{
Recursive = true,
GenreIds = new[] { item.Id },
- IncludeItemTypes = new[] { nameof(MusicAlbum) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions(),
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index f35d90f21..08f639d93 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -124,7 +124,7 @@ namespace Emby.Dlna.Main
config);
Current = this;
- var netConfig = config.GetConfiguration<NetworkConfiguration>("network");
+ var netConfig = config.GetConfiguration<NetworkConfiguration>(NetworkConfigurationStore.StoreKey);
_disabled = appHost.ListenWithHttps && netConfig.RequireHttps;
if (_disabled && _config.GetDlnaConfiguration().EnableServer)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 903c31133..8892f7f40 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -313,22 +313,6 @@ namespace Emby.Server.Implementations
? Environment.MachineName
: ConfigurationManager.Configuration.ServerName;
- /// <summary>
- /// Temporary function to migration network settings out of system.xml and into network.xml.
- /// TODO: remove at the point when a fixed migration path has been decided upon.
- /// </summary>
- private void MigrateNetworkConfiguration()
- {
- string path = Path.Combine(ConfigurationManager.CommonApplicationPaths.ConfigurationDirectoryPath, "network.xml");
- if (!File.Exists(path))
- {
- var networkSettings = new NetworkConfiguration();
- ClassMigrationHelper.CopyProperties(ConfigurationManager.Configuration, networkSettings);
- _xmlSerializer.SerializeToFile(networkSettings, path);
- Logger.LogDebug("Successfully migrated network settings.");
- }
- }
-
public string ExpandVirtualPath(string path)
{
var appPaths = ApplicationPaths;
@@ -513,8 +497,6 @@ namespace Emby.Server.Implementations
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
- // Have to migrate settings here as migration subsystem not yet initialised.
- MigrateNetworkConfiguration();
NetManager = new NetworkManager(ConfigurationManager, LoggerFactory.CreateLogger<NetworkManager>());
// Initialize runtime stat collection
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index f65eaec1c..8c167824e 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -541,7 +541,7 @@ namespace Emby.Server.Implementations.Channels
return _libraryManager.GetItemIds(
new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Channel) },
+ IncludeItemTypes = new[] { BaseItemKind.Channel },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }
}).Select(i => GetChannelFeatures(i)).ToArray();
}
diff --git a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs
index 2391eed42..b358ba4d5 100644
--- a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs
+++ b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs
@@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -51,7 +52,7 @@ namespace Emby.Server.Implementations.Channels
var uninstalledChannels = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Channel) },
+ IncludeItemTypes = new[] { BaseItemKind.Channel },
ExcludeItemIds = installedChannelIds.ToArray()
});
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 13f1df7c8..48c3710cb 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -196,57 +196,56 @@ namespace Emby.Server.Implementations.Data
private static readonly string _mediaAttachmentInsertPrefix;
- private static readonly HashSet<string> _programTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _programTypes = new[]
{
- "Program",
- "TvChannel",
- "LiveTvProgram",
- "LiveTvTvChannel"
+ BaseItemKind.Program,
+ BaseItemKind.TvChannel,
+ BaseItemKind.LiveTvProgram,
+ BaseItemKind.LiveTvChannel
};
- private static readonly HashSet<string> _programExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _programExcludeParentTypes = new[]
{
- "Series",
- "Season",
- "MusicAlbum",
- "MusicArtist",
- "PhotoAlbum"
+ BaseItemKind.Series,
+ BaseItemKind.Season,
+ BaseItemKind.MusicAlbum,
+ BaseItemKind.MusicArtist,
+ BaseItemKind.PhotoAlbum
};
- private static readonly HashSet<string> _serviceTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _serviceTypes = new[]
{
- "TvChannel",
- "LiveTvTvChannel"
+ BaseItemKind.TvChannel,
+ BaseItemKind.LiveTvChannel
};
- private static readonly HashSet<string> _startDateTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _startDateTypes = new[]
{
- "Program",
- "LiveTvProgram"
+ BaseItemKind.Program,
+ BaseItemKind.LiveTvProgram
};
- private static readonly HashSet<string> _seriesTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _seriesTypes = new[]
{
- "Book",
- "AudioBook",
- "Episode",
- "Season"
+ BaseItemKind.Book,
+ BaseItemKind.AudioBook,
+ BaseItemKind.Episode,
+ BaseItemKind.Season
};
- private static readonly HashSet<string> _artistExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _artistExcludeParentTypes = new[]
{
- "Series",
- "Season",
- "PhotoAlbum"
+ BaseItemKind.Series,
+ BaseItemKind.Season,
+ BaseItemKind.PhotoAlbum
};
- private static readonly HashSet<string> _artistsTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly BaseItemKind[] _artistsTypes = new[]
{
- "Audio",
- "MusicAlbum",
- "MusicVideo",
- "AudioBook",
- "AudioPodcast"
+ BaseItemKind.Audio,
+ BaseItemKind.MusicAlbum,
+ BaseItemKind.MusicVideo,
+ BaseItemKind.AudioBook
};
private static readonly Type[] _knownTypes =
@@ -2212,7 +2211,7 @@ namespace Emby.Server.Implementations.Data
private bool HasProgramAttributes(InternalItemsQuery query)
{
- if (_programExcludeParentTypes.Contains(query.ParentType))
+ if (query.ParentType != null && _programExcludeParentTypes.Contains(query.ParentType.Value))
{
return false;
}
@@ -2227,7 +2226,7 @@ namespace Emby.Server.Implementations.Data
private bool HasServiceName(InternalItemsQuery query)
{
- if (_programExcludeParentTypes.Contains(query.ParentType))
+ if (query.ParentType != null && _programExcludeParentTypes.Contains(query.ParentType.Value))
{
return false;
}
@@ -2242,7 +2241,7 @@ namespace Emby.Server.Implementations.Data
private bool HasStartDate(InternalItemsQuery query)
{
- if (_programExcludeParentTypes.Contains(query.ParentType))
+ if (query.ParentType != null && _programExcludeParentTypes.Contains(query.ParentType.Value))
{
return false;
}
@@ -2262,7 +2261,7 @@ namespace Emby.Server.Implementations.Data
return true;
}
- return query.IncludeItemTypes.Contains("Episode", StringComparer.OrdinalIgnoreCase);
+ return query.IncludeItemTypes.Contains(BaseItemKind.Episode);
}
private bool HasTrailerTypes(InternalItemsQuery query)
@@ -2272,12 +2271,12 @@ namespace Emby.Server.Implementations.Data
return true;
}
- return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase);
+ return query.IncludeItemTypes.Contains(BaseItemKind.Trailer);
}
private bool HasArtistFields(InternalItemsQuery query)
{
- if (_artistExcludeParentTypes.Contains(query.ParentType))
+ if (query.ParentType != null && _artistExcludeParentTypes.Contains(query.ParentType.Value))
{
return false;
}
@@ -2292,7 +2291,7 @@ namespace Emby.Server.Implementations.Data
private bool HasSeriesFields(InternalItemsQuery query)
{
- if (string.Equals(query.ParentType, "PhotoAlbum", StringComparison.OrdinalIgnoreCase))
+ if (query.ParentType == BaseItemKind.PhotoAlbum)
{
return false;
}
@@ -3487,8 +3486,8 @@ namespace Emby.Server.Implementations.Data
if (query.IsMovie == true)
{
if (query.IncludeItemTypes.Length == 0
- || query.IncludeItemTypes.Contains(nameof(Movie))
- || query.IncludeItemTypes.Contains(nameof(Trailer)))
+ || query.IncludeItemTypes.Contains(BaseItemKind.Movie)
+ || query.IncludeItemTypes.Contains(BaseItemKind.Trailer))
{
whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
}
@@ -3563,15 +3562,15 @@ namespace Emby.Server.Implementations.Data
statement?.TryBind("@IsFolder", query.IsFolder);
}
- var includeTypes = query.IncludeItemTypes.Select(MapIncludeItemTypes).Where(x => x != null).ToArray();
+ var includeTypes = query.IncludeItemTypes;
// Only specify excluded types if no included types are specified
- if (includeTypes.Length == 0)
+ if (query.IncludeItemTypes.Length == 0)
{
- var excludeTypes = query.ExcludeItemTypes.Select(MapIncludeItemTypes).Where(x => x != null).ToArray();
+ var excludeTypes = query.ExcludeItemTypes;
if (excludeTypes.Length == 1)
{
whereClauses.Add("type<>@type");
- statement?.TryBind("@type", excludeTypes[0]);
+ statement?.TryBind("@type", excludeTypes[0].ToString());
}
else if (excludeTypes.Length > 1)
{
@@ -3582,7 +3581,7 @@ namespace Emby.Server.Implementations.Data
else if (includeTypes.Length == 1)
{
whereClauses.Add("type=@type");
- statement?.TryBind("@type", includeTypes[0]);
+ statement?.TryBind("@type", includeTypes[0].ToString());
}
else if (includeTypes.Length > 1)
{
@@ -3911,7 +3910,7 @@ namespace Emby.Server.Implementations.Data
if (query.IsPlayed.HasValue)
{
// We should probably figure this out for all folders, but for right now, this is the only place where we need it
- if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], nameof(Series), StringComparison.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.Series)
{
if (query.IsPlayed.Value)
{
@@ -4761,27 +4760,27 @@ namespace Emby.Server.Implementations.Data
{
var list = new List<string>();
- if (IsTypeInQuery(nameof(Person), query))
+ if (IsTypeInQuery(BaseItemKind.Person, query))
{
list.Add(typeof(Person).FullName);
}
- if (IsTypeInQuery(nameof(Genre), query))
+ if (IsTypeInQuery(BaseItemKind.Genre, query))
{
list.Add(typeof(Genre).FullName);
}
- if (IsTypeInQuery(nameof(MusicGenre), query))
+ if (IsTypeInQuery(BaseItemKind.MusicGenre, query))
{
list.Add(typeof(MusicGenre).FullName);
}
- if (IsTypeInQuery(nameof(MusicArtist), query))
+ if (IsTypeInQuery(BaseItemKind.MusicArtist, query))
{
list.Add(typeof(MusicArtist).FullName);
}
- if (IsTypeInQuery(nameof(Studio), query))
+ if (IsTypeInQuery(BaseItemKind.Studio, query))
{
list.Add(typeof(Studio).FullName);
}
@@ -4789,14 +4788,14 @@ namespace Emby.Server.Implementations.Data
return list;
}
- private bool IsTypeInQuery(string type, InternalItemsQuery query)
+ private bool IsTypeInQuery(BaseItemKind type, InternalItemsQuery query)
{
- if (query.ExcludeItemTypes.Contains(type, StringComparer.OrdinalIgnoreCase))
+ if (query.ExcludeItemTypes.Contains(type))
{
return false;
}
- return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type, StringComparer.OrdinalIgnoreCase);
+ return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type);
}
private string GetCleanValue(string value)
@@ -4836,12 +4835,12 @@ namespace Emby.Server.Implementations.Data
return true;
}
- if (query.IncludeItemTypes.Contains(nameof(Episode), StringComparer.OrdinalIgnoreCase)
- || query.IncludeItemTypes.Contains(nameof(Video), StringComparer.OrdinalIgnoreCase)
- || query.IncludeItemTypes.Contains(nameof(Movie), StringComparer.OrdinalIgnoreCase)
- || query.IncludeItemTypes.Contains(nameof(MusicVideo), StringComparer.OrdinalIgnoreCase)
- || query.IncludeItemTypes.Contains(nameof(Series), StringComparer.OrdinalIgnoreCase)
- || query.IncludeItemTypes.Contains(nameof(Season), StringComparer.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Contains(BaseItemKind.Episode)
+ || query.IncludeItemTypes.Contains(BaseItemKind.Video)
+ || query.IncludeItemTypes.Contains(BaseItemKind.Movie)
+ || query.IncludeItemTypes.Contains(BaseItemKind.MusicVideo)
+ || query.IncludeItemTypes.Contains(BaseItemKind.Series)
+ || query.IncludeItemTypes.Contains(BaseItemKind.Season))
{
return true;
}
@@ -4890,22 +4889,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return dict;
}
- private string MapIncludeItemTypes(string value)
- {
- if (_types.TryGetValue(value, out string result))
- {
- return result;
- }
-
- if (IsValidType(value))
- {
- return value;
- }
-
- Logger.LogWarning("Unknown item type: {ItemType}", value);
- return null;
- }
-
public void DeleteItem(Guid id)
{
if (id == Guid.Empty)
@@ -5569,7 +5552,7 @@ AND Type = @InternalPersonType)");
return result;
}
- private static ItemCounts GetItemCounts(IReadOnlyList<ResultSetValue> reader, int countStartColumn, string[] typesToCount)
+ private static ItemCounts GetItemCounts(IReadOnlyList<ResultSetValue> reader, int countStartColumn, BaseItemKind[] typesToCount)
{
var counts = new ItemCounts();
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index b91ff6408..a34bfdb75 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -470,7 +470,7 @@ namespace Emby.Server.Implementations.Dto
{
var parentAlbumIds = _libraryManager.GetItemIds(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(MusicAlbum) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
Name = item.Album,
Limit = 1
});
diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
index 0229fbae7..7e12ebb08 100644
--- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
@@ -28,35 +28,35 @@ namespace Emby.Server.Implementations.Images
var view = (CollectionFolder)item;
var viewType = view.CollectionType;
- string[] includeItemTypes;
+ BaseItemKind[] includeItemTypes;
if (string.Equals(viewType, CollectionType.Movies, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "Movie" };
+ includeItemTypes = new[] { BaseItemKind.Movie };
}
else if (string.Equals(viewType, CollectionType.TvShows, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "Series" };
+ includeItemTypes = new[] { BaseItemKind.Series };
}
else if (string.Equals(viewType, CollectionType.Music, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "MusicAlbum" };
+ includeItemTypes = new[] { BaseItemKind.MusicAlbum };
}
else if (string.Equals(viewType, CollectionType.Books, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "Book", "AudioBook" };
+ includeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook };
}
else if (string.Equals(viewType, CollectionType.BoxSets, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "BoxSet" };
+ includeItemTypes = new[] { BaseItemKind.BoxSet };
}
else if (string.Equals(viewType, CollectionType.HomeVideos, StringComparison.Ordinal) || string.Equals(viewType, CollectionType.Photos, StringComparison.Ordinal))
{
- includeItemTypes = new string[] { "Video", "Photo" };
+ includeItemTypes = new[] { BaseItemKind.Video, BaseItemKind.Photo };
}
else
{
- includeItemTypes = new string[] { "Video", "Audio", "Photo", "Movie", "Series" };
+ includeItemTypes = new[] { BaseItemKind.Video, BaseItemKind.Audio, BaseItemKind.Photo, BaseItemKind.Movie, BaseItemKind.Series };
}
var recursive = !string.Equals(CollectionType.Playlists, viewType, StringComparison.OrdinalIgnoreCase);
diff --git a/Emby.Server.Implementations/Images/DynamicImageProvider.cs b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
index 900b3fd9c..0c3fe33a3 100644
--- a/Emby.Server.Implementations/Images/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@@ -41,7 +42,7 @@ namespace Emby.Server.Implementations.Images
User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null,
CollapseBoxSetItems = false,
Recursive = recursive,
- ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Person" },
+ ExcludeItemTypes = new[] { BaseItemKind.UserView, BaseItemKind.CollectionFolder, BaseItemKind.Person },
DtoOptions = new DtoOptions(false)
});
diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs
index 1f5090f7f..f8eefad6b 100644
--- a/Emby.Server.Implementations/Images/GenreImageProvider.cs
+++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs
@@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.Images
return _libraryManager.GetItemList(new InternalItemsQuery
{
Genres = new[] { item.Name },
- IncludeItemTypes = new[] { nameof(Series), nameof(Movie) },
+ IncludeItemTypes = new[] { BaseItemKind.Series, BaseItemKind.Movie },
OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
Limit = 4,
Recursive = true,
diff --git a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs
index baf1c9051..31f053f06 100644
--- a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs
+++ b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs
@@ -44,9 +44,9 @@ namespace Emby.Server.Implementations.Images
Genres = new[] { item.Name },
IncludeItemTypes = new[]
{
- nameof(MusicAlbum),
- nameof(MusicVideo),
- nameof(Audio)
+ BaseItemKind.MusicAlbum,
+ BaseItemKind.MusicVideo,
+ BaseItemKind.Audio
},
OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
Limit = 4,
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 01749242f..8cc9a2fd5 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Library
{
var existing = GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(MusicArtist) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicArtist },
Name = name,
DtoOptions = options
}).Cast<MusicArtist>()
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index e2f1fb0ad..d33213564 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -52,7 +52,7 @@ namespace Emby.Server.Implementations.Library
var genres = item
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Audio) },
+ IncludeItemTypes = new[] { BaseItemKind.Audio },
DtoOptions = dtoOptions
})
.Cast<Audio>()
@@ -89,7 +89,7 @@ namespace Emby.Server.Implementations.Library
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Audio) },
+ IncludeItemTypes = new[] { BaseItemKind.Audio },
GenreIds = genreIds.ToArray(),
diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs
index d5b855cdf..6f61dc713 100644
--- a/Emby.Server.Implementations/Library/PathExtensions.cs
+++ b/Emby.Server.Implementations/Library/PathExtensions.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="attribute">The attrib.</param>
/// <returns>System.String.</returns>
/// <exception cref="ArgumentException"><paramref name="str" /> or <paramref name="attribute" /> is empty.</exception>
- public static string? GetAttributeValue(this string str, string attribute)
+ public static string? GetAttributeValue(this ReadOnlySpan<char> str, ReadOnlySpan<char> attribute)
{
if (str.Length == 0)
{
@@ -28,17 +28,31 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentException("String can't be empty.", nameof(attribute));
}
- string srch = "[" + attribute + "=";
- int start = str.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
- if (start != -1)
+ var attributeIndex = str.IndexOf(attribute, StringComparison.OrdinalIgnoreCase);
+
+ // Must be at least 3 characters after the attribute =, ], any character.
+ var maxIndex = str.Length - attribute.Length - 3;
+ while (attributeIndex > -1 && attributeIndex < maxIndex)
{
- start += srch.Length;
- int end = str.IndexOf(']', start);
- return str.Substring(start, end - start);
+ var attributeEnd = attributeIndex + attribute.Length;
+ if (attributeIndex > 0
+ && str[attributeIndex - 1] == '['
+ && str[attributeEnd] == '=')
+ {
+ var closingIndex = str[attributeEnd..].IndexOf(']');
+ // Must be at least 1 character before the closing bracket.
+ if (closingIndex > 1)
+ {
+ return str[(attributeEnd + 1)..(attributeEnd + closingIndex)].Trim().ToString();
+ }
+ }
+
+ str = str[attributeEnd..];
+ attributeIndex = str.IndexOf(attribute, StringComparison.OrdinalIgnoreCase);
}
// for imdbid we also accept pattern matching
- if (string.Equals(attribute, "imdbid", StringComparison.OrdinalIgnoreCase))
+ if (attribute.Equals("imdbid", StringComparison.OrdinalIgnoreCase))
{
var match = ProviderIdParsers.TryFindImdbId(str, out var imdbId);
return match ? imdbId.ToString() : null;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
index e7abe1e6d..6cc04ea81 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
@@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
private static void SetProviderIdFromPath(BaseItem item)
{
// we need to only look at the name of this actual item (not parents)
- var justName = Path.GetFileName(item.Path);
+ var justName = Path.GetFileName(item.Path.AsSpan());
var id = justName.GetAttributeValue("tmdbid");
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index de3c1e415..10f42b926 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -362,9 +362,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (item is Movie || item is MusicVideo)
{
// We need to only look at the name of this actual item (not parents)
- var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.ContainingFolderPath);
+ var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path.AsSpan()) : Path.GetFileName(item.ContainingFolderPath.AsSpan());
- if (!string.IsNullOrEmpty(justName))
+ if (!justName.IsEmpty)
{
// check for tmdb id
var tmdbid = justName.GetAttributeValue("tmdbid");
@@ -378,7 +378,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (!string.IsNullOrEmpty(item.Path))
{
// check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
- var imdbid = item.Path.GetAttributeValue("imdbid");
+ var imdbid = item.Path.AsSpan().GetAttributeValue("imdbid");
if (!string.IsNullOrWhiteSpace(imdbid))
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 4e15acd18..46e36847d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -185,13 +185,42 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// <param name="path">The path.</param>
private static void SetProviderIdFromPath(Series item, string path)
{
- var justName = Path.GetFileName(path);
+ var justName = Path.GetFileName(path.AsSpan());
- var id = justName.GetAttributeValue("tvdbid");
+ var tvdbId = justName.GetAttributeValue("tvdbid");
+ if (!string.IsNullOrEmpty(tvdbId))
+ {
+ item.SetProviderId(MetadataProvider.Tvdb, tvdbId);
+ }
+
+ var tvmazeId = justName.GetAttributeValue("tvmazeid");
+ if (!string.IsNullOrEmpty(tvmazeId))
+ {
+ item.SetProviderId(MetadataProvider.TvMaze, tvmazeId);
+ }
+
+ var tmdbId = justName.GetAttributeValue("tmdbid");
+ if (!string.IsNullOrEmpty(tmdbId))
+ {
+ item.SetProviderId(MetadataProvider.Tmdb, tmdbId);
+ }
+
+ var anidbId = justName.GetAttributeValue("anidbid");
+ if (!string.IsNullOrEmpty(anidbId))
+ {
+ item.SetProviderId("AniDB", anidbId);
+ }
+
+ var aniListId = justName.GetAttributeValue("anilistid");
+ if (!string.IsNullOrEmpty(aniListId))
+ {
+ item.SetProviderId("AniList", aniListId);
+ }
- if (!string.IsNullOrEmpty(id))
+ var aniSearchId = justName.GetAttributeValue("anisearchid");
+ if (!string.IsNullOrEmpty(aniSearchId))
{
- item.SetProviderId(MetadataProvider.Tvdb, id);
+ item.SetProviderId("AniSearch", aniSearchId);
}
}
}
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index bebc25b77..42374b2a2 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -59,9 +59,9 @@ namespace Emby.Server.Implementations.Library
};
}
- private static void AddIfMissing(List<string> list, string value)
+ private static void AddIfMissing(List<BaseItemKind> list, BaseItemKind value)
{
- if (!list.Contains(value, StringComparer.OrdinalIgnoreCase))
+ if (!list.Contains(value))
{
list.Add(value);
}
@@ -86,63 +86,63 @@ namespace Emby.Server.Implementations.Library
searchTerm = searchTerm.Trim().RemoveDiacritics();
var excludeItemTypes = query.ExcludeItemTypes.ToList();
- var includeItemTypes = (query.IncludeItemTypes ?? Array.Empty<string>()).ToList();
+ var includeItemTypes = (query.IncludeItemTypes ?? Array.Empty<BaseItemKind>()).ToList();
- excludeItemTypes.Add(nameof(Year));
- excludeItemTypes.Add(nameof(Folder));
+ excludeItemTypes.Add(BaseItemKind.Year);
+ excludeItemTypes.Add(BaseItemKind.Folder);
- if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase)))
+ if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains(BaseItemKind.Genre)))
{
if (!query.IncludeMedia)
{
- AddIfMissing(includeItemTypes, nameof(Genre));
- AddIfMissing(includeItemTypes, nameof(MusicGenre));
+ AddIfMissing(includeItemTypes, BaseItemKind.Genre);
+ AddIfMissing(includeItemTypes, BaseItemKind.MusicGenre);
}
}
else
{
- AddIfMissing(excludeItemTypes, nameof(Genre));
- AddIfMissing(excludeItemTypes, nameof(MusicGenre));
+ AddIfMissing(excludeItemTypes, BaseItemKind.Genre);
+ AddIfMissing(excludeItemTypes, BaseItemKind.MusicGenre);
}
- if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase)))
+ if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains(BaseItemKind.Person)))
{
if (!query.IncludeMedia)
{
- AddIfMissing(includeItemTypes, nameof(Person));
+ AddIfMissing(includeItemTypes, BaseItemKind.Person);
}
}
else
{
- AddIfMissing(excludeItemTypes, nameof(Person));
+ AddIfMissing(excludeItemTypes, BaseItemKind.Person);
}
- if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase)))
+ if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains(BaseItemKind.Studio)))
{
if (!query.IncludeMedia)
{
- AddIfMissing(includeItemTypes, nameof(Studio));
+ AddIfMissing(includeItemTypes, BaseItemKind.Studio);
}
}
else
{
- AddIfMissing(excludeItemTypes, nameof(Studio));
+ AddIfMissing(excludeItemTypes, BaseItemKind.Studio);
}
- if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase)))
+ if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains(BaseItemKind.MusicArtist)))
{
if (!query.IncludeMedia)
{
- AddIfMissing(includeItemTypes, nameof(MusicArtist));
+ AddIfMissing(includeItemTypes, BaseItemKind.MusicArtist);
}
}
else
{
- AddIfMissing(excludeItemTypes, nameof(MusicArtist));
+ AddIfMissing(excludeItemTypes, BaseItemKind.MusicArtist);
}
- AddIfMissing(excludeItemTypes, nameof(CollectionFolder));
- AddIfMissing(excludeItemTypes, nameof(Folder));
+ AddIfMissing(excludeItemTypes, BaseItemKind.CollectionFolder);
+ AddIfMissing(excludeItemTypes, BaseItemKind.Folder);
var mediaTypes = query.MediaTypes.ToList();
if (includeItemTypes.Count > 0)
@@ -183,7 +183,7 @@ namespace Emby.Server.Implementations.Library
List<BaseItem> mediaItems;
- if (searchQuery.IncludeItemTypes.Length == 1 && string.Equals(searchQuery.IncludeItemTypes[0], "MusicArtist", StringComparison.OrdinalIgnoreCase))
+ if (searchQuery.IncludeItemTypes.Length == 1 && searchQuery.IncludeItemTypes[0] == BaseItemKind.MusicArtist)
{
if (!searchQuery.ParentId.Equals(Guid.Empty))
{
@@ -192,7 +192,7 @@ namespace Emby.Server.Implementations.Library
searchQuery.ParentId = Guid.Empty;
searchQuery.IncludeItemsByName = true;
- searchQuery.IncludeItemTypes = Array.Empty<string>();
+ searchQuery.IncludeItemTypes = Array.Empty<BaseItemKind>();
mediaItems = _libraryManager.GetAllArtists(searchQuery).Items.Select(i => i.Item1).ToList();
}
else
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index 711647e7a..3593986a9 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -300,11 +300,11 @@ namespace Emby.Server.Implementations.Library
{
if (hasCollectionType.All(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)))
{
- includeItemTypes = new string[] { "Movie" };
+ includeItemTypes = new[] { BaseItemKind.Movie };
}
else if (hasCollectionType.All(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)))
{
- includeItemTypes = new string[] { "Episode" };
+ includeItemTypes = new[] { BaseItemKind.Episode };
}
}
}
@@ -344,13 +344,13 @@ namespace Emby.Server.Implementations.Library
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0
? new[]
{
- nameof(Person),
- nameof(Studio),
- nameof(Year),
- nameof(MusicGenre),
- nameof(Genre)
+ BaseItemKind.Person,
+ BaseItemKind.Studio,
+ BaseItemKind.Year,
+ BaseItemKind.MusicGenre,
+ BaseItemKind.Genre
}
- : Array.Empty<string>();
+ : Array.Empty<BaseItemKind>();
var query = new InternalItemsQuery(user)
{
diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
index 40436d9c5..7591e8391 100644
--- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -3,6 +3,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -81,7 +82,7 @@ namespace Emby.Server.Implementations.Library.Validators
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(MusicArtist) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicArtist },
IsDeadArtist = true,
IsLocked = false
}).Cast<MusicArtist>().ToList();
diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs
index 945b559ad..73e58d16c 100644
--- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs
@@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.Library.Validators
var movies = _libraryManager.GetItemList(new InternalItemsQuery
{
MediaTypes = new string[] { MediaType.Video },
- IncludeItemTypes = new[] { nameof(Movie) },
+ IncludeItemTypes = new[] { BaseItemKind.Movie },
IsVirtualItem = false,
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
Parent = library,
@@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.Library.Validators
var boxSets = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(BoxSet) },
+ IncludeItemTypes = new[] { BaseItemKind.BoxSet },
CollapseBoxSetItems = false,
Recursive = true
});
diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
index 8a9a4b865..601aab5b9 100644
--- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -2,6 +2,7 @@ using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -91,7 +92,7 @@ namespace Emby.Server.Implementations.Library.Validators
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Person) },
+ IncludeItemTypes = new[] { BaseItemKind.Person },
IsDeadPerson = true,
IsLocked = false
});
diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
index 8577d722e..26bc49c1f 100644
--- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -2,6 +2,7 @@ using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
@@ -80,7 +81,7 @@ namespace Emby.Server.Implementations.Library.Validators
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Studio) },
+ IncludeItemTypes = new[] { BaseItemKind.Studio },
IsDeadStudio = true,
IsLocked = false
});
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 644f9050d..e604000ad 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1778,7 +1778,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var program = string.IsNullOrWhiteSpace(timer.ProgramId) ? null : _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
Limit = 1,
ExternalId = timer.ProgramId,
DtoOptions = new DtoOptions(true)
@@ -2137,7 +2137,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var query = new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
Limit = 1,
DtoOptions = new DtoOptions(true)
{
@@ -2352,7 +2352,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var query = new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
ExternalSeriesId = seriesTimer.SeriesId,
DtoOptions = new DtoOptions(true)
{
@@ -2387,7 +2387,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
channel = _libraryManager.GetItemList(
new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvChannel) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel },
ItemIds = new[] { parent.ChannelId },
DtoOptions = new DtoOptions()
}).FirstOrDefault() as LiveTvChannel;
@@ -2446,7 +2446,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
channel = _libraryManager.GetItemList(
new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvChannel) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel },
ItemIds = new[] { programInfo.ChannelId },
DtoOptions = new DtoOptions()
}).FirstOrDefault() as LiveTvChannel;
@@ -2511,7 +2511,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var seriesIds = _libraryManager.GetItemIds(
new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Name = program.Name
}).ToArray();
@@ -2524,7 +2524,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var result = _libraryManager.GetItemIds(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
ParentIndexNumber = program.SeasonNumber.Value,
IndexNumber = program.EpisodeNumber.Value,
AncestorIds = seriesIds,
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 598e3f88a..317bcbfdd 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -7,6 +7,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Drawing;
@@ -161,7 +162,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var librarySeries = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb },
@@ -204,7 +205,7 @@ namespace Emby.Server.Implementations.LiveTv
var program = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
@@ -255,7 +256,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var librarySeries = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb },
@@ -298,7 +299,7 @@ namespace Emby.Server.Implementations.LiveTv
var program = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
@@ -309,7 +310,7 @@ namespace Emby.Server.Implementations.LiveTv
{
program = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index a41b63f28..2f826c63e 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.LiveTv
IsKids = query.IsKids,
IsSports = query.IsSports,
IsSeries = query.IsSeries,
- IncludeItemTypes = new[] { nameof(LiveTvChannel) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel },
TopParentIds = new[] { topFolder.Id },
IsFavorite = query.IsFavorite,
IsLiked = query.IsLiked,
@@ -810,7 +810,7 @@ namespace Emby.Server.Implementations.LiveTv
var internalQuery = new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
MinEndDate = query.MinEndDate,
MinStartDate = query.MinStartDate,
MaxEndDate = query.MaxEndDate,
@@ -874,7 +874,7 @@ namespace Emby.Server.Implementations.LiveTv
var internalQuery = new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
IsAiring = query.IsAiring,
HasAired = query.HasAired,
IsNews = query.IsNews,
@@ -1085,8 +1085,8 @@ namespace Emby.Server.Implementations.LiveTv
if (cleanDatabase)
{
- CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { nameof(LiveTvChannel) }, progress, cancellationToken);
- CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { nameof(LiveTvProgram) }, progress, cancellationToken);
+ CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { BaseItemKind.LiveTvChannel }, progress, cancellationToken);
+ CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { BaseItemKind.LiveTvProgram }, progress, cancellationToken);
}
var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
@@ -1177,7 +1177,7 @@ namespace Emby.Server.Implementations.LiveTv
var existingPrograms = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new string[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
ChannelIds = new Guid[] { currentChannel.Id },
DtoOptions = new DtoOptions(true)
}).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
@@ -1261,7 +1261,7 @@ namespace Emby.Server.Implementations.LiveTv
return new Tuple<List<Guid>, List<Guid>>(channels, programs);
}
- private void CleanDatabaseInternal(Guid[] currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
+ private void CleanDatabaseInternal(Guid[] currentIdList, BaseItemKind[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
{
var list = _itemRepo.GetItemIdsList(new InternalItemsQuery
{
@@ -1328,25 +1328,25 @@ namespace Emby.Server.Implementations.LiveTv
.Select(i => i.Id)
.ToList();
- var excludeItemTypes = new List<string>();
+ var excludeItemTypes = new List<BaseItemKind>();
if (folderIds.Count == 0)
{
return new QueryResult<BaseItem>();
}
- var includeItemTypes = new List<string>();
+ var includeItemTypes = new List<BaseItemKind>();
var genres = new List<string>();
if (query.IsMovie.HasValue)
{
if (query.IsMovie.Value)
{
- includeItemTypes.Add(nameof(Movie));
+ includeItemTypes.Add(BaseItemKind.Movie);
}
else
{
- excludeItemTypes.Add(nameof(Movie));
+ excludeItemTypes.Add(BaseItemKind.Movie);
}
}
@@ -1354,11 +1354,11 @@ namespace Emby.Server.Implementations.LiveTv
{
if (query.IsSeries.Value)
{
- includeItemTypes.Add(nameof(Episode));
+ includeItemTypes.Add(BaseItemKind.Episode);
}
else
{
- excludeItemTypes.Add(nameof(Episode));
+ excludeItemTypes.Add(BaseItemKind.Episode);
}
}
@@ -1878,7 +1878,7 @@ namespace Emby.Server.Implementations.LiveTv
var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(LiveTvProgram) },
+ IncludeItemTypes = new[] { BaseItemKind.LiveTvProgram },
ChannelIds = channelIds,
MaxStartDate = now,
MinEndDate = now,
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 570d600fc..9d4d40e51 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -15,7 +15,7 @@
"Favorites": "مفضلات",
"Folders": "المجلدات",
"Genres": "التضنيفات",
- "HeaderAlbumArtists": "ألبوم الفنان",
+ "HeaderAlbumArtists": "فناني الألبوم",
"HeaderContinueWatching": "استمر بالمشاهدة",
"HeaderFavoriteAlbums": "الألبومات المفضلة",
"HeaderFavoriteArtists": "الفنانون المفضلون",
diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json
index 3cadde0a0..8abf7fa66 100644
--- a/Emby.Server.Implementations/Localization/Core/eo.json
+++ b/Emby.Server.Implementations/Localization/Core/eo.json
@@ -104,7 +104,7 @@
"TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.",
"TaskDownloadMissingSubtitles": "Elŝuti mankantajn subtekstojn",
"TaskCleanTranscode": "Malplenigi Transkodadan Katalogon",
- "TaskRefreshChapterImages": "Eltiri Ĉapitraj Bildojn",
+ "TaskRefreshChapterImages": "Eltiri Ĉapitrajn Bildojn",
"TaskCleanCache": "Malplenigi Staplan Katalogon",
"TaskCleanActivityLog": "Malplenigi Aktivecan Ĵurnalon",
"PluginUpdatedWithName": "{0} estis ĝisdatigita",
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index 3d3b3533f..6960ff007 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -118,5 +118,6 @@
"Default": "پیشفرض",
"TaskCleanActivityLogDescription": "ورودی‌های قدیمی‌تر از سن تنظیم شده در سیاهه فعالیت را حذف می‌کند.",
"TaskCleanActivityLog": "پاکسازی سیاهه فعالیت",
- "Undefined": "تعریف نشده"
+ "Undefined": "تعریف نشده",
+ "TaskOptimizeDatabase": "بهینه سازی پایگاه داده"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index d7cda61da..4df0444e6 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -15,7 +15,7 @@
"Favorites": "Favoriti",
"Folders": "Mape",
"Genres": "Žanrovi",
- "HeaderAlbumArtists": "Album od izvođača",
+ "HeaderAlbumArtists": "Izvođači albuma",
"HeaderContinueWatching": "Nastavi gledati",
"HeaderFavoriteAlbums": "Omiljeni albumi",
"HeaderFavoriteArtists": "Omiljeni izvođači",
diff --git a/Emby.Server.Implementations/Localization/Core/ja.json b/Emby.Server.Implementations/Localization/Core/ja.json
index 7f41561ec..2588f1e8c 100644
--- a/Emby.Server.Implementations/Localization/Core/ja.json
+++ b/Emby.Server.Implementations/Localization/Core/ja.json
@@ -16,7 +16,7 @@
"Folders": "フォルダー",
"Genres": "ジャンル",
"HeaderAlbumArtists": "アルバムアーティスト",
- "HeaderContinueWatching": "視聴を続ける",
+ "HeaderContinueWatching": "続きを見る",
"HeaderFavoriteAlbums": "お気に入りのアルバム",
"HeaderFavoriteArtists": "お気に入りのアーティスト",
"HeaderFavoriteEpisodes": "お気に入りのエピソード",
diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json
index f3a131d40..f0a07f604 100644
--- a/Emby.Server.Implementations/Localization/Core/lt-LT.json
+++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json
@@ -1,7 +1,7 @@
{
"Albums": "Albumai",
"AppDeviceValues": "Programa: {0}, Įrenginys: {1}",
- "Application": "Programa",
+ "Application": "Programėlė",
"Artists": "Atlikėjai",
"AuthenticationSucceededWithUserName": "{0} sėkmingai autentifikuota",
"Books": "Knygos",
diff --git a/Emby.Server.Implementations/Localization/Core/mk.json b/Emby.Server.Implementations/Localization/Core/mk.json
index d7839be57..279734c5e 100644
--- a/Emby.Server.Implementations/Localization/Core/mk.json
+++ b/Emby.Server.Implementations/Localization/Core/mk.json
@@ -97,5 +97,8 @@
"TasksChannelsCategory": "Интернет Канали",
"TasksApplicationCategory": "Апликација",
"TasksLibraryCategory": "Библиотека",
- "TasksMaintenanceCategory": "Одржување"
+ "TasksMaintenanceCategory": "Одржување",
+ "Undefined": "Недефинирано",
+ "Forced": "Принудно",
+ "Default": "Зададено"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index 94ee389d7..2e0fbc366 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -55,7 +55,7 @@
"NotificationOptionPluginInstalled": "Plugin telah dipasang",
"NotificationOptionPluginUninstalled": "Plugin telah dinyahpasang",
"NotificationOptionPluginUpdateInstalled": "Kemaskini plugin telah dipasang",
- "NotificationOptionServerRestartRequired": "Server restart required",
+ "NotificationOptionServerRestartRequired": "",
"NotificationOptionTaskFailed": "Kegagalan tugas berjadual",
"NotificationOptionUserLockedOut": "Pengguna telah dikunci",
"NotificationOptionVideoPlayback": "Ulangmain video bermula",
@@ -66,19 +66,19 @@
"PluginInstalledWithName": "{0} telah dipasang",
"PluginUninstalledWithName": "{0} telah dinyahpasang",
"PluginUpdatedWithName": "{0} telah dikemaskini",
- "ProviderValue": "Provider: {0}",
+ "ProviderValue": "Pembekal: {0}",
"ScheduledTaskFailedWithName": "{0} gagal",
"ScheduledTaskStartedWithName": "{0} bermula",
"ServerNameNeedsToBeRestarted": "{0} perlu di ulangmula",
- "Shows": "Series",
+ "Shows": "Tayangan",
"Songs": "Lagu-lagu",
"StartupEmbyServerIsLoading": "Pelayan Jellyfin sedang dimuatkan. Sila cuba sebentar lagi.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"SubtitleDownloadFailureFromForItem": "Muat turun sarikata gagal dari {0} untuk {1}",
- "Sync": "Sync",
+ "Sync": "",
"System": "Sistem",
"TvShows": "Tayangan TV",
- "User": "User",
+ "User": "Pengguna",
"UserCreatedWithName": "Pengguna {0} telah diwujudkan",
"UserDeletedWithName": "Pengguna {0} telah dipadamkan",
"UserDownloadingItemWithValues": "{0} sedang memuat turun {1}",
diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json
index 510aac11c..f8fad7b63 100644
--- a/Emby.Server.Implementations/Localization/Core/ro.json
+++ b/Emby.Server.Implementations/Localization/Core/ro.json
@@ -74,7 +74,7 @@
"HeaderFavoriteArtists": "Artiști Favoriți",
"HeaderFavoriteAlbums": "Albume Favorite",
"HeaderContinueWatching": "Vizionează în continuare",
- "HeaderAlbumArtists": "Album Artiști",
+ "HeaderAlbumArtists": "Albume Artiști",
"Genres": "Genuri",
"Folders": "Dosare",
"Favorites": "Favorite",
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index 1cef30b6c..f3f601661 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -96,8 +96,8 @@
"TaskDownloadMissingSubtitles": "Ladda ned saknade undertexter",
"TaskRefreshChannelsDescription": "Uppdaterar information för internetkanaler.",
"TaskRefreshChannels": "Uppdatera kanaler",
- "TaskCleanTranscodeDescription": "Raderar transkodningsfiler som är mer än en dag gamla.",
- "TaskCleanTranscode": "Töm transkodningskatalog",
+ "TaskCleanTranscodeDescription": "Raderar omkodningsfiler som är mer än en dag gamla.",
+ "TaskCleanTranscode": "Töm omkodningskatalog",
"TaskUpdatePluginsDescription": "Laddar ned och installerar uppdateringar till insticksprogram som är konfigurerade att uppdateras automatiskt.",
"TaskUpdatePlugins": "Uppdatera insticksprogram",
"TaskRefreshPeopleDescription": "Uppdaterar metadata för skådespelare och regissörer i ditt mediabibliotek.",
diff --git a/Emby.Server.Implementations/Localization/Core/zu.json b/Emby.Server.Implementations/Localization/Core/zu.json
index 0967ef424..b5f4b920f 100644
--- a/Emby.Server.Implementations/Localization/Core/zu.json
+++ b/Emby.Server.Implementations/Localization/Core/zu.json
@@ -1 +1,29 @@
-{}
+{
+ "TasksApplicationCategory": "Ukusetshenziswa",
+ "TasksLibraryCategory": "Umtapo",
+ "TasksMaintenanceCategory": "Ukunakekela",
+ "User": "Umsebenzisi",
+ "Undefined": "Akuchaziwe",
+ "System": "Isistimu",
+ "Sync": "Vumelanisa",
+ "Songs": "Amaculo",
+ "Shows": "Izinhlelo",
+ "Plugin": "Isijobelelo",
+ "Playlists": "Izinhla Zokudlalayo",
+ "Photos": "Izithombe",
+ "Music": "Umculo",
+ "Movies": "Amamuvi",
+ "Latest": "lwakamuva",
+ "Inherit": "Ngefa",
+ "Forced": "Kuphoqiwe",
+ "Application": "Ukusetshenziswa",
+ "Genres": "Izinhlobo",
+ "Folders": "Izikhwama",
+ "Favorites": "Izintandokazi",
+ "Default": "Okumisiwe",
+ "Collections": "Amaqoqo",
+ "Channels": "Amashaneli",
+ "Books": "Izincwadi",
+ "Artists": "Abadlali",
+ "Albums": "Ama-albhamu"
+}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs
index 8b1cee89d..8ec9f6161 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Querying;
@@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.Playlists
}
query.Recursive = true;
- query.IncludeItemTypes = new[] { "Playlist" };
+ query.IncludeItemTypes = new[] { BaseItemKind.Playlist };
query.Parent = null;
return LibraryManager.GetItemsResult(query);
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 341d2c8e6..d10a24bbc 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -1292,7 +1292,7 @@ namespace Emby.Server.Implementations.Session
{
["ItemId"] = command.ItemId,
["ItemName"] = command.ItemName,
- ["ItemType"] = command.ItemType
+ ["ItemType"] = command.ItemType.ToString()
}
};
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 4d990c871..a87831294 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.TV
.GetItemList(
new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
SeriesPresentationUniqueKey = presentationUniqueKey,
Limit = limit,
@@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Descending) },
IsPlayed = true,
Limit = 1,
@@ -209,7 +209,7 @@ namespace Emby.Server.Implementations.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) },
Limit = 1,
IsPlayed = false,
@@ -226,7 +226,7 @@ namespace Emby.Server.Implementations.TV
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
ParentIndexNumber = 0,
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
IsPlayed = false,
IsVirtualItem = false,
DtoOptions = dtoOptions
diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs
index 154a56702..3df975563 100644
--- a/Jellyfin.Api/Controllers/ArtistsController.cs
+++ b/Jellyfin.Api/Controllers/ArtistsController.cs
@@ -133,8 +133,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes,
StartIndex = startIndex,
Limit = limit,
@@ -337,8 +337,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes,
StartIndex = startIndex,
Limit = limit,
diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs
index 223b2a2b6..02a0785e7 100644
--- a/Jellyfin.Api/Controllers/FilterController.cs
+++ b/Jellyfin.Api/Controllers/FilterController.cs
@@ -71,7 +71,7 @@ namespace Jellyfin.Api.Controllers
{
User = user,
MediaTypes = mediaTypes,
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ IncludeItemTypes = includeItemTypes,
Recursive = true,
EnableTotalRecordCount = false,
DtoOptions = new DtoOptions
@@ -166,7 +166,7 @@ namespace Jellyfin.Api.Controllers
var filters = new QueryFilters();
var genreQuery = new InternalItemsQuery(user)
{
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ IncludeItemTypes = includeItemTypes,
DtoOptions = new DtoOptions
{
Fields = Array.Empty<ItemFields>(),
diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs
index 5aa457153..37e6ae184 100644
--- a/Jellyfin.Api/Controllers/GenresController.cs
+++ b/Jellyfin.Api/Controllers/GenresController.cs
@@ -101,8 +101,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
StartIndex = startIndex,
Limit = limit,
IsFavorite = isFavorite,
@@ -160,7 +160,7 @@ namespace Jellyfin.Api.Controllers
Genre item = new Genre();
if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
{
- var result = GetItemFromSlugName<Genre>(_libraryManager, genreName, dtoOptions);
+ var result = GetItemFromSlugName<Genre>(_libraryManager, genreName, dtoOptions, BaseItemKind.Genre);
if (result != null)
{
@@ -182,27 +182,27 @@ namespace Jellyfin.Api.Controllers
return _dtoService.GetBaseItemDto(item, dtoOptions);
}
- private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
+ private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions, BaseItemKind baseItemKind)
where T : BaseItem, new()
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '&'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
result ??= libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '/'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
result ??= libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '?'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index 45a36c8fe..22e3fd202 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -296,8 +296,8 @@ namespace Jellyfin.Api.Controllers
{
IsPlayed = isPlayed,
MediaTypes = mediaTypes,
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
+ IncludeItemTypes = includeItemTypes,
+ ExcludeItemTypes = excludeItemTypes,
Recursive = recursive ?? false,
OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
IsFavorite = isFavorite,
@@ -459,7 +459,7 @@ namespace Jellyfin.Api.Controllers
{
query.AlbumIds = albums.SelectMany(i =>
{
- return _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { nameof(MusicAlbum) }, Name = i, Limit = 1 });
+ return _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { BaseItemKind.MusicAlbum }, Name = i, Limit = 1 });
}).ToArray();
}
@@ -483,7 +483,7 @@ namespace Jellyfin.Api.Controllers
if (query.OrderBy.Count == 0)
{
// Albums by artist
- if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], "MusicAlbum", StringComparison.OrdinalIgnoreCase))
+ if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.MusicAlbum)
{
query.OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.ProductionYear, SortOrder.Descending), new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) };
}
@@ -831,8 +831,8 @@ namespace Jellyfin.Api.Controllers
CollapseBoxSetItems = false,
EnableTotalRecordCount = enableTotalRecordCount,
AncestorIds = ancestorIds,
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
+ IncludeItemTypes = includeItemTypes,
+ ExcludeItemTypes = excludeItemTypes,
SearchTerm = searchTerm,
ExcludeItemIds = excludeItemIds
});
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 0be853ca4..d4cc3810a 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -14,6 +14,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LibraryDtos;
using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
@@ -413,14 +414,14 @@ namespace Jellyfin.Api.Controllers
var counts = new ItemCounts
{
- AlbumCount = GetCount(typeof(MusicAlbum), user, isFavorite),
- EpisodeCount = GetCount(typeof(Episode), user, isFavorite),
- MovieCount = GetCount(typeof(Movie), user, isFavorite),
- SeriesCount = GetCount(typeof(Series), user, isFavorite),
- SongCount = GetCount(typeof(Audio), user, isFavorite),
- MusicVideoCount = GetCount(typeof(MusicVideo), user, isFavorite),
- BoxSetCount = GetCount(typeof(BoxSet), user, isFavorite),
- BookCount = GetCount(typeof(Book), user, isFavorite)
+ AlbumCount = GetCount(BaseItemKind.MusicAlbum, user, isFavorite),
+ EpisodeCount = GetCount(BaseItemKind.Episode, user, isFavorite),
+ MovieCount = GetCount(BaseItemKind.Movie, user, isFavorite),
+ SeriesCount = GetCount(BaseItemKind.Series, user, isFavorite),
+ SongCount = GetCount(BaseItemKind.Audio, user, isFavorite),
+ MusicVideoCount = GetCount(BaseItemKind.MusicVideo, user, isFavorite),
+ BoxSetCount = GetCount(BaseItemKind.BoxSet, user, isFavorite),
+ BookCount = GetCount(BaseItemKind.Book, user, isFavorite)
};
return counts;
@@ -529,7 +530,7 @@ namespace Jellyfin.Api.Controllers
{
var series = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
DtoOptions = new DtoOptions(false)
{
EnableImages = false
@@ -559,7 +560,7 @@ namespace Jellyfin.Api.Controllers
{
var movies = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(Movie) },
+ IncludeItemTypes = new[] { BaseItemKind.Movie },
DtoOptions = new DtoOptions(false)
{
EnableImages = false
@@ -715,26 +716,26 @@ namespace Jellyfin.Api.Controllers
bool? isMovie = item is Movie || (program != null && program.IsMovie) || item is Trailer;
bool? isSeries = item is Series || (program != null && program.IsSeries);
- var includeItemTypes = new List<string>();
+ var includeItemTypes = new List<BaseItemKind>();
if (isMovie.Value)
{
- includeItemTypes.Add(nameof(Movie));
+ includeItemTypes.Add(BaseItemKind.Movie);
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
{
- includeItemTypes.Add(nameof(Trailer));
- includeItemTypes.Add(nameof(LiveTvProgram));
+ includeItemTypes.Add(BaseItemKind.Trailer);
+ includeItemTypes.Add(BaseItemKind.LiveTvProgram);
}
}
else if (isSeries.Value)
{
- includeItemTypes.Add(nameof(Series));
+ includeItemTypes.Add(BaseItemKind.Series);
}
else
{
// For non series and movie types these columns are typically null
isSeries = null;
isMovie = null;
- includeItemTypes.Add(item.GetType().Name);
+ includeItemTypes.Add(item.GetBaseItemKind());
}
var query = new InternalItemsQuery(user)
@@ -871,11 +872,11 @@ namespace Jellyfin.Api.Controllers
return result;
}
- private int GetCount(Type type, User? user, bool? isFavorite)
+ private int GetCount(BaseItemKind itemKind, User? user, bool? isFavorite)
{
var query = new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { type.Name },
+ IncludeItemTypes = new[] { itemKind },
Limit = 0,
Recursive = true,
IsVirtualItem = false,
diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs
index 99c90d19e..def10f0bd 100644
--- a/Jellyfin.Api/Controllers/MoviesController.cs
+++ b/Jellyfin.Api/Controllers/MoviesController.cs
@@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
{
IncludeItemTypes = new[]
{
- nameof(Movie),
+ BaseItemKind.Movie,
// nameof(Trailer),
// nameof(LiveTvProgram)
},
@@ -99,11 +99,11 @@ namespace Jellyfin.Api.Controllers
var recentlyPlayedMovies = _libraryManager.GetItemList(query);
- var itemTypes = new List<string> { nameof(Movie) };
+ var itemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
{
- itemTypes.Add(nameof(Trailer));
- itemTypes.Add(nameof(LiveTvProgram));
+ itemTypes.Add(BaseItemKind.Trailer);
+ itemTypes.Add(BaseItemKind.LiveTvProgram);
}
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
@@ -182,11 +182,11 @@ namespace Jellyfin.Api.Controllers
DtoOptions dtoOptions,
RecommendationType type)
{
- var itemTypes = new List<string> { nameof(Movie) };
+ var itemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
{
- itemTypes.Add(nameof(Trailer));
- itemTypes.Add(nameof(LiveTvProgram));
+ itemTypes.Add(BaseItemKind.Trailer);
+ itemTypes.Add(BaseItemKind.LiveTvProgram);
}
foreach (var name in names)
@@ -224,11 +224,11 @@ namespace Jellyfin.Api.Controllers
private IEnumerable<RecommendationDto> GetWithActor(User? user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
- var itemTypes = new List<string> { nameof(Movie) };
+ var itemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
{
- itemTypes.Add(nameof(Trailer));
- itemTypes.Add(nameof(LiveTvProgram));
+ itemTypes.Add(BaseItemKind.Trailer);
+ itemTypes.Add(BaseItemKind.LiveTvProgram);
}
foreach (var name in names)
@@ -264,11 +264,11 @@ namespace Jellyfin.Api.Controllers
private IEnumerable<RecommendationDto> GetSimilarTo(User? user, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
- var itemTypes = new List<string> { nameof(Movie) };
+ var itemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
{
- itemTypes.Add(nameof(Trailer));
- itemTypes.Add(nameof(LiveTvProgram));
+ itemTypes.Add(BaseItemKind.Trailer);
+ itemTypes.Add(BaseItemKind.LiveTvProgram);
}
foreach (var item in baselineItems)
diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs
index 27eec2b9a..c4c03aa4f 100644
--- a/Jellyfin.Api/Controllers/MusicGenresController.cs
+++ b/Jellyfin.Api/Controllers/MusicGenresController.cs
@@ -101,8 +101,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
StartIndex = startIndex,
Limit = limit,
IsFavorite = isFavorite,
@@ -149,7 +149,7 @@ namespace Jellyfin.Api.Controllers
if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
{
- item = GetItemFromSlugName<MusicGenre>(_libraryManager, genreName, dtoOptions);
+ item = GetItemFromSlugName<MusicGenre>(_libraryManager, genreName, dtoOptions, BaseItemKind.MusicGenre);
}
else
{
@@ -166,27 +166,27 @@ namespace Jellyfin.Api.Controllers
return _dtoService.GetBaseItemDto(item, dtoOptions);
}
- private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
+ private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions, BaseItemKind baseItemKind)
where T : BaseItem, new()
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '&'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
result ??= libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '/'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
result ??= libraryManager.GetItemList(new InternalItemsQuery
{
Name = name.Replace(BaseItem.SlugChar, '?'),
- IncludeItemTypes = new[] { typeof(T).Name },
+ IncludeItemTypes = new[] { baseItemKind },
DtoOptions = dtoOptions
}).OfType<T>().FirstOrDefault();
diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs
index 73bdf9018..02ee7860f 100644
--- a/Jellyfin.Api/Controllers/SearchController.cs
+++ b/Jellyfin.Api/Controllers/SearchController.cs
@@ -110,8 +110,8 @@ namespace Jellyfin.Api.Controllers
IncludeStudios = includeStudios,
StartIndex = startIndex,
UserId = userId ?? Guid.Empty,
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
+ IncludeItemTypes = includeItemTypes,
+ ExcludeItemTypes = excludeItemTypes,
MediaTypes = mediaTypes,
ParentId = parentId,
diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
index 3a04cb3a4..a6bbd40cc 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -127,7 +127,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> DisplayContent(
[FromRoute, Required] string sessionId,
- [FromQuery, Required] string itemType,
+ [FromQuery, Required] BaseItemKind itemType,
[FromQuery, Required] string itemId,
[FromQuery, Required] string itemName)
{
diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs
index a01a617fc..c49bde93f 100644
--- a/Jellyfin.Api/Controllers/StartupController.cs
+++ b/Jellyfin.Api/Controllers/StartupController.cs
@@ -93,7 +93,7 @@ namespace Jellyfin.Api.Controllers
NetworkConfiguration settings = _config.GetNetworkConfiguration();
settings.EnableRemoteAccess = startupRemoteAccessDto.EnableRemoteAccess;
settings.EnableUPnP = startupRemoteAccessDto.EnableAutomaticPortMapping;
- _config.SaveConfiguration("network", settings);
+ _config.SaveConfiguration(NetworkConfigurationStore.StoreKey, settings);
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs
index da8f8b199..4422ef32c 100644
--- a/Jellyfin.Api/Controllers/StudiosController.cs
+++ b/Jellyfin.Api/Controllers/StudiosController.cs
@@ -97,8 +97,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
StartIndex = startIndex,
Limit = limit,
IsFavorite = isFavorite,
diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs
index 97eec4bd2..af77c801f 100644
--- a/Jellyfin.Api/Controllers/SuggestionsController.cs
+++ b/Jellyfin.Api/Controllers/SuggestionsController.cs
@@ -58,7 +58,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<QueryResult<BaseItemDto>> GetSuggestions(
[FromRoute, Required] Guid userId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaType,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] type,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] type,
[FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] bool enableTotalRecordCount = false)
diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs
index 5dd773331..f47e71bd1 100644
--- a/Jellyfin.Api/Controllers/TvShowsController.cs
+++ b/Jellyfin.Api/Controllers/TvShowsController.cs
@@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.PremiereDate, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
MinPremiereDate = minPremiereDate,
StartIndex = startIndex,
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 249379619..ae7e13f67 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -297,7 +297,7 @@ namespace Jellyfin.Api.Controllers
new LatestItemsQuery
{
GroupItems = groupItems,
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ IncludeItemTypes = includeItemTypes,
IsPlayed = isPlayed,
Limit = limit,
ParentId = parentId ?? Guid.Empty,
diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs
index d6dc6650c..2bba2b97d 100644
--- a/Jellyfin.Api/Controllers/YearsController.cs
+++ b/Jellyfin.Api/Controllers/YearsController.cs
@@ -101,8 +101,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user)
{
- ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
- IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes,
DtoOptions = dtoOptions
};
diff --git a/Jellyfin.Api/Helpers/ClassMigrationHelper.cs b/Jellyfin.Api/Helpers/ClassMigrationHelper.cs
deleted file mode 100644
index 76fb27bcc..000000000
--- a/Jellyfin.Api/Helpers/ClassMigrationHelper.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Reflection;
-
-namespace Jellyfin.Api.Helpers
-{
- /// <summary>
- /// A static class for copying matching properties from one object to another.
- /// TODO: remove at the point when a fixed migration path has been decided upon.
- /// </summary>
- public static class ClassMigrationHelper
- {
- /// <summary>
- /// Extension for 'Object' that copies the properties to a destination object.
- /// </summary>
- /// <param name="source">The source.</param>
- /// <param name="destination">The destination.</param>
- public static void CopyProperties(this object source, object destination)
- {
- // If any this null throw an exception.
- if (source == null || destination == null)
- {
- throw new ArgumentException("Source or/and Destination Objects are null");
- }
-
- // Getting the Types of the objects.
- Type typeDest = destination.GetType();
- Type typeSrc = source.GetType();
-
- // Iterate the Properties of the source instance and populate them from their destination counterparts.
- PropertyInfo[] srcProps = typeSrc.GetProperties();
- foreach (PropertyInfo srcProp in srcProps)
- {
- if (!srcProp.CanRead)
- {
- continue;
- }
-
- var targetProperty = typeDest.GetProperty(srcProp.Name);
- if (targetProperty == null)
- {
- continue;
- }
-
- if (!targetProperty.CanWrite)
- {
- continue;
- }
-
- var obj = targetProperty.GetSetMethod(true);
- if (obj != null && obj.IsPrivate)
- {
- continue;
- }
-
- var target = targetProperty.GetSetMethod();
- if (target != null && (target.Attributes & MethodAttributes.Static) != 0)
- {
- continue;
- }
-
- if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
- {
- continue;
- }
-
- // Passed all tests, lets set the value.
- targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
- }
- }
- }
-}
diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs
index 0efd3443b..ca8bc0bdd 100644
--- a/Jellyfin.Api/Helpers/RequestHelpers.cs
+++ b/Jellyfin.Api/Helpers/RequestHelpers.cs
@@ -137,21 +137,5 @@ namespace Jellyfin.Api.Helpers
TotalRecordCount = result.TotalRecordCount
};
}
-
- internal static string[] GetItemTypeStrings(IReadOnlyList<BaseItemKind> itemKinds)
- {
- if (itemKinds.Count == 0)
- {
- return Array.Empty<string>();
- }
-
- var itemTypes = new string[itemKinds.Count];
- for (var i = 0; i < itemKinds.Count; i++)
- {
- itemTypes[i] = itemKinds[i].ToString();
- }
-
- return itemTypes;
- }
}
}
diff --git a/Jellyfin.Networking/Configuration/NetworkConfigurationFactory.cs b/Jellyfin.Networking/Configuration/NetworkConfigurationFactory.cs
index ac0485d87..14726565a 100644
--- a/Jellyfin.Networking/Configuration/NetworkConfigurationFactory.cs
+++ b/Jellyfin.Networking/Configuration/NetworkConfigurationFactory.cs
@@ -16,11 +16,7 @@ namespace Jellyfin.Networking.Configuration
{
return new[]
{
- new ConfigurationStore
- {
- Key = "network",
- ConfigurationType = typeof(NetworkConfiguration)
- }
+ new NetworkConfigurationStore()
};
}
}
diff --git a/Jellyfin.Networking/Configuration/NetworkConfigurationStore.cs b/Jellyfin.Networking/Configuration/NetworkConfigurationStore.cs
new file mode 100644
index 000000000..a268ebb68
--- /dev/null
+++ b/Jellyfin.Networking/Configuration/NetworkConfigurationStore.cs
@@ -0,0 +1,24 @@
+using MediaBrowser.Common.Configuration;
+
+namespace Jellyfin.Networking.Configuration
+{
+ /// <summary>
+ /// A configuration that stores network related settings.
+ /// </summary>
+ public class NetworkConfigurationStore : ConfigurationStore
+ {
+ /// <summary>
+ /// The name of the configuration in the storage.
+ /// </summary>
+ public const string StoreKey = "network";
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NetworkConfigurationStore"/> class.
+ /// </summary>
+ public NetworkConfigurationStore()
+ {
+ ConfigurationType = typeof(NetworkConfiguration);
+ Key = StoreKey;
+ }
+ }
+}
diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs
index cf002dc73..58b30ad2d 100644
--- a/Jellyfin.Networking/Manager/NetworkManager.cs
+++ b/Jellyfin.Networking/Manager/NetworkManager.cs
@@ -727,7 +727,7 @@ namespace Jellyfin.Networking.Manager
private void ConfigurationUpdated(object? sender, ConfigurationUpdateEventArgs evt)
{
- if (evt.Key.Equals("network", StringComparison.Ordinal))
+ if (evt.Key.Equals(NetworkConfigurationStore.StoreKey, StringComparison.Ordinal))
{
UpdateSettings((NetworkConfiguration)evt.NewConfiguration);
}
diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
index 73ee69424..8b461e6af 100644
--- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
+++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
@@ -18,7 +18,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="System.Linq.Async" Version="5.0.0" />
+ <PackageReference Include="System.Linq.Async" Version="5.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs
index 7365c8dbc..e9a45c140 100644
--- a/Jellyfin.Server/Migrations/MigrationRunner.cs
+++ b/Jellyfin.Server/Migrations/MigrationRunner.cs
@@ -1,6 +1,11 @@
using System;
+using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using Emby.Server.Implementations;
+using Emby.Server.Implementations.Serialization;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -12,6 +17,14 @@ namespace Jellyfin.Server.Migrations
public sealed class MigrationRunner
{
/// <summary>
+ /// The list of known pre-startup migrations, in order of applicability.
+ /// </summary>
+ private static readonly Type[] _preStartupMigrationTypes =
+ {
+ typeof(PreStartupRoutines.CreateNetworkConfiguration)
+ };
+
+ /// <summary>
/// The list of known migrations, in order of applicability.
/// </summary>
private static readonly Type[] _migrationTypes =
@@ -41,17 +54,55 @@ namespace Jellyfin.Server.Migrations
.Select(m => ActivatorUtilities.CreateInstance(host.ServiceProvider, m))
.OfType<IMigrationRoutine>()
.ToArray();
+
var migrationOptions = host.ConfigurationManager.GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
+ HandleStartupWizardCondition(migrations, migrationOptions, host.ConfigurationManager.Configuration.IsStartupWizardCompleted, logger);
+ PerformMigrations(migrations, migrationOptions, options => host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, options), logger);
+ }
- if (!host.ConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0)
+ /// <summary>
+ /// Run all needed pre-startup migrations.
+ /// </summary>
+ /// <param name="appPaths">Application paths.</param>
+ /// <param name="loggerFactory">Factory for making the logger.</param>
+ public static void RunPreStartup(ServerApplicationPaths appPaths, ILoggerFactory loggerFactory)
+ {
+ var logger = loggerFactory.CreateLogger<MigrationRunner>();
+ var migrations = _preStartupMigrationTypes
+ .Select(m => Activator.CreateInstance(m, appPaths, loggerFactory))
+ .OfType<IMigrationRoutine>()
+ .ToArray();
+
+ var xmlSerializer = new MyXmlSerializer();
+ var migrationConfigPath = Path.Join(appPaths.ConfigurationDirectoryPath, MigrationsListStore.StoreKey.ToLowerInvariant() + ".xml");
+ var migrationOptions = File.Exists(migrationConfigPath)
+ ? (MigrationOptions)xmlSerializer.DeserializeFromFile(typeof(MigrationOptions), migrationConfigPath)!
+ : new MigrationOptions();
+
+ // We have to deserialize it manually since the configuration manager may overwrite it
+ var serverConfig = File.Exists(appPaths.SystemConfigurationFilePath)
+ ? (ServerConfiguration)xmlSerializer.DeserializeFromFile(typeof(ServerConfiguration), appPaths.SystemConfigurationFilePath)!
+ : new ServerConfiguration();
+
+ HandleStartupWizardCondition(migrations, migrationOptions, serverConfig.IsStartupWizardCompleted, logger);
+ PerformMigrations(migrations, migrationOptions, options => xmlSerializer.SerializeToFile(options, migrationConfigPath), logger);
+ }
+
+ private static void HandleStartupWizardCondition(IEnumerable<IMigrationRoutine> migrations, MigrationOptions migrationOptions, bool isStartWizardCompleted, ILogger logger)
+ {
+ if (isStartWizardCompleted || migrationOptions.Applied.Count != 0)
{
- // If startup wizard is not finished, this is a fresh install.
- // Don't run any migrations, just mark all of them as applied.
- logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
- migrationOptions.Applied.AddRange(migrations.Where(m => !m.PerformOnNewInstall).Select(m => (m.Id, m.Name)));
- host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
+ return;
}
+ // If startup wizard is not finished, this is a fresh install.
+ var onlyOldInstalls = migrations.Where(m => !m.PerformOnNewInstall).ToArray();
+ logger.LogInformation("Marking following migrations as applied because this is a fresh install: {@OnlyOldInstalls}", onlyOldInstalls.Select(m => m.Name));
+ migrationOptions.Applied.AddRange(onlyOldInstalls.Select(m => (m.Id, m.Name)));
+ }
+
+ private static void PerformMigrations(IMigrationRoutine[] migrations, MigrationOptions migrationOptions, Action<MigrationOptions> saveConfiguration, ILogger logger)
+ {
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
for (var i = 0; i < migrations.Length; i++)
@@ -78,7 +129,7 @@ namespace Jellyfin.Server.Migrations
// Mark the migration as completed
logger.LogInformation("Migration '{Name}' applied successfully", migrationRoutine.Name);
migrationOptions.Applied.Add((migrationRoutine.Id, migrationRoutine.Name));
- host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
+ saveConfiguration(migrationOptions);
logger.LogDebug("Migration '{Name}' marked as applied in configuration.", migrationRoutine.Name);
}
}
diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs
new file mode 100644
index 000000000..a951f751e
--- /dev/null
+++ b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs
@@ -0,0 +1,138 @@
+using System;
+using System.IO;
+using System.Xml;
+using System.Xml.Serialization;
+using Emby.Server.Implementations;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server.Migrations.PreStartupRoutines;
+
+/// <inheritdoc />
+public class CreateNetworkConfiguration : IMigrationRoutine
+{
+ private readonly ServerApplicationPaths _applicationPaths;
+ private readonly ILogger<CreateNetworkConfiguration> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CreateNetworkConfiguration"/> class.
+ /// </summary>
+ /// <param name="applicationPaths">An instance of <see cref="ServerApplicationPaths"/>.</param>
+ /// <param name="loggerFactory">An instance of the <see cref="ILoggerFactory"/> interface.</param>
+ public CreateNetworkConfiguration(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory)
+ {
+ _applicationPaths = applicationPaths;
+ _logger = loggerFactory.CreateLogger<CreateNetworkConfiguration>();
+ }
+
+ /// <inheritdoc />
+ public Guid Id => Guid.Parse("9B354818-94D5-4B68-AC49-E35CB85F9D84");
+
+ /// <inheritdoc />
+ public string Name => nameof(CreateNetworkConfiguration);
+
+ /// <inheritdoc />
+ public bool PerformOnNewInstall => false;
+
+ /// <inheritdoc />
+ public void Perform()
+ {
+ string path = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "network.xml");
+ if (File.Exists(path))
+ {
+ _logger.LogDebug("Network configuration file already exists, skipping");
+ return;
+ }
+
+ var serverConfigSerializer = new XmlSerializer(typeof(OldNetworkConfiguration), new XmlRootAttribute("ServerConfiguration"));
+ using var xmlReader = XmlReader.Create(_applicationPaths.SystemConfigurationFilePath);
+ var networkSettings = serverConfigSerializer.Deserialize(xmlReader);
+
+ var networkConfigSerializer = new XmlSerializer(typeof(OldNetworkConfiguration), new XmlRootAttribute("NetworkConfiguration"));
+ var xmlWriterSettings = new XmlWriterSettings { Indent = true };
+ using var xmlWriter = XmlWriter.Create(path, xmlWriterSettings);
+ networkConfigSerializer.Serialize(xmlWriter, networkSettings);
+ }
+
+#pragma warning disable CS1591
+ public sealed class OldNetworkConfiguration
+ {
+ public const int DefaultHttpPort = 8096;
+
+ public const int DefaultHttpsPort = 8920;
+
+ private string _baseUrl = string.Empty;
+
+ public bool RequireHttps { get; set; }
+
+ public string CertificatePath { get; set; } = string.Empty;
+
+ public string CertificatePassword { get; set; } = string.Empty;
+
+ public string BaseUrl
+ {
+ get => _baseUrl;
+ set
+ {
+ // Normalize the start of the string
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ // If baseUrl is empty, set an empty prefix string
+ _baseUrl = string.Empty;
+ return;
+ }
+
+ if (value[0] != '/')
+ {
+ // If baseUrl was not configured with a leading slash, append one for consistency
+ value = "/" + value;
+ }
+
+ // Normalize the end of the string
+ if (value[^1] == '/')
+ {
+ // If baseUrl was configured with a trailing slash, remove it for consistency
+ value = value.Remove(value.Length - 1);
+ }
+
+ _baseUrl = value;
+ }
+ }
+
+ public int PublicHttpsPort { get; set; } = DefaultHttpsPort;
+
+ public int HttpServerPortNumber { get; set; } = DefaultHttpPort;
+
+ public int HttpsPortNumber { get; set; } = DefaultHttpsPort;
+
+ public bool EnableHttps { get; set; }
+
+ public int PublicPort { get; set; } = DefaultHttpPort;
+
+ public bool EnableIPV6 { get; set; }
+
+ public bool EnableIPV4 { get; set; } = true;
+
+ public bool IgnoreVirtualInterfaces { get; set; } = true;
+
+ public string VirtualInterfaceNames { get; set; } = "vEthernet*";
+
+ public bool TrustAllIP6Interfaces { get; set; }
+
+ public string[] PublishedServerUriBySubnet { get; set; } = Array.Empty<string>();
+
+ public string[] RemoteIPFilter { get; set; } = Array.Empty<string>();
+
+ public bool IsRemoteIPFilterBlacklist { get; set; }
+
+ public bool EnableUPnP { get; set; }
+
+ public bool EnableRemoteAccess { get; set; } = true;
+
+ public string[] LocalNetworkSubnets { get; set; } = Array.Empty<string>();
+
+ public string[] LocalNetworkAddresses { get; set; } = Array.Empty<string>();
+
+ public string[] KnownProxies { get; set; } = Array.Empty<string>();
+ }
+#pragma warning restore CS1591
+}
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 7f158aebb..f40526e22 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -175,6 +175,7 @@ namespace Jellyfin.Server
}
PerformStaticInitialization();
+ Migrations.MigrationRunner.RunPreStartup(appPaths, _loggerFactory);
var appHost = new CoreAppHost(
appPaths,
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index f30f8ce7f..11b95b94b 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -88,7 +88,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Audio), nameof(MusicVideo), nameof(MusicAlbum) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Audio, BaseItemKind.MusicVideo, BaseItemKind.MusicAlbum };
query.ArtistIds = new[] { Id };
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index dc6fcc55a..73a25232e 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Diacritics.Extensions;
+using Jellyfin.Data.Enums;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.Audio
@@ -66,7 +67,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
query.GenreIds = new[] { Id };
- query.IncludeItemTypes = new[] { nameof(MusicVideo), nameof(Audio), nameof(MusicAlbum), nameof(MusicArtist) };
+ query.IncludeItemTypes = new[] { BaseItemKind.MusicVideo, BaseItemKind.Audio, BaseItemKind.MusicAlbum, BaseItemKind.MusicArtist };
return LibraryManager.GetItemList(query);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 200f98cc9..4114ff7b0 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -40,6 +40,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo>, IEquatable<BaseItem>
{
+ private BaseItemKind? _baseItemKind;
+
public const string TrailerFileName = "trailer";
public const string TrailersFolderName = "trailers";
public const string ThemeSongsFolderName = "theme-music";
@@ -1808,7 +1810,7 @@ namespace MediaBrowser.Controller.Entities
public BaseItemKind GetBaseItemKind()
{
- return Enum.Parse<BaseItemKind>(GetClientTypeName());
+ return _baseItemKind ??= Enum.Parse<BaseItemKind>(GetClientTypeName());
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index ec1ebaabe..55551e70e 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -792,7 +792,7 @@ namespace MediaBrowser.Controller.Entities
private bool RequiresPostFiltering2(InternalItemsQuery query)
{
- if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.BoxSet)
{
Logger.LogDebug("Query requires post-filtering due to BoxSet query");
return true;
@@ -882,7 +882,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsPlayed.HasValue)
{
- if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(nameof(Series)))
+ if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(BaseItemKind.Series))
{
Logger.LogDebug("Query requires post-filtering due to IsPlayed");
return true;
@@ -1101,7 +1101,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Movie", StringComparer.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(BaseItemKind.Movie))
{
param = true;
}
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 338f96204..4be673237 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Diacritics.Extensions;
-using MediaBrowser.Controller.Entities.Audio;
+using Jellyfin.Data.Enums;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -66,10 +66,10 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { Id };
query.ExcludeItemTypes = new[]
{
- nameof(MusicVideo),
- nameof(Entities.Audio.Audio),
- nameof(MusicAlbum),
- nameof(MusicArtist)
+ BaseItemKind.MusicVideo,
+ BaseItemKind.Audio,
+ BaseItemKind.MusicAlbum,
+ BaseItemKind.MusicArtist
};
return LibraryManager.GetItemList(query);
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 0baa7725e..f06b5c787 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -27,13 +27,13 @@ namespace MediaBrowser.Controller.Entities
ExcludeArtistIds = Array.Empty<Guid>();
ExcludeInheritedTags = Array.Empty<string>();
ExcludeItemIds = Array.Empty<Guid>();
- ExcludeItemTypes = Array.Empty<string>();
+ ExcludeItemTypes = Array.Empty<BaseItemKind>();
ExcludeTags = Array.Empty<string>();
GenreIds = Array.Empty<Guid>();
Genres = Array.Empty<string>();
GroupByPresentationUniqueKey = true;
ImageTypes = Array.Empty<ImageType>();
- IncludeItemTypes = Array.Empty<string>();
+ IncludeItemTypes = Array.Empty<BaseItemKind>();
ItemIds = Array.Empty<Guid>();
MediaTypes = Array.Empty<string>();
MinSimilarityScore = 20;
@@ -87,9 +87,9 @@ namespace MediaBrowser.Controller.Entities
public string[] MediaTypes { get; set; }
- public string[] IncludeItemTypes { get; set; }
+ public BaseItemKind[] IncludeItemTypes { get; set; }
- public string[] ExcludeItemTypes { get; set; }
+ public BaseItemKind[] ExcludeItemTypes { get; set; }
public string[] ExcludeTags { get; set; }
@@ -229,7 +229,7 @@ namespace MediaBrowser.Controller.Entities
public Guid ParentId { get; set; }
- public string? ParentType { get; set; }
+ public BaseItemKind? ParentType { get; set; }
public Guid[] AncestorIds { get; set; }
@@ -314,7 +314,7 @@ namespace MediaBrowser.Controller.Entities
else
{
ParentId = value.Id;
- ParentType = value.GetType().Name;
+ ParentType = value.GetBaseItemKind();
}
}
}
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 90fcffe32..bdadc2775 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -127,7 +127,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Season) },
+ IncludeItemTypes = new[] { BaseItemKind.Season },
IsVirtualItem = false,
Limit = 0,
DtoOptions = new DtoOptions(false)
@@ -155,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
}
query.IsVirtualItem = false;
@@ -209,7 +209,7 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
- query.IncludeItemTypes = new[] { nameof(Season) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Season };
query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
if (user != null && !user.DisplayMissingEpisodes)
@@ -235,7 +235,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Episode), nameof(Season) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season };
}
query.IsVirtualItem = false;
@@ -255,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Episode), nameof(Season) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
@@ -359,7 +359,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 25511f9d9..aacf1498f 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -140,7 +140,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
}
return parent.QueryRecursive(query);
@@ -165,7 +165,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -176,7 +176,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -187,7 +187,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
return _libraryManager.GetItemsResult(query);
}
@@ -198,7 +198,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -206,7 +206,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
{
query.Parent = null;
- query.IncludeItemTypes = new[] { nameof(BoxSet) };
+ query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
query.SetUser(user);
query.Recursive = true;
@@ -220,7 +220,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -233,7 +233,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -252,7 +252,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Movie) },
+ IncludeItemTypes = new[] { BaseItemKind.Movie },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -283,7 +283,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -299,9 +299,9 @@ namespace MediaBrowser.Controller.Entities
{
query.IncludeItemTypes = new[]
{
- nameof(Series),
- nameof(Season),
- nameof(Episode)
+ BaseItemKind.Series,
+ BaseItemKind.Season,
+ BaseItemKind.Episode
};
}
@@ -329,7 +329,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
query.IsVirtualItem = false;
return ConvertToResult(_libraryManager.GetItemList(query));
@@ -360,7 +360,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -371,7 +371,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -380,7 +380,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -411,7 +411,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -499,12 +499,12 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
{
return false;
}
- if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
+ if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
{
return false;
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index de42c67d3..8e0593507 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -33,6 +33,7 @@ namespace MediaBrowser.Controller.Entities
AdditionalParts = Array.Empty<string>();
LocalAlternateVersions = Array.Empty<string>();
SubtitleFiles = Array.Empty<string>();
+ AudioFiles = Array.Empty<string>();
LinkedAlternateVersions = Array.Empty<LinkedChild>();
}
@@ -98,6 +99,12 @@ namespace MediaBrowser.Controller.Entities
public string[] SubtitleFiles { get; set; }
/// <summary>
+ /// Gets or sets the audio paths.
+ /// </summary>
+ /// <value>The audio paths.</value>
+ public string[] AudioFiles { get; set; }
+
+ /// <summary>
/// Gets or sets a value indicating whether this instance has subtitles.
/// </summary>
/// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 5715194b8..92b345f12 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -696,6 +696,11 @@ namespace MediaBrowser.Controller.MediaEncoding
arg.Append(" -i \"").Append(subtitlePath).Append('\"');
}
+ if (state.AudioStream != null && state.AudioStream.IsExternal)
+ {
+ arg.Append(" -i \"").Append(state.AudioStream.Path).Append('"');
+ }
+
return arg.ToString();
}
@@ -1999,10 +2004,24 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.AudioStream != null)
{
- args += string.Format(
- CultureInfo.InvariantCulture,
- " -map 0:{0}",
- state.AudioStream.Index);
+ if (state.AudioStream.IsExternal)
+ {
+ int externalAudioMapIndex = state.SubtitleStream != null && state.SubtitleStream.IsExternal ? 2 : 1;
+ int externalAudioStream = state.MediaSource.MediaStreams.Where(i => i.Path == state.AudioStream.Path).ToList().IndexOf(state.AudioStream);
+
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ " -map {0}:{1}",
+ externalAudioMapIndex,
+ externalAudioStream);
+ }
+ else
+ {
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ " -map 0:{0}",
+ state.AudioStream.Index);
+ }
}
else
{
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index 5e671a725..89f3bdf46 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -189,7 +189,7 @@ namespace MediaBrowser.Controller.Playlists
return LibraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
- IncludeItemTypes = new[] { nameof(Audio) },
+ IncludeItemTypes = new[] { BaseItemKind.Audio },
GenreIds = new[] { musicGenre.Id },
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
@@ -201,7 +201,7 @@ namespace MediaBrowser.Controller.Playlists
return LibraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
- IncludeItemTypes = new[] { nameof(Audio) },
+ IncludeItemTypes = new[] { BaseItemKind.Audio },
ArtistIds = new[] { musicArtist.Id },
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 32ff1dee6..770881149 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -45,6 +45,7 @@ namespace MediaBrowser.MediaEncoding.Probing
{
"AC/DC",
"Au/Ra",
+ "Bremer/McCoy",
"이달의 소녀 1/3",
"LOONA 1/3",
"LOONA / yyxy",
@@ -648,11 +649,6 @@ namespace MediaBrowser.MediaEncoding.Probing
stream.IsAVC = false;
}
- if (!string.IsNullOrWhiteSpace(streamInfo.FieldOrder) && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase))
- {
- stream.IsInterlaced = true;
- }
-
// Filter out junk
if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString) && !streamInfo.CodecTagString.Contains("[0]", StringComparison.OrdinalIgnoreCase))
{
@@ -724,6 +720,23 @@ namespace MediaBrowser.MediaEncoding.Probing
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
+ // Some interlaced H.264 files in mp4 containers using MBAFF coding aren't flagged as being interlaced by FFprobe,
+ // so for H.264 files we also calculate the frame rate from the codec time base and check if it is double the reported
+ // frame rate (both rounded to the nearest integer) to determine if the file is interlaced
+ int roundedTimeBaseFPS = Convert.ToInt32(1 / GetFrameRate(stream.CodecTimeBase) ?? 0);
+ int roundedDoubleFrameRate = Convert.ToInt32(stream.AverageFrameRate * 2 ?? 0);
+
+ bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
+ && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase);
+ bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)
+ && string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
+ && roundedTimeBaseFPS == roundedDoubleFrameRate;
+
+ if (videoInterlaced || h264MbaffCoded)
+ {
+ stream.IsInterlaced = true;
+ }
+
if (isAudio
|| string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 0ab721b77..46e61ee1a 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -14,18 +14,6 @@ namespace MediaBrowser.Model.Configuration
public class ServerConfiguration : BaseApplicationConfiguration
{
/// <summary>
- /// The default value for <see cref="HttpServerPortNumber"/>.
- /// </summary>
- public const int DefaultHttpPort = 8096;
-
- /// <summary>
- /// The default value for <see cref="PublicHttpsPort"/> and <see cref="HttpsPortNumber"/>.
- /// </summary>
- public const int DefaultHttpsPort = 8920;
-
- private string _baseUrl = string.Empty;
-
- /// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
public ServerConfiguration()
@@ -76,149 +64,13 @@ namespace MediaBrowser.Model.Configuration
}
/// <summary>
- /// Gets or sets a value indicating whether to enable automatic port forwarding.
- /// </summary>
- public bool EnableUPnP { get; set; } = false;
-
- /// <summary>
/// Gets or sets a value indicating whether to enable prometheus metrics exporting.
/// </summary>
public bool EnableMetrics { get; set; } = false;
- /// <summary>
- /// Gets or sets the public mapped port.
- /// </summary>
- /// <value>The public mapped port.</value>
- public int PublicPort { get; set; } = DefaultHttpPort;
-
- /// <summary>
- /// Gets or sets a value indicating whether the http port should be mapped as part of UPnP automatic port forwarding.
- /// </summary>
- public bool UPnPCreateHttpPortMap { get; set; } = false;
-
- /// <summary>
- /// Gets or sets client udp port range.
- /// </summary>
- public string UDPPortRange { get; set; } = string.Empty;
-
- /// <summary>
- /// Gets or sets a value indicating whether IPV6 capability is enabled.
- /// </summary>
- public bool EnableIPV6 { get; set; } = false;
-
- /// <summary>
- /// Gets or sets a value indicating whether IPV4 capability is enabled.
- /// </summary>
- public bool EnableIPV4 { get; set; } = true;
-
- /// <summary>
- /// Gets or sets a value indicating whether detailed ssdp logs are sent to the console/log.
- /// "Emby.Dlna": "Debug" must be set in logging.default.json for this property to work.
- /// </summary>
- public bool EnableSSDPTracing { get; set; } = false;
-
- /// <summary>
- /// Gets or sets a value indicating whether an IP address is to be used to filter the detailed ssdp logs that are being sent to the console/log.
- /// If the setting "Emby.Dlna": "Debug" msut be set in logging.default.json for this property to work.
- /// </summary>
- public string SSDPTracingFilter { get; set; } = string.Empty;
-
- /// <summary>
- /// Gets or sets the number of times SSDP UDP messages are sent.
- /// </summary>
- public int UDPSendCount { get; set; } = 2;
-
- /// <summary>
- /// Gets or sets the delay between each groups of SSDP messages (in ms).
- /// </summary>
- public int UDPSendDelay { get; set; } = 100;
-
- /// <summary>
- /// Gets or sets a value indicating whether address names that match <see cref="VirtualInterfaceNames"/> should be Ignore for the purposes of binding.
- /// </summary>
- public bool IgnoreVirtualInterfaces { get; set; } = true;
-
- /// <summary>
- /// Gets or sets a value indicating the interfaces that should be ignored. The list can be comma separated. <seealso cref="IgnoreVirtualInterfaces"/>.
- /// </summary>
- public string VirtualInterfaceNames { get; set; } = "vEthernet*";
-
- /// <summary>
- /// Gets or sets the time (in seconds) between the pings of SSDP gateway monitor.
- /// </summary>
- public int GatewayMonitorPeriod { get; set; } = 60;
-
- /// <summary>
- /// Gets a value indicating whether multi-socket binding is available.
- /// </summary>
- public bool EnableMultiSocketBinding { get; } = true;
-
- /// <summary>
- /// Gets or sets a value indicating whether all IPv6 interfaces should be treated as on the internal network.
- /// Depending on the address range implemented ULA ranges might not be used.
- /// </summary>
- public bool TrustAllIP6Interfaces { get; set; } = false;
-
- /// <summary>
- /// Gets or sets the ports that HDHomerun uses.
- /// </summary>
- public string HDHomerunPortRange { get; set; } = string.Empty;
-
- /// <summary>
- /// Gets or sets PublishedServerUri to advertise for specific subnets.
- /// </summary>
- public string[] PublishedServerUriBySubnet { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets a value indicating whether Autodiscovery tracing is enabled.
- /// </summary>
- public bool AutoDiscoveryTracing { get; set; } = false;
-
- /// <summary>
- /// Gets or sets a value indicating whether Autodiscovery is enabled.
- /// </summary>
- public bool AutoDiscovery { get; set; } = true;
-
- /// <summary>
- /// Gets or sets the public HTTPS port.
- /// </summary>
- /// <value>The public HTTPS port.</value>
- public int PublicHttpsPort { get; set; } = DefaultHttpsPort;
-
- /// <summary>
- /// Gets or sets the HTTP server port number.
- /// </summary>
- /// <value>The HTTP server port number.</value>
- public int HttpServerPortNumber { get; set; } = DefaultHttpPort;
-
- /// <summary>
- /// Gets or sets the HTTPS server port number.
- /// </summary>
- /// <value>The HTTPS server port number.</value>
- public int HttpsPortNumber { get; set; } = DefaultHttpsPort;
-
- /// <summary>
- /// Gets or sets a value indicating whether to use HTTPS.
- /// </summary>
- /// <remarks>
- /// In order for HTTPS to be used, in addition to setting this to true, valid values must also be
- /// provided for <see cref="CertificatePath"/> and <see cref="CertificatePassword"/>.
- /// </remarks>
- public bool EnableHttps { get; set; } = false;
-
public bool EnableNormalizedItemByNameIds { get; set; } = true;
/// <summary>
- /// Gets or sets the filesystem path of an X.509 certificate to use for SSL.
- /// </summary>
- public string CertificatePath { get; set; } = string.Empty;
-
- /// <summary>
- /// Gets or sets the password required to access the X.509 certificate data in the file specified by <see cref="CertificatePath"/>.
- /// </summary>
- public string CertificatePassword { get; set; } = string.Empty;
-
- /// <summary>
/// Gets or sets a value indicating whether this instance is port authorized.
/// </summary>
/// <value><c>true</c> if this instance is port authorized; otherwise, <c>false</c>.</value>
@@ -230,11 +82,6 @@ namespace MediaBrowser.Model.Configuration
public bool QuickConnectAvailable { get; set; } = false;
/// <summary>
- /// Gets or sets a value indicating whether access outside of the LAN is permitted.
- /// </summary>
- public bool EnableRemoteAccess { get; set; } = true;
-
- /// <summary>
/// Gets or sets a value indicating whether [enable case sensitive item ids].
/// </summary>
/// <value><c>true</c> if [enable case sensitive item ids]; otherwise, <c>false</c>.</value>
@@ -319,13 +166,6 @@ namespace MediaBrowser.Model.Configuration
public int LibraryMonitorDelay { get; set; } = 60;
/// <summary>
- /// Gets or sets a value indicating whether [enable dashboard response caching].
- /// Allows potential contributors without visual studio to modify production dashboard code and test changes.
- /// </summary>
- /// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
- public bool EnableDashboardResponseCaching { get; set; } = true;
-
- /// <summary>
/// Gets or sets the image saving convention.
/// </summary>
/// <value>The image saving convention.</value>
@@ -337,36 +177,6 @@ namespace MediaBrowser.Model.Configuration
public string ServerName { get; set; } = string.Empty;
- public string BaseUrl
- {
- get => _baseUrl;
- set
- {
- // Normalize the start of the string
- if (string.IsNullOrWhiteSpace(value))
- {
- // If baseUrl is empty, set an empty prefix string
- _baseUrl = string.Empty;
- return;
- }
-
- if (value[0] != '/')
- {
- // If baseUrl was not configured with a leading slash, append one for consistency
- value = "/" + value;
- }
-
- // Normalize the end of the string
- if (value[value.Length - 1] == '/')
- {
- // If baseUrl was configured with a trailing slash, remove it for consistency
- value = value.Remove(value.Length - 1);
- }
-
- _baseUrl = value;
- }
- }
-
public string UICulture { get; set; } = "en-US";
public bool SaveMetadataHidden { get; set; } = false;
@@ -381,43 +191,16 @@ namespace MediaBrowser.Model.Configuration
public bool DisplaySpecialsWithinSeasons { get; set; } = true;
- /// <summary>
- /// Gets or sets the subnets that are deemed to make up the LAN.
- /// </summary>
- public string[] LocalNetworkSubnets { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the interface addresses which Jellyfin will bind to. If empty, all interfaces will be used.
- /// </summary>
- public string[] LocalNetworkAddresses { get; set; } = Array.Empty<string>();
-
public string[] CodecsUsed { get; set; } = Array.Empty<string>();
public List<RepositoryInfo> PluginRepositories { get; set; } = new List<RepositoryInfo>();
public bool EnableExternalContentInSuggestions { get; set; } = true;
- /// <summary>
- /// Gets or sets a value indicating whether the server should force connections over HTTPS.
- /// </summary>
- public bool RequireHttps { get; set; } = false;
-
- /// <summary>
- /// Gets or sets the filter for remote IP connectivity. Used in conjuntion with <seealso cref="IsRemoteIPFilterBlacklist"/>.
- /// </summary>
- public string[] RemoteIPFilter { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets a value indicating whether <seealso cref="RemoteIPFilter"/> contains a blacklist or a whitelist. Default is a whitelist.
- /// </summary>
- public bool IsRemoteIPFilterBlacklist { get; set; } = false;
-
public int ImageExtractionTimeoutMs { get; set; } = 0;
public PathSubstitution[] PathSubstitutions { get; set; } = Array.Empty<PathSubstitution>();
- public string[] UninstalledPlugins { get; set; } = Array.Empty<string>();
-
/// <summary>
/// Gets or sets a value indicating whether slow server responses should be logged as a warning.
/// </summary>
@@ -434,11 +217,6 @@ namespace MediaBrowser.Model.Configuration
public string[] CorsHosts { get; set; } = new[] { "*" };
/// <summary>
- /// Gets or sets the known proxies.
- /// </summary>
- public string[] KnownProxies { get; set; } = Array.Empty<string>();
-
- /// <summary>
/// Gets or sets the number of days we should retain activity logs.
/// </summary>
public int? ActivityLogRetentionDays { get; set; } = 30;
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 506e8e9d6..3b03466e9 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -116,7 +116,7 @@ namespace MediaBrowser.Model.Net
{ "audio/x-wavpack", ".wv" },
// Type image
- { "image/jpg", ".jpg" },
+ { "image/jpeg", ".jpg" },
{ "image/x-png", ".png" },
// Type text
@@ -137,7 +137,7 @@ namespace MediaBrowser.Model.Net
/// <param name="filename">The filename to find the MIME type of.</param>
/// <param name="defaultValue">The default value to return if no fitting MIME type is found.</param>
/// <returns>The correct MIME type for the given filename, or <paramref name="defaultValue"/> if it wasn't found.</returns>
- [return: NotNullIfNotNullAttribute("defaultValue")]
+ [return: NotNullIfNotNull("defaultValue")]
public static string? GetMimeType(string filename, string? defaultValue = null)
{
if (filename.Length == 0)
diff --git a/MediaBrowser.Model/Querying/LatestItemsQuery.cs b/MediaBrowser.Model/Querying/LatestItemsQuery.cs
index f555ffb36..d2d9f1f9a 100644
--- a/MediaBrowser.Model/Querying/LatestItemsQuery.cs
+++ b/MediaBrowser.Model/Querying/LatestItemsQuery.cs
@@ -2,6 +2,7 @@
#pragma warning disable CS1591
using System;
+using Jellyfin.Data.Enums;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Querying
@@ -48,7 +49,7 @@ namespace MediaBrowser.Model.Querying
/// Gets or sets the include item types.
/// </summary>
/// <value>The include item types.</value>
- public string[] IncludeItemTypes { get; set; }
+ public BaseItemKind[] IncludeItemTypes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is played.
diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs
index aedfa4d36..1caed827f 100644
--- a/MediaBrowser.Model/Search/SearchQuery.cs
+++ b/MediaBrowser.Model/Search/SearchQuery.cs
@@ -2,6 +2,7 @@
#pragma warning disable CS1591
using System;
+using Jellyfin.Data.Enums;
namespace MediaBrowser.Model.Search
{
@@ -16,8 +17,8 @@ namespace MediaBrowser.Model.Search
IncludeStudios = true;
MediaTypes = Array.Empty<string>();
- IncludeItemTypes = Array.Empty<string>();
- ExcludeItemTypes = Array.Empty<string>();
+ IncludeItemTypes = Array.Empty<BaseItemKind>();
+ ExcludeItemTypes = Array.Empty<BaseItemKind>();
}
/// <summary>
@@ -56,9 +57,9 @@ namespace MediaBrowser.Model.Search
public string[] MediaTypes { get; set; }
- public string[] IncludeItemTypes { get; set; }
+ public BaseItemKind[] IncludeItemTypes { get; set; }
- public string[] ExcludeItemTypes { get; set; }
+ public BaseItemKind[] ExcludeItemTypes { get; set; }
public Guid? ParentId { get; set; }
diff --git a/MediaBrowser.Model/Session/BrowseRequest.cs b/MediaBrowser.Model/Session/BrowseRequest.cs
index 65afe5cf3..5ad7d783a 100644
--- a/MediaBrowser.Model/Session/BrowseRequest.cs
+++ b/MediaBrowser.Model/Session/BrowseRequest.cs
@@ -1,3 +1,5 @@
+using Jellyfin.Data.Enums;
+
#nullable disable
namespace MediaBrowser.Model.Session
{
@@ -8,10 +10,9 @@ namespace MediaBrowser.Model.Session
{
/// <summary>
/// Gets or sets the item type.
- /// Artist, Genre, Studio, Person, or any kind of BaseItem.
/// </summary>
/// <value>The type of the item.</value>
- public string ItemType { get; set; }
+ public BaseItemKind ItemType { get; set; }
/// <summary>
/// Gets or sets the item id.
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index ca557f6d6..6e5753361 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -11,6 +11,7 @@ using System.Net.Http;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using Jellyfin.Data.Events;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Progress;
@@ -1133,7 +1134,7 @@ namespace MediaBrowser.Providers.Manager
var albums = _libraryManager
.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { nameof(MusicAlbum) },
+ IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
ArtistIds = new[] { item.Id },
DtoOptions = new DtoOptions(false)
{
diff --git a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs
new file mode 100644
index 000000000..425913501
--- /dev/null
+++ b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Naming.Audio;
+using Emby.Naming.Common;
+using Jellyfin.Extensions;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.MediaInfo;
+
+namespace MediaBrowser.Providers.MediaInfo
+{
+ /// <summary>
+ /// Resolves external audios for videos.
+ /// </summary>
+ public class AudioResolver
+ {
+ private readonly ILocalizationManager _localizationManager;
+ private readonly IMediaEncoder _mediaEncoder;
+ private readonly NamingOptions _namingOptions;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AudioResolver"/> class.
+ /// </summary>
+ /// <param name="localizationManager">The localization manager.</param>
+ /// <param name="mediaEncoder">The media encoder.</param>
+ /// <param name="namingOptions">The naming options.</param>
+ public AudioResolver(
+ ILocalizationManager localizationManager,
+ IMediaEncoder mediaEncoder,
+ NamingOptions namingOptions)
+ {
+ _localizationManager = localizationManager;
+ _mediaEncoder = mediaEncoder;
+ _namingOptions = namingOptions;
+ }
+
+ /// <summary>
+ /// Returns the audio streams found in the external audio files for the given video.
+ /// </summary>
+ /// <param name="video">The video to get the external audio streams from.</param>
+ /// <param name="startIndex">The stream index to start adding audio streams at.</param>
+ /// <param name="directoryService">The directory service to search for files.</param>
+ /// <param name="clearCache">True if the directory service cache should be cleared before searching.</param>
+ /// <param name="cancellationToken">The cancellation token to cancel operation.</param>
+ /// <returns>A list of external audio streams.</returns>
+ public async IAsyncEnumerable<MediaStream> GetExternalAudioStreams(
+ Video video,
+ int startIndex,
+ IDirectoryService directoryService,
+ bool clearCache,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (!video.IsFileProtocol)
+ {
+ yield break;
+ }
+
+ IEnumerable<string> paths = GetExternalAudioFiles(video, directoryService, clearCache);
+ foreach (string path in paths)
+ {
+ string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
+ Model.MediaInfo.MediaInfo mediaInfo = await GetMediaInfo(path, cancellationToken).ConfigureAwait(false);
+
+ foreach (MediaStream mediaStream in mediaInfo.MediaStreams)
+ {
+ mediaStream.Index = startIndex++;
+ mediaStream.Type = MediaStreamType.Audio;
+ mediaStream.IsExternal = true;
+ mediaStream.Path = path;
+ mediaStream.IsDefault = false;
+ mediaStream.Title = null;
+
+ if (string.IsNullOrEmpty(mediaStream.Language))
+ {
+ // Try to translate to three character code
+ // Be flexible and check against both the full and three character versions
+ var language = StringExtensions.RightPart(fileNameWithoutExtension, '.').ToString();
+
+ if (language != fileNameWithoutExtension)
+ {
+ var culture = _localizationManager.FindLanguageInfo(language);
+
+ language = culture == null ? language : culture.ThreeLetterISOLanguageName;
+ mediaStream.Language = language;
+ }
+ }
+
+ yield return mediaStream;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the external audio file paths for the given video.
+ /// </summary>
+ /// <param name="video">The video to get the external audio file paths from.</param>
+ /// <param name="directoryService">The directory service to search for files.</param>
+ /// <param name="clearCache">True if the directory service cache should be cleared before searching.</param>
+ /// <returns>A list of external audio file paths.</returns>
+ public IEnumerable<string> GetExternalAudioFiles(
+ Video video,
+ IDirectoryService directoryService,
+ bool clearCache)
+ {
+ if (!video.IsFileProtocol)
+ {
+ yield break;
+ }
+
+ // Check if video folder exists
+ string folder = video.ContainingFolderPath;
+ if (!Directory.Exists(folder))
+ {
+ yield break;
+ }
+
+ string videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
+
+ var files = directoryService.GetFilePaths(folder, clearCache, true);
+ for (int i = 0; i < files.Count; i++)
+ {
+ string file = files[i];
+ if (string.Equals(video.Path, file, StringComparison.OrdinalIgnoreCase)
+ || !AudioFileParser.IsAudioFile(file, _namingOptions)
+ || Path.GetExtension(file.AsSpan()).Equals(".strm", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
+ // The audio filename must either be equal to the video filename or start with the video filename followed by a dot
+ if (videoFileNameWithoutExtension.Equals(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)
+ || (fileNameWithoutExtension.Length > videoFileNameWithoutExtension.Length
+ && fileNameWithoutExtension[videoFileNameWithoutExtension.Length] == '.'
+ && fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)))
+ {
+ yield return file;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the media info of the given audio file.
+ /// </summary>
+ /// <param name="path">The path to the audio file.</param>
+ /// <param name="cancellationToken">The cancellation token to cancel operation.</param>
+ /// <returns>The media info for the given audio file.</returns>
+ private Task<Model.MediaInfo.MediaInfo> GetMediaInfo(string path, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ return _mediaEncoder.GetMediaInfo(
+ new MediaInfoRequest
+ {
+ MediaType = DlnaProfileType.Audio,
+ MediaSource = new MediaSourceInfo
+ {
+ Path = path,
+ Protocol = MediaProtocol.File
+ }
+ },
+ cancellationToken);
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index 887a7f80c..19a435196 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Naming.Common;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -39,6 +40,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
private readonly ILogger<FFProbeProvider> _logger;
private readonly SubtitleResolver _subtitleResolver;
+ private readonly AudioResolver _audioResolver;
private readonly FFProbeVideoInfo _videoProber;
private readonly FFProbeAudioInfo _audioProber;
@@ -55,10 +57,11 @@ namespace MediaBrowser.Providers.MediaInfo
IServerConfigurationManager config,
ISubtitleManager subtitleManager,
IChapterManager chapterManager,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ NamingOptions namingOptions)
{
_logger = logger;
-
+ _audioResolver = new AudioResolver(localization, mediaEncoder, namingOptions);
_subtitleResolver = new SubtitleResolver(BaseItem.LocalizationManager);
_videoProber = new FFProbeVideoInfo(
_logger,
@@ -71,7 +74,8 @@ namespace MediaBrowser.Providers.MediaInfo
config,
subtitleManager,
chapterManager,
- libraryManager);
+ libraryManager,
+ _audioResolver);
_audioProber = new FFProbeAudioInfo(mediaSourceManager, mediaEncoder, itemRepo, libraryManager);
}
@@ -92,7 +96,7 @@ namespace MediaBrowser.Providers.MediaInfo
var file = directoryService.GetFile(path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)
{
- _logger.LogDebug("Refreshing {0} due to date modified timestamp change.", path);
+ _logger.LogDebug("Refreshing {ItemPath} due to date modified timestamp change.", path);
return true;
}
}
@@ -102,7 +106,15 @@ namespace MediaBrowser.Providers.MediaInfo
&& !video.SubtitleFiles.SequenceEqual(
_subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
{
- _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
+ _logger.LogDebug("Refreshing {ItemPath} due to external subtitles change.", item.Path);
+ return true;
+ }
+
+ if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder
+ && !video.AudioFiles.SequenceEqual(
+ _audioResolver.GetExternalAudioFiles(video, directoryService, false), StringComparer.Ordinal))
+ {
+ _logger.LogDebug("Refreshing {ItemPath} due to external audio change.", item.Path);
return true;
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 4ab15f60e..77372e063 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -44,6 +44,7 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly ISubtitleManager _subtitleManager;
private readonly IChapterManager _chapterManager;
private readonly ILibraryManager _libraryManager;
+ private readonly AudioResolver _audioResolver;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks;
@@ -59,7 +60,8 @@ namespace MediaBrowser.Providers.MediaInfo
IServerConfigurationManager config,
ISubtitleManager subtitleManager,
IChapterManager chapterManager,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ AudioResolver audioResolver)
{
_logger = logger;
_mediaEncoder = mediaEncoder;
@@ -71,6 +73,7 @@ namespace MediaBrowser.Providers.MediaInfo
_subtitleManager = subtitleManager;
_chapterManager = chapterManager;
_libraryManager = libraryManager;
+ _audioResolver = audioResolver;
_mediaSourceManager = mediaSourceManager;
}
@@ -214,6 +217,8 @@ namespace MediaBrowser.Providers.MediaInfo
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
+ await AddExternalAudioAsync(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
+
var libraryOptions = _libraryManager.GetLibraryOptions(video);
if (mediaInfo != null)
@@ -575,6 +580,31 @@ namespace MediaBrowser.Providers.MediaInfo
}
/// <summary>
+ /// Adds the external audio.
+ /// </summary>
+ /// <param name="video">The video.</param>
+ /// <param name="currentStreams">The current streams.</param>
+ /// <param name="options">The refreshOptions.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ private async Task AddExternalAudioAsync(
+ Video video,
+ List<MediaStream> currentStreams,
+ MetadataRefreshOptions options,
+ CancellationToken cancellationToken)
+ {
+ var startIndex = currentStreams.Count == 0 ? 0 : currentStreams.Max(i => i.Index) + 1;
+ var externalAudioStreams = _audioResolver.GetExternalAudioStreams(video, startIndex, options.DirectoryService, false, cancellationToken);
+
+ await foreach (MediaStream externalAudioStream in externalAudioStreams)
+ {
+ currentStreams.Add(externalAudioStream);
+ }
+
+ // Select all external audio file paths
+ video.AudioFiles = currentStreams.Where(i => i.Type == MediaStreamType.Audio && i.IsExternal).Select(i => i.Path).Distinct().ToArray();
+ }
+
+ /// <summary>
/// Creates dummy chapters.
/// </summary>
/// <param name="video">The video.</param>
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
index 1eacbf1e1..cce71b067 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
@@ -66,7 +67,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var options = GetOptions();
- var types = new[] { "Episode", "Movie" };
+ var types = new[] { BaseItemKind.Episode, BaseItemKind.Movie };
var dict = new Dictionary<Guid, BaseItem>();
diff --git a/bump_version b/bump_version
index f615606e2..41d27f5c8 100755
--- a/bump_version
+++ b/bump_version
@@ -52,7 +52,8 @@ echo $old_version
# Set the build.yaml version to the specified new_version
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
-sed -i "s/${old_version_sed}/${new_version}/g" ${build_file}
+new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )"
+sed -i "s/${old_version_sed}/${new_version_sed}/g" ${build_file}
# update nuget package version
for subproject in ${jellyfin_subprojects[@]}; do
@@ -64,26 +65,29 @@ for subproject in ${jellyfin_subprojects[@]}; do
| sed -E 's/<VersionPrefix>([0-9\.]+[-a-z0-9]*)<\/VersionPrefix>/\1/'
)"
echo old nuget version: $old_version
+ new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )"
# Set the nuget version to the specified new_version
- sed -i "s|${old_version}|${new_version}|g" ${subproject}
+ sed -i "s|${old_version}|${new_version_sed}|g" ${subproject}
done
if [[ ${new_version} == *"-"* ]]; then
- new_version_deb="$( sed 's/-/~/g' <<<"${new_version}" )"
+ new_version_pkg="$( sed 's/-/~/g' <<<"${new_version}" )"
+ new_version_deb_sup=""
else
- new_version_deb="${new_version}-1"
+ new_version_pkg="${new_version}"
+ new_version_deb_sup="-1"
fi
# Update the metapackage equivs file
debian_equivs_file="debian/metapackage/jellyfin"
-sed -i "s/${old_version_sed}/${new_version}/g" ${debian_equivs_file}
+sed -i "s/${old_version_sed}/${new_version_pkg}/g" ${debian_equivs_file}
# Write out a temporary Debian changelog with our new stuff appended and some templated formatting
debian_changelog_file="debian/changelog"
debian_changelog_temp="$( mktemp )"
# Create new temp file with our changelog
-echo -e "jellyfin-server (${new_version_deb}) unstable; urgency=medium
+echo -e "jellyfin-server (${new_version_pkg}${new_version_deb_sup}) unstable; urgency=medium
* New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v${new_version}
@@ -104,7 +108,7 @@ pushd ${fedora_spec_temp_dir}
# Split out the stuff before and after changelog
csplit jellyfin.spec "/^%changelog/" # produces xx00 xx01
# Update the version in xx00
-sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00
+sed -i "s/${old_version_sed}/${new_version_pkg}/g" xx00
# Remove the header from xx01
sed -i '/^%changelog/d' xx01
# Create new temp file with our changelog
@@ -121,5 +125,5 @@ mv ${fedora_spec_temp} ${fedora_spec_file}
rm -rf ${fedora_spec_temp_dir}
# Stage the changed files for commit
-git add ${shared_version_file} ${build_file} ${debian_equivs_file} ${debian_changelog_file} ${fedora_spec_file}
-git status
+git add .
+git status -v
diff --git a/debian/jellyfin.service b/debian/jellyfin.service
index e215a8536..071f949dd 100644
--- a/debian/jellyfin.service
+++ b/debian/jellyfin.service
@@ -13,7 +13,20 @@ TimeoutSec = 15
NoNewPrivileges=true
SystemCallArchitectures=native
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
-ProtectKernelModules=True
+RestrictNamespaces=true
+RestrictRealtime=true
+RestrictSUIDSGID=true
+ProtectClock=true
+ProtectControlGroups=true
+ProtectHostname=true
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+LockPersonality=true
+PrivateTmp=true
+PrivateDevices=false
+PrivateUsers=true
+RemoveIPC=true
SystemCallFilter=~@clock
SystemCallFilter=~@aio
SystemCallFilter=~@chown
diff --git a/fedora/Makefile b/fedora/Makefile
index 97904ddd3..6b09458b5 100644
--- a/fedora/Makefile
+++ b/fedora/Makefile
@@ -1,26 +1,41 @@
VERSION := $(shell sed -ne '/^Version:/s/.* *//p' fedora/jellyfin.spec)
+outdir ?= fedora/
+TARGET ?= fedora-35-x86_64
srpm:
- cd fedora/; \
- SOURCE_DIR=.. \
- WORKDIR="$${PWD}"; \
- tar \
- --transform "s,^\.,jellyfin-server-$(VERSION)," \
- --exclude='.git*' \
- --exclude='**/.git' \
- --exclude='**/.hg' \
- --exclude='**/.vs' \
- --exclude='**/.vscode' \
- --exclude='deployment' \
- --exclude='**/bin' \
- --exclude='**/obj' \
- --exclude='**/.nuget' \
- --exclude='*.deb' \
- --exclude='*.rpm' \
- --exclude='jellyfin-server-$(VERSION).tar.gz' \
- -czf "jellyfin-server-$(VERSION).tar.gz" \
- -C $${SOURCE_DIR} ./
- cd fedora/; \
- rpmbuild -bs jellyfin.spec \
- --define "_sourcedir $$PWD/" \
+ pushd fedora/; \
+ if [ "$$(id -u)" = "0" ]; then \
+ dnf -y install git; \
+ fi; \
+ version=$$(git describe --tags | sed -e 's/^v//' \
+ -e 's/-[0-9]*-g.*$$//' \
+ -e 's/-/~/'); \
+ SOURCE_DIR=.. \
+ WORKDIR="$${PWD}"; \
+ tar \
+ --transform "s,^\.,jellyfin-server-$$version," \
+ --exclude='.git*' \
+ --exclude='**/.git' \
+ --exclude='**/.hg' \
+ --exclude='**/.vs' \
+ --exclude='**/.vscode' \
+ --exclude=deployment \
+ --exclude='**/bin' \
+ --exclude='**/obj' \
+ --exclude='**/.nuget' \
+ --exclude='*.deb' \
+ --exclude='*.rpm' \
+ --exclude=jellyfin-server-$$version.tar.gz \
+ -czf "jellyfin-server-$$version.tar.gz" \
+ -C $${SOURCE_DIR} ./; \
+ popd; \
+ ./bump_version $$version
+ cd fedora/; \
+ rpmbuild -bs jellyfin.spec \
+ --define "_sourcedir $$PWD/" \
--define "_srcrpmdir $(outdir)"
+
+rpms: fedora/jellyfin-$(shell git describe --tags | sed -e 's/^v//' -e 's/-[0-9]*-g.*$$//' -e 's/-/~/')-1$(shell rpm --eval %dist).src.rpm
+ mock --addrepo=https://download.copr.fedorainfracloud.org/results/@dotnet-sig/dotnet-preview/$(TARGET)/ \
+ --enable-network \
+ -r $(TARGET) $<
diff --git a/fedora/jellyfin-server-lowports.conf b/fedora/jellyfin-server-lowports.conf
new file mode 100644
index 000000000..eeb48a4e4
--- /dev/null
+++ b/fedora/jellyfin-server-lowports.conf
@@ -0,0 +1,4 @@
+# This allows Jellyfin to bind to low ports such as 80 and/or 443
+
+[Service]
+AmbientCapabilities=CAP_NET_BIND_SERVICE \ No newline at end of file
diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec
index 47dee7c13..a4584364e 100644
--- a/fedora/jellyfin.spec
+++ b/fedora/jellyfin.spec
@@ -12,7 +12,7 @@ Release: 1%{?dist}
Summary: The Free Software Media System
License: GPLv3
URL: https://jellyfin.org
-# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%{version}.tar.gz`
+# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%%{version}.tar.gz`
Source0: jellyfin-server-%{version}.tar.gz
Source11: jellyfin.service
Source12: jellyfin.env
@@ -20,6 +20,7 @@ Source13: jellyfin.sudoers
Source14: restart.sh
Source15: jellyfin.override.conf
Source16: jellyfin-firewalld.xml
+Source17: jellyfin-server-lowports.conf
%{?systemd_requires}
BuildRequires: systemd
@@ -45,6 +46,16 @@ Requires: libcurl, fontconfig, freetype, openssl, glibc, libicu, at, sudo
%description server
The Jellyfin media server backend.
+%package server-lowports
+# RPMfusion free
+Summary: The Free Software Media System Server backend. Low-port binding.
+Requires: jellyfin-server
+
+%description server-lowports
+The Jellyfin media server backend low port binding package. This package
+enables binding to ports < 1024. You would install this if you want
+the Jellyfin server to bind to ports 80 and/or 443 for example.
+
%prep
%autosetup -n jellyfin-server-%{version} -b 0
@@ -57,6 +68,7 @@ dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin
"-p:DebugSymbols=false;DebugType=none" Jellyfin.Server
%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/jellyfin/LICENSE
%{__install} -D -m 0644 %{SOURCE15} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf
+%{__install} -D -m 0644 %{SOURCE17} %{buildroot}%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf
%{__install} -D -m 0644 Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/jellyfin/logging.json
%{__mkdir} -p %{buildroot}%{_bindir}
tee %{buildroot}%{_bindir}/jellyfin << EOF
@@ -95,6 +107,9 @@ EOF
%attr(750,jellyfin,jellyfin) %dir %{_var}/cache/jellyfin
%{_datadir}/licenses/jellyfin/LICENSE
+%files server-lowports
+%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf
+
%pre server
getent group jellyfin >/dev/null || groupadd -r jellyfin
getent passwd jellyfin >/dev/null || \
@@ -137,6 +152,9 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
+* Mon Nov 29 2021 Brian J. Murrell <brian@interlinx.bc.ca>
+- Add jellyfin-server-lowports.service drop-in in a server-lowports
+ subpackage to allow binding to low ports
* Fri Dec 04 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
index 4ba7e1d2f..c4640bd22 100644
--- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
+++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
@@ -55,35 +55,5 @@ namespace Jellyfin.Api.Tests.Helpers
return data;
}
-
- [Fact]
- public static void GetItemTypeStrings_Empty_Empty()
- {
- Assert.Empty(RequestHelpers.GetItemTypeStrings(Array.Empty<BaseItemKind>()));
- }
-
- [Fact]
- public static void GetItemTypeStrings_Valid_Success()
- {
- BaseItemKind[] input =
- {
- BaseItemKind.AggregateFolder,
- BaseItemKind.Audio,
- BaseItemKind.BasePluginFolder,
- BaseItemKind.CollectionFolder
- };
-
- string[] expected =
- {
- "AggregateFolder",
- "Audio",
- "BasePluginFolder",
- "CollectionFolder"
- };
-
- var res = RequestHelpers.GetItemTypeStrings(input);
-
- Assert.Equal(expected, res);
- }
}
}
diff --git a/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs b/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
index 55050cc95..cbab455f0 100644
--- a/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
+++ b/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
@@ -1,8 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using MediaBrowser.Model.Net;
using Xunit;
@@ -129,7 +124,7 @@ namespace Jellyfin.Model.Tests.Net
[InlineData("font/woff2", ".woff2")]
[InlineData("image/bmp", ".bmp")]
[InlineData("image/gif", ".gif")]
- [InlineData("image/jpg", ".jpg")]
+ [InlineData("image/jpeg", ".jpg")]
[InlineData("image/png", ".png")]
[InlineData("image/svg+xml", ".svg")]
[InlineData("image/tiff", ".tif")]
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
index c5cc056f5..54a63a5f2 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
@@ -11,6 +11,18 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[InlineData("Superman: Red Son - tt10985510", "imdbid", "tt10985510")]
[InlineData("Superman: Red Son", "imdbid", null)]
[InlineData("Superman: Red Son", "something", null)]
+ [InlineData("Superman: Red Son [imdbid1=tt11111111][imdbid=tt10985510]", "imdbid", "tt10985510")]
+ [InlineData("Superman: Red Son [tmdbid=618355][imdbid=tt10985510]", "imdbid", "tt10985510")]
+ [InlineData("Superman: Red Son [tmdbid=618355][imdbid=tt10985510]", "tmdbid", "618355")]
+ [InlineData("[tmdbid=618355]", "tmdbid", "618355")]
+ [InlineData("tmdbid=111111][tmdbid=618355]", "tmdbid", "618355")]
+ [InlineData("[tmdbid=618355]tmdbid=111111]", "tmdbid", "618355")]
+ [InlineData("tmdbid=618355]", "tmdbid", null)]
+ [InlineData("[tmdbid=618355", "tmdbid", null)]
+ [InlineData("tmdbid=618355", "tmdbid", null)]
+ [InlineData("tmdbid=", "tmdbid", null)]
+ [InlineData("tmdbid", "tmdbid", null)]
+ [InlineData("[tmdbid=][imdbid=tt10985510]", "tmdbid", null)]
public void GetAttributeValue_ValidArgs_Correct(string input, string attribute, string? expectedResult)
{
Assert.Equal(expectedResult, PathExtensions.GetAttributeValue(input, attribute));