diff options
Diffstat (limited to 'Emby.Server.Implementations')
81 files changed, 785 insertions, 753 deletions
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index d385356345..5ba4749a60 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -301,7 +301,7 @@ namespace Emby.Server.Implementations.AppBase { return _configurations.GetOrAdd( key, - (k, configurationManager) => + static (k, configurationManager) => { var file = configurationManager.GetConfigurationFile(k); diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 3a916e5c01..f923e59efb 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using MediaBrowser.Model.Serialization; namespace Emby.Server.Implementations.AppBase diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 903c311334..8892f7f40f 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/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs index 9e1d550ebc..6a3b250d25 100644 --- a/Emby.Server.Implementations/Archiving/ZipClient.cs +++ b/Emby.Server.Implementations/Archiving/ZipClient.cs @@ -1,11 +1,8 @@ using System.IO; using MediaBrowser.Model.IO; -using SharpCompress.Archives.SevenZip; -using SharpCompress.Archives.Tar; using SharpCompress.Common; using SharpCompress.Readers; using SharpCompress.Readers.GZip; -using SharpCompress.Readers.Zip; namespace Emby.Server.Implementations.Archiving { @@ -14,55 +11,6 @@ namespace Emby.Server.Implementations.Archiving /// </summary> public class ZipClient : IZipClient { - /// <summary> - /// Extracts all. - /// </summary> - /// <param name="sourceFile">The source file.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAll(string sourceFile, string targetPath, bool overwriteExistingFiles) - { - using var fileStream = File.OpenRead(sourceFile); - ExtractAll(fileStream, targetPath, overwriteExistingFiles); - } - - /// <summary> - /// Extracts all. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles) - { - using var reader = ReaderFactory.Open(source); - var options = new ExtractionOptions - { - ExtractFullPath = true - }; - - if (overwriteExistingFiles) - { - options.Overwrite = true; - } - - Directory.CreateDirectory(targetPath); - reader.WriteAllToDirectory(targetPath, options); - } - - /// <inheritdoc /> - public void ExtractAllFromZip(Stream source, string targetPath, bool overwriteExistingFiles) - { - using var reader = ZipReader.Open(source); - var options = new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = overwriteExistingFiles - }; - - Directory.CreateDirectory(targetPath); - reader.WriteAllToDirectory(targetPath, options); - } - /// <inheritdoc /> public void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles) { @@ -94,69 +42,5 @@ namespace Emby.Server.Implementations.Archiving reader.WriteEntryToFile(Path.Combine(targetPath, filename)); } } - - /// <summary> - /// Extracts all from7z. - /// </summary> - /// <param name="sourceFile">The source file.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAllFrom7z(string sourceFile, string targetPath, bool overwriteExistingFiles) - { - using var fileStream = File.OpenRead(sourceFile); - ExtractAllFrom7z(fileStream, targetPath, overwriteExistingFiles); - } - - /// <summary> - /// Extracts all from7z. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAllFrom7z(Stream source, string targetPath, bool overwriteExistingFiles) - { - using var archive = SevenZipArchive.Open(source); - using var reader = archive.ExtractAllEntries(); - var options = new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = overwriteExistingFiles - }; - - Directory.CreateDirectory(targetPath); - reader.WriteAllToDirectory(targetPath, options); - } - - /// <summary> - /// Extracts all from tar. - /// </summary> - /// <param name="sourceFile">The source file.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAllFromTar(string sourceFile, string targetPath, bool overwriteExistingFiles) - { - using var fileStream = File.OpenRead(sourceFile); - ExtractAllFromTar(fileStream, targetPath, overwriteExistingFiles); - } - - /// <summary> - /// Extracts all from tar. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="targetPath">The target path.</param> - /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> - public void ExtractAllFromTar(Stream source, string targetPath, bool overwriteExistingFiles) - { - using var archive = TarArchive.Open(source); - using var reader = archive.ExtractAllEntries(); - var options = new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = overwriteExistingFiles - }; - - Directory.CreateDirectory(targetPath); - reader.WriteAllToDirectory(targetPath, options); - } } } diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index f65eaec1c8..8702691d1d 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -179,7 +180,7 @@ namespace Emby.Server.Implementations.Channels try { return (GetChannelProvider(i) is IHasFolderAttributes hasAttributes - && hasAttributes.Attributes.Contains("Recordings", StringComparer.OrdinalIgnoreCase)) == val; + && hasAttributes.Attributes.Contains("Recordings", StringComparison.OrdinalIgnoreCase)) == val; } catch { @@ -541,7 +542,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(); } @@ -1135,7 +1136,7 @@ namespace Emby.Server.Implementations.Channels if (!info.IsLiveStream) { - if (item.Tags.Contains("livestream", StringComparer.OrdinalIgnoreCase)) + if (item.Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase)) { item.Tags = item.Tags.Except(new[] { "livestream" }, StringComparer.OrdinalIgnoreCase).ToArray(); _logger.LogDebug("Forcing update due to Tags {0}", item.Name); @@ -1144,7 +1145,7 @@ namespace Emby.Server.Implementations.Channels } else { - if (!item.Tags.Contains("livestream", StringComparer.OrdinalIgnoreCase)) + if (!item.Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase)) { item.Tags = item.Tags.Concat(new[] { "livestream" }).ToArray(); _logger.LogDebug("Forcing update due to Tags {0}", item.Name); diff --git a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs index 2391eed428..b358ba4d55 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/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 73c31f49d1..5030cbacb8 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; +using Jellyfin.Extensions; using Microsoft.Extensions.Logging; using SQLitePCL.pretty; @@ -194,7 +194,7 @@ namespace Emby.Server.Implementations.Data protected void AddColumn(IDatabaseConnection connection, string table, string columnName, string type, List<string> existingColumnNames) { - if (existingColumnNames.Contains(columnName, StringComparer.OrdinalIgnoreCase)) + if (existingColumnNames.Contains(columnName, StringComparison.OrdinalIgnoreCase)) { return; } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 13f1df7c86..beae7e2431 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Data private readonly ItemFields[] _allItemFields = Enum.GetValues<ItemFields>(); - private static readonly string[] _retriveItemColumns = + private static readonly string[] _retrieveItemColumns = { "type", "data", @@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Data "OwnerId" }; - private static readonly string _retriveItemColumnsSelectQuery = $"select {string.Join(',', _retriveItemColumns)} from TypedBaseItems where guid = @guid"; + private static readonly string _retrieveItemColumnsSelectQuery = $"select {string.Join(',', _retrieveItemColumns)} from TypedBaseItems where guid = @guid"; private static readonly string[] _mediaStreamSaveColumns = { @@ -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 = @@ -285,6 +284,43 @@ namespace Emby.Server.Implementations.Data private readonly Dictionary<string, string> _types = GetTypeMapDictionary(); + private static readonly Dictionary<BaseItemKind, string> _baseItemKindNames = new() + { + { BaseItemKind.AggregateFolder, typeof(AggregateFolder).FullName }, + { BaseItemKind.Audio, typeof(Audio).FullName }, + { BaseItemKind.AudioBook, typeof(AudioBook).FullName }, + { BaseItemKind.BasePluginFolder, typeof(BasePluginFolder).FullName }, + { BaseItemKind.Book, typeof(Book).FullName }, + { BaseItemKind.BoxSet, typeof(BoxSet).FullName }, + { BaseItemKind.Channel, typeof(Channel).FullName }, + { BaseItemKind.CollectionFolder, typeof(CollectionFolder).FullName }, + { BaseItemKind.Episode, typeof(Episode).FullName }, + { BaseItemKind.Folder, typeof(Folder).FullName }, + { BaseItemKind.Genre, typeof(Genre).FullName }, + { BaseItemKind.Movie, typeof(Movie).FullName }, + { BaseItemKind.LiveTvChannel, typeof(LiveTvChannel).FullName }, + { BaseItemKind.LiveTvProgram, typeof(LiveTvProgram).FullName }, + { BaseItemKind.MusicAlbum, typeof(MusicAlbum).FullName }, + { BaseItemKind.MusicArtist, typeof(MusicArtist).FullName }, + { BaseItemKind.MusicGenre, typeof(MusicGenre).FullName }, + { BaseItemKind.MusicVideo, typeof(MusicVideo).FullName }, + { BaseItemKind.Person, typeof(Person).FullName }, + { BaseItemKind.Photo, typeof(Photo).FullName }, + { BaseItemKind.PhotoAlbum, typeof(PhotoAlbum).FullName }, + { BaseItemKind.Playlist, typeof(Playlist).FullName }, + { BaseItemKind.PlaylistsFolder, typeof(PlaylistsFolder).FullName }, + { BaseItemKind.Season, typeof(Season).FullName }, + { BaseItemKind.Series, typeof(Series).FullName }, + { BaseItemKind.Studio, typeof(Studio).FullName }, + { BaseItemKind.Trailer, typeof(Trailer).FullName }, + { BaseItemKind.TvChannel, typeof(LiveTvChannel).FullName }, + { BaseItemKind.TvProgram, typeof(LiveTvProgram).FullName }, + { BaseItemKind.UserRootFolder, typeof(UserRootFolder).FullName }, + { BaseItemKind.UserView, typeof(UserView).FullName }, + { BaseItemKind.Video, typeof(Video).FullName }, + { BaseItemKind.Year, typeof(Year).FullName } + }; + static SqliteItemRepository() { var queryPrefixText = new StringBuilder(); @@ -1320,7 +1356,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - using (var statement = PrepareStatement(connection, _retriveItemColumnsSelectQuery)) + using (var statement = PrepareStatement(connection, _retrieveItemColumnsSelectQuery)) { statement.TryBind("@guid", id); @@ -2212,7 +2248,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 +2263,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 +2278,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 +2298,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 +2308,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 +2328,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; } @@ -2630,7 +2666,7 @@ namespace Emby.Server.Implementations.Data query.Limit = query.Limit.Value + 4; } - var columns = _retriveItemColumns.ToList(); + var columns = _retrieveItemColumns.ToList(); SetFinalColumnsToSelect(query, columns); var commandTextBuilder = new StringBuilder("select ", 1024) .AppendJoin(',', columns) @@ -2821,7 +2857,7 @@ namespace Emby.Server.Implementations.Data query.Limit = query.Limit.Value + 4; } - var columns = _retriveItemColumns.ToList(); + var columns = _retrieveItemColumns.ToList(); SetFinalColumnsToSelect(query, columns); var commandTextBuilder = new StringBuilder("select ", 512) .AppendJoin(',', columns) @@ -3487,8 +3523,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,31 +3599,81 @@ 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]); + if (_baseItemKindNames.TryGetValue(excludeTypes[0], out var excludeTypeName)) + { + whereClauses.Add("type<>@type"); + statement?.TryBind("@type", excludeTypeName); + } + else + { + Logger.LogWarning("Undefined BaseItemKind to Type mapping: {BaseItemKind}", excludeTypes[0]); + } } else if (excludeTypes.Length > 1) { - var inClause = string.Join(',', excludeTypes.Select(i => "'" + i + "'")); - whereClauses.Add($"type not in ({inClause})"); + var whereBuilder = new StringBuilder("type not in ("); + foreach (var excludeType in excludeTypes) + { + if (_baseItemKindNames.TryGetValue(excludeType, out var baseItemKindName)) + { + whereBuilder + .Append('\'') + .Append(baseItemKindName) + .Append("',"); + } + else + { + Logger.LogWarning("Undefined BaseItemKind to Type mapping: {BaseItemKind}", excludeType); + } + } + + // Remove trailing comma. + whereBuilder.Length--; + whereBuilder.Append(')'); + whereClauses.Add(whereBuilder.ToString()); } } else if (includeTypes.Length == 1) { - whereClauses.Add("type=@type"); - statement?.TryBind("@type", includeTypes[0]); + if (_baseItemKindNames.TryGetValue(includeTypes[0], out var includeTypeName)) + { + whereClauses.Add("type=@type"); + statement?.TryBind("@type", includeTypeName); + } + else + { + Logger.LogWarning("Undefined BaseItemKind to Type mapping: {BaseItemKind}", includeTypes[0]); + } } else if (includeTypes.Length > 1) { - var inClause = string.Join(',', includeTypes.Select(i => "'" + i + "'")); - whereClauses.Add($"type in ({inClause})"); + var whereBuilder = new StringBuilder("type in ("); + foreach (var includeType in includeTypes) + { + if (_baseItemKindNames.TryGetValue(includeType, out var baseItemKindName)) + { + whereBuilder + .Append('\'') + .Append(baseItemKindName) + .Append("',"); + } + else + { + Logger.LogWarning("Undefined BaseItemKind to Type mapping: {BaseItemKind}", includeType); + } + } + + // Remove trailing comma. + whereBuilder.Length--; + whereBuilder.Append(')'); + whereClauses.Add(whereBuilder.ToString()); } if (query.ChannelIds.Count == 1) @@ -3911,7 +3997,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 +4847,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 +4875,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 +4922,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 +4976,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) @@ -5351,7 +5421,7 @@ AND Type = @InternalPersonType)"); stringBuilder.Clear(); } - List<string> columns = _retriveItemColumns.ToList(); + List<string> columns = _retrieveItemColumns.ToList(); // Unfortunately we need to add it to columns to ensure the order of the columns in the select if (!string.IsNullOrEmpty(itemCountColumns)) { @@ -5569,7 +5639,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 b91ff64087..a6406827cc 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -7,9 +7,9 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Common; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; @@ -294,7 +294,7 @@ namespace Emby.Server.Implementations.Dto path = path.TrimStart('.'); } - if (!string.IsNullOrEmpty(path) && containers.Contains(path, StringComparer.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(path) && containers.Contains(path, StringComparison.OrdinalIgnoreCase)) { fileExtensionContainer = path; } @@ -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 }); @@ -1404,44 +1404,27 @@ namespace Emby.Server.Implementations.Dto return null; } - ImageDimensions size; - - var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio(); - - if (defaultAspectRatio > 0) - { - return defaultAspectRatio; - } - if (!imageInfo.IsLocalFile) { - return null; + return item.GetDefaultPrimaryImageAspectRatio(); } try { - size = _imageProcessor.GetImageDimensions(item, imageInfo); - - if (size.Width <= 0 || size.Height <= 0) + var size = _imageProcessor.GetImageDimensions(item, imageInfo); + var width = size.Width; + var height = size.Height; + if (width > 0 && height > 0) { - return null; + return (double)width / height; } } catch (Exception ex) { - _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path); - return null; - } - - var width = size.Width; - var height = size.Height; - - if (width <= 0 || height <= 0) - { - return null; + _logger.LogError(ex, "Failed to determine primary image aspect ratio for {ImagePath}", imageInfo.Path); } - return (double)width / height; + return item.GetDefaultPrimaryImageAspectRatio(); } } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 95acd216d9..329a84acb9 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -29,7 +29,7 @@ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.1" /> <PackageReference Include="Mono.Nat" Version="3.0.2" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.2" /> <PackageReference Include="sharpcompress" Version="0.30.1" /> diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index d325fa14fc..06e57ad127 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -13,7 +13,6 @@ using Jellyfin.Networking.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; -using MediaBrowser.Model.Dlna; using Microsoft.Extensions.Logging; using Mono.Nat; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index e7103ec958..1d04f3da37 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Jellyfin.Data.Enums; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 5f25f69801..0eca2a6080 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.HttpServer } WebSocketMessage<object>? stub; - long bytesConsumed = 0; + long bytesConsumed; try { stub = DeserializeWebSocketMessage(buffer, out bytesConsumed); diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index 0229fbae79..7e12ebb087 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 900b3fd9c6..5756806535 100644 --- a/Emby.Server.Implementations/Images/DynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/DynamicImageProvider.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -34,14 +36,14 @@ namespace Emby.Server.Implementations.Images var view = (UserView)item; var isUsingCollectionStrip = IsUsingCollectionStrip(view); - var recursive = isUsingCollectionStrip && !new[] { CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); + var recursive = isUsingCollectionStrip && !new[] { CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparison.OrdinalIgnoreCase); var result = view.GetItemList(new InternalItemsQuery { 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 1f5090f7f5..968bf5fa33 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -8,8 +8,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -43,7 +41,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 baf1c90517..31f053f065 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/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 29758a0788..e558fbe27b 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -54,20 +54,10 @@ namespace Emby.Server.Implementations.Library { if (parent != null) { - // Ignore trailer folders but allow it at the collection level - if (string.Equals(filename, BaseItem.TrailersFolderName, StringComparison.OrdinalIgnoreCase) - && !(parent is AggregateFolder) - && !(parent is UserRootFolder)) - { - return true; - } - - if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) + // Ignore extras folders but allow it at the collection level + if (_namingOptions.AllExtrasTypesFolderNames.ContainsKey(filename) + && parent is not AggregateFolder + && parent is not UserRootFolder) { return true; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 778b6225e1..270264dba8 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -11,11 +11,9 @@ using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Emby.Naming.Audio; using Emby.Naming.Common; using Emby.Naming.TV; using Emby.Naming.Video; -using Emby.Server.Implementations.Library.Resolvers; using Emby.Server.Implementations.Library.Validators; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks; @@ -533,8 +531,8 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null) - => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent); + public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, IDirectoryService directoryService = null) + => ResolvePath(fileInfo, directoryService ?? new DirectoryService(_fileSystem), null, parent); private BaseItem ResolvePath( FileSystemMetadata fileInfo, @@ -654,7 +652,7 @@ namespace Emby.Server.Implementations.Library return !args.ContainsFileSystemEntryByName(".ignore"); } - public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType) + public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType = null) { return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers); } @@ -677,7 +675,7 @@ namespace Emby.Server.Implementations.Library { var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService); - if (result != null && result.Items.Count > 0) + if (result?.Items.Count > 0) { var items = new List<BaseItem>(); items.AddRange(result.Items); @@ -965,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>() @@ -2685,89 +2683,105 @@ namespace Emby.Server.Implementations.Library }; } - public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) + public IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) { - var namingOptions = _namingOptions; - - var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory) - .Where(i => string.Equals(i.Name, BaseItem.TrailersFolderName, StringComparison.OrdinalIgnoreCase)) - .SelectMany(i => _fileSystem.GetFiles(i.FullName, namingOptions.VideoFileExtensions, false, false)) - .ToList(); - - var videos = VideoListResolver.Resolve(fileSystemChildren, namingOptions); - - var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files[0].Path, StringComparison.OrdinalIgnoreCase)); - - if (currentVideo != null) + var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions); + if (ownerVideoInfo == null) { - files.AddRange(currentVideo.Extras.Where(i => i.ExtraType == ExtraType.Trailer).Select(i => _fileSystem.GetFileInfo(i.Path))); + yield break; } - var resolvers = new IItemResolver[] + var count = fileSystemChildren.Count; + var files = new List<VideoFileInfo>(); + var nonVideoFiles = new List<FileSystemMetadata>(); + for (var i = 0; i < count; i++) { - new GenericVideoResolver<Trailer>(_namingOptions) - }; + var current = fileSystemChildren[i]; + if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name)) + { + var filesInSubFolder = _fileSystem.GetFiles(current.FullName, _namingOptions.VideoFileExtensions, false, false); + foreach (var file in filesInSubFolder) + { + var videoInfo = VideoResolver.Resolve(file.FullName, file.IsDirectory, _namingOptions); + if (videoInfo == null) + { + nonVideoFiles.Add(file); + continue; + } - return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers) - .OfType<Trailer>() - .Select(video => + files.Add(videoInfo); + } + } + else if (!current.IsDirectory) { - // Try to retrieve it from the db. If we don't find it, use the resolved version - if (GetItemById(video.Id) is Trailer dbItem) + var videoInfo = VideoResolver.Resolve(current.FullName, current.IsDirectory, _namingOptions); + if (videoInfo == null) { - video = dbItem; + nonVideoFiles.Add(current); + continue; } - video.ParentId = Guid.Empty; - video.OwnerId = owner.Id; - video.ExtraType = ExtraType.Trailer; - video.TrailerTypes = new[] { TrailerType.LocalTrailer }; - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path); - } - - public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) - { - var namingOptions = _namingOptions; + files.Add(videoInfo); + } + } - var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory) - .Where(i => BaseItem.AllExtrasTypesFolderNames.ContainsKey(i.Name ?? string.Empty)) - .SelectMany(i => _fileSystem.GetFiles(i.FullName, namingOptions.VideoFileExtensions, false, false)) - .ToList(); + if (files.Count == 0) + { + yield break; + } - var videos = VideoListResolver.Resolve(fileSystemChildren, namingOptions); + var videos = VideoListResolver.Resolve(files, _namingOptions); + // owner video info cannot be null as that implies it has no path + var extras = ExtraResolver.GetExtras(videos, ownerVideoInfo, _namingOptions.VideoFlagDelimiters); + for (var i = 0; i < extras.Count; i++) + { + var currentExtra = extras[i]; + var resolved = ResolvePath(_fileSystem.GetFileInfo(currentExtra.Path), null, directoryService); + if (resolved is not Video video) + { + continue; + } - var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files[0].Path, StringComparison.OrdinalIgnoreCase)); + // Try to retrieve it from the db. If we don't find it, use the resolved version + if (GetItemById(resolved.Id) is Video dbItem) + { + video = dbItem; + } - if (currentVideo != null) - { - files.AddRange(currentVideo.Extras.Where(i => i.ExtraType != ExtraType.Trailer).Select(i => _fileSystem.GetFileInfo(i.Path))); + video.ExtraType = currentExtra.ExtraType; + video.ParentId = Guid.Empty; + video.OwnerId = owner.Id; + yield return video; } - return ResolvePaths(files, directoryService, null, new LibraryOptions(), null) - .OfType<Video>() - .Select(video => + // TODO: theme songs must be handled "manually" (but should we?) since they aren't video files + for (var i = 0; i < nonVideoFiles.Count; i++) + { + var current = nonVideoFiles[i]; + var extraInfo = ExtraResolver.GetExtraInfo(current.FullName, _namingOptions); + if (extraInfo.ExtraType != ExtraType.ThemeSong) { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } + continue; + } - video.ParentId = Guid.Empty; - video.OwnerId = owner.Id; + var resolved = ResolvePath(current, null, directoryService); + if (resolved is not Audio themeSong) + { + continue; + } - SetExtraTypeFromFilename(video); + // Try to retrieve it from the db. If we don't find it, use the resolved version + if (GetItemById(themeSong.Id) is Audio dbItem) + { + themeSong = dbItem; + } - return video; + themeSong.ExtraType = ExtraType.ThemeSong; + themeSong.OwnerId = owner.Id; + themeSong.ParentId = Guid.Empty; - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path); + yield return themeSong; + } } public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem) @@ -2817,15 +2831,6 @@ namespace Emby.Server.Implementations.Library return path; } - private void SetExtraTypeFromFilename(Video item) - { - var resolver = new ExtraResolver(_namingOptions); - - var result = resolver.GetExtraInfo(item.Path); - - item.ExtraType = result.ExtraType; - } - public List<PersonInfo> GetPeople(InternalPeopleQuery query) { return _itemRepository.GetPeople(query); @@ -2932,11 +2937,12 @@ namespace Emby.Server.Implementations.Library var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; + var existingNameCount = 1; // first numbered name will be 2 var virtualFolderPath = Path.Combine(rootFolderPath, name); while (Directory.Exists(virtualFolderPath)) { - name += "1"; - virtualFolderPath = Path.Combine(rootFolderPath, name); + existingNameCount++; + virtualFolderPath = Path.Combine(rootFolderPath, name + " " + existingNameCount); } var mediaPathInfos = options.PathInfos; diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index b3837fedb4..da0c89c13e 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Model.Entities; namespace Emby.Server.Implementations.Library @@ -64,18 +65,18 @@ namespace Emby.Server.Implementations.Library stream = sortedStreams.FirstOrDefault(s => s.IsExternal || s.IsForced || s.IsDefault); // if the audio language is not understood by the user, load their preferred subs, if there are any - if (stream == null && !preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) + if (stream == null && !preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) { - stream = sortedStreams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = sortedStreams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Smart) { // if the audio language is not understood by the user, load their preferred subs, if there are any - if (!preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) + if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) { - stream = streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Always) @@ -136,9 +137,9 @@ namespace Emby.Server.Implementations.Library else if (mode == SubtitlePlaybackMode.Smart) { // Prefer smart logic over embedded metadata - if (!preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) + if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) { - filteredStreams = streams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) + filteredStreams = streams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase)) .ToList(); } } diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index e2f1fb0ade..d332135647 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 d5b855cdf2..6f61dc7135 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/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 27e18be42c..210ed0953a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -4,12 +4,10 @@ using System; using System.Linq; using System.Threading.Tasks; using Emby.Naming.Common; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library.Resolvers.Audio diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index 0ebf0e5302..9222a94797 100644 --- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -49,120 +49,71 @@ namespace Emby.Server.Implementations.Library.Resolvers protected virtual TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName) where TVideoType : Video, new() { - var namingOptions = NamingOptions; + VideoFileInfo videoInfo = null; + VideoType? videoType = null; // If the path is a file check for a matching extensions if (args.IsDirectory) { - TVideoType video = null; - VideoFileInfo videoInfo = null; - // Loop through each child file/folder and see if we find a video foreach (var child in args.FileSystemChildren) { var filename = child.Name; - if (child.IsDirectory) { if (IsDvdDirectory(child.FullName, filename, args.DirectoryService)) { - videoInfo = VideoResolver.ResolveDirectory(args.Path, namingOptions); - - if (videoInfo == null) - { - return null; - } - - video = new TVideoType - { - Path = args.Path, - VideoType = VideoType.Dvd, - ProductionYear = videoInfo.Year - }; - break; + videoType = VideoType.Dvd; } - - if (IsBluRayDirectory(filename)) + else if (IsBluRayDirectory(filename)) { - videoInfo = VideoResolver.ResolveDirectory(args.Path, namingOptions); - - if (videoInfo == null) - { - return null; - } - - video = new TVideoType - { - Path = args.Path, - VideoType = VideoType.BluRay, - ProductionYear = videoInfo.Year - }; - break; + videoType = VideoType.BluRay; } } else if (IsDvdFile(filename)) { - videoInfo = VideoResolver.ResolveDirectory(args.Path, namingOptions); - - if (videoInfo == null) - { - return null; - } - - video = new TVideoType - { - Path = args.Path, - VideoType = VideoType.Dvd, - ProductionYear = videoInfo.Year - }; - break; + videoType = VideoType.Dvd; } - } - if (video != null) - { - video.Name = parseName ? - videoInfo.Name : - Path.GetFileName(args.Path); + if (videoType == null) + { + continue; + } - Set3DFormat(video, videoInfo); + videoInfo = VideoResolver.ResolveDirectory(args.Path, NamingOptions, parseName); + break; } - - return video; } else { - var videoInfo = VideoResolver.Resolve(args.Path, false, namingOptions, false); - - if (videoInfo == null) - { - return null; - } - - if (VideoResolver.IsVideoFile(args.Path, NamingOptions) || videoInfo.IsStub) - { - var path = args.Path; - - var video = new TVideoType - { - Path = path, - IsInMixedFolder = true, - ProductionYear = videoInfo.Year - }; - - SetVideoType(video, videoInfo); + videoInfo = VideoResolver.Resolve(args.Path, false, NamingOptions, parseName); + } - video.Name = parseName ? - videoInfo.Name : - Path.GetFileNameWithoutExtension(args.Path); + if (videoInfo == null || (!videoInfo.IsStub && !VideoResolver.IsVideoFile(args.Path, NamingOptions))) + { + return null; + } - Set3DFormat(video, videoInfo); + var video = new TVideoType + { + Name = videoInfo.Name, + Path = args.Path, + ProductionYear = videoInfo.Year, + ExtraType = videoInfo.ExtraType + }; - return video; - } + if (videoType.HasValue) + { + video.VideoType = videoType.Value; } + else + { + SetVideoType(video, videoInfo); + } + + Set3DFormat(video, videoInfo); - return null; + return video; } protected void SetVideoType(Video video, VideoFileInfo videoInfo) @@ -207,8 +158,8 @@ namespace Emby.Server.Implementations.Library.Resolvers { // use disc-utils, both DVDs and BDs use UDF filesystem using (var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read)) + using (UdfReader udfReader = new UdfReader(videoFileStream)) { - UdfReader udfReader = new UdfReader(videoFileStream); if (udfReader.DirectoryExists("VIDEO_TS")) { video.IsoType = IsoType.Dvd; diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs index e685c87f1a..8f224f547a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; +using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; @@ -32,7 +33,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books var extension = Path.GetExtension(args.Path); - if (extension != null && _validExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) + if (extension != null && _validExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)) { // It's a book return new Book diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index e7abe1e6da..6cc04ea810 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 732be0fe5c..4feaf3fb4c 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -26,7 +26,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver { private readonly IImageProcessor _imageProcessor; - private readonly StackResolver _stackResolver; private string[] _validCollectionTypes = new[] { @@ -46,7 +45,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies : base(namingOptions) { _imageProcessor = imageProcessor; - _stackResolver = new StackResolver(NamingOptions); } /// <summary> @@ -62,7 +60,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies string collectionType, IDirectoryService directoryService) { - var result = ResolveMultipleInternal(parent, files, collectionType, directoryService); + var result = ResolveMultipleInternal(parent, files, collectionType); if (result != null) { @@ -92,16 +90,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return null; } + Video movie = null; var files = args.GetActualFileSystemChildren().ToList(); if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); + movie = FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); + movie = FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); } if (string.IsNullOrEmpty(collectionType)) @@ -118,17 +117,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return null; } - { - return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true); - } + movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true); } if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true); + movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true); } - return null; + // ignore extras + return movie?.ExtraType == null ? movie : null; } // Handle owned items @@ -169,6 +167,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies item = ResolveVideo<Video>(args, false); } + // Ignore extras + if (item?.ExtraType != null) + { + return null; + } + if (item != null) { item.IsInMixedFolder = true; @@ -180,8 +184,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies private MultiItemResolverResult ResolveMultipleInternal( Folder parent, List<FileSystemMetadata> files, - string collectionType, - IDirectoryService directoryService) + string collectionType) { if (IsInvalid(parent, collectionType)) { @@ -190,13 +193,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<MusicVideo>(parent, files, directoryService, true, collectionType, false); + return ResolveVideos<MusicVideo>(parent, files, true, collectionType, false); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) || string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<Video>(parent, files, directoryService, false, collectionType, false); + return ResolveVideos<Video>(parent, files, false, collectionType, false); } if (string.IsNullOrEmpty(collectionType)) @@ -204,7 +207,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies // Owned items should just use the plain video type if (parent == null) { - return ResolveVideos<Video>(parent, files, directoryService, false, collectionType, false); + return ResolveVideos<Video>(parent, files, false, collectionType, false); } if (parent is Series || parent.GetParents().OfType<Series>().Any()) @@ -212,12 +215,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return null; } - return ResolveVideos<Movie>(parent, files, directoryService, false, collectionType, true); + return ResolveVideos<Movie>(parent, files, false, collectionType, true); } if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<Movie>(parent, files, directoryService, true, collectionType, true); + return ResolveVideos<Movie>(parent, files, true, collectionType, true); } return null; @@ -226,21 +229,20 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies private MultiItemResolverResult ResolveVideos<T>( Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, - IDirectoryService directoryService, - bool suppportMultiEditions, + bool supportMultiEditions, string collectionType, bool parseName) where T : Video, new() { var files = new List<FileSystemMetadata>(); - var videos = new List<BaseItem>(); var leftOver = new List<FileSystemMetadata>(); + var hasCollectionType = !string.IsNullOrEmpty(collectionType); // Loop through each child file/folder and see if we find a video foreach (var child in fileSystemEntries) { // This is a hack but currently no better way to resolve a sometimes ambiguous situation - if (string.IsNullOrEmpty(collectionType)) + if (!hasCollectionType) { if (string.Equals(child.Name, "tvshow.nfo", StringComparison.OrdinalIgnoreCase) || string.Equals(child.Name, "season.nfo", StringComparison.OrdinalIgnoreCase)) @@ -259,29 +261,39 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies } } - var resolverResult = VideoListResolver.Resolve(files, NamingOptions, suppportMultiEditions).ToList(); + var videoInfos = files + .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName)) + .Where(f => f != null) + .ToList(); + + var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName); var result = new MultiItemResolverResult { - ExtraFiles = leftOver, - Items = videos + ExtraFiles = leftOver }; - var isInMixedFolder = resolverResult.Count > 1 || (parent != null && parent.IsTopParent); + var isInMixedFolder = resolverResult.Count > 1 || parent?.IsTopParent == true; foreach (var video in resolverResult) { var firstVideo = video.Files[0]; + var path = firstVideo.Path; + if (video.ExtraType != null) + { + result.ExtraFiles.Add(files.Find(f => string.Equals(f.FullName, path, StringComparison.OrdinalIgnoreCase))); + continue; + } + + var additionalParts = video.Files.Count > 1 ? video.Files.Skip(1).Select(i => i.Path).ToArray() : Array.Empty<string>(); var videoItem = new T { - Path = video.Files[0].Path, + Path = path, IsInMixedFolder = isInMixedFolder, ProductionYear = video.Year, - Name = parseName ? - video.Name : - Path.GetFileNameWithoutExtension(video.Files[0].Path), - AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToArray(), + Name = parseName ? video.Name : firstVideo.Name, + AdditionalParts = additionalParts, LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray() }; @@ -299,21 +311,34 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies private static bool IsIgnored(string filename) { // Ignore samples - Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase); + Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase | RegexOptions.Compiled); return m.Success; } - private bool ContainsFile(List<VideoInfo> result, FileSystemMetadata file) + private static bool ContainsFile(IReadOnlyList<VideoInfo> result, FileSystemMetadata file) { - return result.Any(i => ContainsFile(i, file)); - } + for (var i = 0; i < result.Count; i++) + { + var current = result[i]; + for (var j = 0; j < current.Files.Count; j++) + { + if (ContainsFile(current.Files[j], file)) + { + return true; + } + } - private bool ContainsFile(VideoInfo result, FileSystemMetadata file) - { - return result.Files.Any(i => ContainsFile(i, file)) || - result.AlternateVersions.Any(i => ContainsFile(i, file)) || - result.Extras.Any(i => ContainsFile(i, file)); + for (var j = 0; j < current.AlternateVersions.Count; j++) + { + if (ContainsFile(current.AlternateVersions[j], file)) + { + return true; + } + } + } + + return false; } private static bool ContainsFile(VideoFileInfo result, FileSystemMetadata file) @@ -342,9 +367,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"); @@ -358,7 +383,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)) { @@ -431,7 +456,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies // TODO: Allow GetMultiDiscMovie in here const bool SupportsMultiVersion = true; - var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, SupportsMultiVersion, collectionType, parseName) ?? + var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ?? new MultiItemResolverResult(); if (result.Items.Count == 1) @@ -510,7 +535,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return null; } - var result = _stackResolver.ResolveDirectories(folderPaths).ToList(); + var result = StackResolver.ResolveDirectories(folderPaths, NamingOptions).ToList(); if (result.Count != 1) { diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 51d8193037..e52b430500 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using Emby.Naming.Common; using Emby.Naming.Video; +using Jellyfin.Extensions; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -109,7 +110,7 @@ namespace Emby.Server.Implementations.Library.Resolvers } string extension = Path.GetExtension(path).TrimStart('.'); - return imageProcessor.SupportedInputFormats.Contains(extension, StringComparer.OrdinalIgnoreCase); + return imageProcessor.SupportedInputFormats.Contains(extension, StringComparison.OrdinalIgnoreCase); } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs index 8ce59717d0..6b0dfe9864 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; +using Jellyfin.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Resolvers; @@ -57,10 +58,10 @@ namespace Emby.Server.Implementations.Library.Resolvers // Check if this is a music playlist file // It should have the correct collection type and a supported file extension - else if (_musicPlaylistCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + else if (_musicPlaylistCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { var extension = Path.GetExtension(args.Path); - if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { return new Playlist { diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index f72da3617b..be99056470 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -3,7 +3,6 @@ using System; using System.Linq; using Emby.Naming.Common; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; @@ -45,34 +44,36 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV // If the parent is a Season or Series and the parent is not an extras folder, then this is an Episode if the VideoResolver returns something // Also handle flat tv folders - if ((season != null || - string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || - args.HasParent<Series>()) - && (parent is Series || !BaseItem.AllExtrasTypesFolderNames.ContainsKey(parent.Name))) + if (season != null || + string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || + args.HasParent<Series>()) { var episode = ResolveVideo<Episode>(args, false); - if (episode != null) + // Ignore extras + if (episode == null || episode.ExtraType != null) { - var series = parent as Series ?? parent.GetParents().OfType<Series>().FirstOrDefault(); + return null; + } - if (series != null) - { - episode.SeriesId = series.Id; - episode.SeriesName = series.Name; - } + var series = parent as Series ?? parent.GetParents().OfType<Series>().FirstOrDefault(); - if (season != null) - { - episode.SeasonId = season.Id; - episode.SeasonName = season.Name; - } + if (series != null) + { + episode.SeriesId = series.Id; + episode.SeriesName = series.Name; + } - // Assume season 1 if there's no season folder and a season number could not be determined - if (season == null && !episode.ParentIndexNumber.HasValue && (episode.IndexNumber.HasValue || episode.PremiereDate.HasValue)) - { - episode.ParentIndexNumber = 1; - } + if (season != null) + { + episode.SeasonId = season.Id; + episode.SeasonName = season.Name; + } + + // Assume season 1 if there's no season folder and a season number could not be determined + if (season == null && !episode.ParentIndexNumber.HasValue && (episode.IndexNumber.HasValue || episode.PremiereDate.HasValue)) + { + episode.ParentIndexNumber = 1; } return episode; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 4e15acd182..f5ac3c665e 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -5,12 +5,9 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Emby.Naming.Common; using Emby.Naming.TV; using Emby.Naming.Video; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; @@ -185,13 +182,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 bebc25b77d..4aacf7774c 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -10,12 +10,9 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Search; -using Genre = MediaBrowser.Controller.Entities.Genre; -using Person = MediaBrowser.Controller.Entities.Person; namespace Emby.Server.Implementations.Library { @@ -59,9 +56,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 +83,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 +180,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 +189,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 711647e7a6..ab8bc6328d 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -8,11 +8,11 @@ using System.Linq; using System.Threading; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Channels; @@ -20,8 +20,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; -using Genre = MediaBrowser.Controller.Entities.Genre; -using Person = MediaBrowser.Controller.Entities.Person; namespace Emby.Server.Implementations.Library { @@ -80,7 +78,7 @@ namespace Emby.Server.Implementations.Library continue; } - if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { list.Add(GetUserView(folder, folderViewType, string.Empty)); } @@ -180,7 +178,7 @@ namespace Emby.Server.Implementations.Library { if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase))) { - if (!presetViews.Contains(viewType, StringComparer.OrdinalIgnoreCase)) + if (!presetViews.Contains(viewType, StringComparison.OrdinalIgnoreCase)) { return (Folder)parents[0]; } @@ -300,11 +298,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 +342,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 40436d9c5d..7591e8391f 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 945b559ad3..73e58d16c3 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 8a9a4b8652..601aab5b94 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 8577d722e0..26bc49c1f0 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 644f9050d6..7ef93d1669 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -17,6 +17,7 @@ using System.Xml; using Emby.Server.Implementations.Library; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -227,7 +228,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV foreach (var virtualFolder in virtualFolders) { - if (!virtualFolder.Locations.Contains(path, StringComparer.OrdinalIgnoreCase)) + if (!virtualFolder.Locations.Contains(path, StringComparison.OrdinalIgnoreCase)) { continue; } @@ -891,7 +892,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV throw new ArgumentNullException(nameof(tunerHostId)); } - return info.EnabledTuners.Contains(tunerHostId, StringComparer.OrdinalIgnoreCase); + return info.EnabledTuners.Contains(tunerHostId, StringComparison.OrdinalIgnoreCase); } public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) @@ -1778,7 +1779,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 +2138,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) { @@ -2332,7 +2333,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var deletes = _timerProvider.GetAll() .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase)) - .Where(i => !allTimerIds.Contains(i.Id, StringComparer.OrdinalIgnoreCase) && i.StartDate > DateTime.UtcNow) + .Where(i => !allTimerIds.Contains(i.Id, StringComparison.OrdinalIgnoreCase) && i.StartDate > DateTime.UtcNow) .Where(i => deleteStatuses.Contains(i.Status)) .ToList(); @@ -2352,7 +2353,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 +2388,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 +2447,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 +2512,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 +2525,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, @@ -2621,7 +2622,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (newDevicesOnly) { - discoveredDevices = discoveredDevices.Where(d => !configuredDeviceIds.Contains(d.DeviceId, StringComparer.OrdinalIgnoreCase)) + discoveredDevices = discoveredDevices.Where(d => !configuredDeviceIds.Contains(d.DeviceId, StringComparison.OrdinalIgnoreCase)) .ToList(); } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 08aa0cfd72..dd0cb6c5de 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,7 +9,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; +using System.Net.Http.Json; using System.Net.Mime; using System.Security.Cryptography; using System.Text; @@ -101,11 +101,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings } }; - var requestString = JsonSerializer.Serialize(requestList, _jsonOptions); - _logger.LogDebug("Request string for schedules is: {RequestString}", requestString); + _logger.LogDebug("Request string for schedules is: {@RequestString}", requestList); using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules"); - options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json); + options.Content = JsonContent.Create(requestList, options: _jsonOptions); options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); @@ -121,8 +120,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings programRequestOptions.Headers.TryAddWithoutValidation("token", token); var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(programIds, _jsonOptions)); - programRequestOptions.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json); + programRequestOptions.Content = JsonContent.Create(programIds, options: _jsonOptions); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); @@ -243,19 +241,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings if (programInfo.AudioProperties.Count != 0) { - if (programInfo.AudioProperties.Contains("atmos", StringComparer.OrdinalIgnoreCase)) + if (programInfo.AudioProperties.Contains("atmos", StringComparison.OrdinalIgnoreCase)) { audioType = ProgramAudio.Atmos; } - else if (programInfo.AudioProperties.Contains("dd 5.1", StringComparer.OrdinalIgnoreCase)) + else if (programInfo.AudioProperties.Contains("dd 5.1", StringComparison.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Contains("dd", StringComparer.OrdinalIgnoreCase)) + else if (programInfo.AudioProperties.Contains("dd", StringComparison.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Contains("stereo", StringComparer.OrdinalIgnoreCase)) + else if (programInfo.AudioProperties.Contains("stereo", StringComparison.OrdinalIgnoreCase)) { audioType = ProgramAudio.Stereo; } @@ -317,8 +315,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings if (programInfo.VideoProperties != null) { - info.IsHD = programInfo.VideoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); - info.Is3D = programInfo.VideoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase); + info.IsHD = programInfo.VideoProperties.Contains("hdtv", StringComparison.OrdinalIgnoreCase); + info.Is3D = programInfo.VideoProperties.Contains("3d", StringComparison.OrdinalIgnoreCase); } if (details.ContentRating != null && details.ContentRating.Count > 0) @@ -327,7 +325,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings .Replace("--", "-", StringComparison.Ordinal); var invalid = new[] { "N/A", "Approved", "Not Rated", "Passed" }; - if (invalid.Contains(info.OfficialRating, StringComparer.OrdinalIgnoreCase)) + if (invalid.Contains(info.OfficialRating, StringComparison.OrdinalIgnoreCase)) { info.OfficialRating = null; } @@ -389,9 +387,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings if (details.Genres != null) { info.Genres = details.Genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); - info.IsNews = details.Genres.Contains("news", StringComparer.OrdinalIgnoreCase); + info.IsNews = details.Genres.Contains("news", StringComparison.OrdinalIgnoreCase); - if (info.Genres.Contains("children", StringComparer.OrdinalIgnoreCase)) + if (info.Genres.Contains("children", StringComparison.OrdinalIgnoreCase)) { info.IsKids = true; } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 0c0ec48d96..3da9d02b83 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -190,10 +190,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings IsSeries = program.Episode != null, IsRepeat = program.IsPreviouslyShown && !program.IsNew, IsPremiere = program.Premiere != null, - IsKids = program.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), - IsMovie = program.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), - IsNews = program.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), - IsSports = program.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), + IsKids = program.Categories.Any(c => info.KidsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)), + IsMovie = program.Categories.Any(c => info.MovieCategories.Contains(c, StringComparison.OrdinalIgnoreCase)), + IsNews = program.Categories.Any(c => info.NewsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)), + IsSports = program.Categories.Any(c => info.SportsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)), ImageUrl = program.Icon != null && !string.IsNullOrEmpty(program.Icon.Source) ? program.Icon.Source : null, HasImage = program.Icon != null && !string.IsNullOrEmpty(program.Icon.Source), OfficialRating = program.Rating != null && !string.IsNullOrEmpty(program.Rating.Value) ? program.Rating.Value : null, diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index 598e3f88a6..323b960210 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -7,12 +7,12 @@ 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; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; @@ -161,7 +161,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 +204,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 +255,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 +298,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 +309,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 a41b63f284..047d8e98c9 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -33,8 +33,6 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; -using Episode = MediaBrowser.Controller.Entities.TV.Episode; -using Movie = MediaBrowser.Controller.Entities.Movies.Movie; namespace Emby.Server.Implementations.LiveTv { @@ -191,7 +189,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 +808,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 +872,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 +1083,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 +1175,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 +1259,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 +1326,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 +1352,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 +1876,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/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 9fba17ca3b..d2f0334394 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -3,7 +3,6 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; @@ -85,7 +84,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Logger.LogInformation("Opening HDHR UDP Live stream from {Host}", uri.Host); var remoteAddress = IPAddress.Parse(uri.Host); - IPAddress localAddress = null; + IPAddress localAddress; using (var tcpClient = new TcpClient()) { try diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 08b9260b98..99486f25ca 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -119,7 +120,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { var extension = Path.GetExtension(mediaSource.Path) ?? string.Empty; - if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) + if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)) { return new SharedHttpStream(mediaSource, tunerHost, streamId, FileSystem, _httpClientFactory, Logger, Config, _appHost, _streamHelper); } diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index a83a453b4c..9d4d40e512 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -11,11 +11,11 @@ "Collections": "التجميعات", "DeviceOfflineWithName": "قُطِع الاتصال ب{0}", "DeviceOnlineWithName": "{0} متصل", - "FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}", + "FailedLoginAttemptWithUserName": "محاولة تسجيل الدخول فشلت من {0}", "Favorites": "مفضلات", "Folders": "المجلدات", "Genres": "التضنيفات", - "HeaderAlbumArtists": "ألبوم الفنان", + "HeaderAlbumArtists": "فناني الألبوم", "HeaderContinueWatching": "استمر بالمشاهدة", "HeaderFavoriteAlbums": "الألبومات المفضلة", "HeaderFavoriteArtists": "الفنانون المفضلون", diff --git a/Emby.Server.Implementations/Localization/Core/cy.json b/Emby.Server.Implementations/Localization/Core/cy.json index 0fa72dea41..1192f5c88a 100644 --- a/Emby.Server.Implementations/Localization/Core/cy.json +++ b/Emby.Server.Implementations/Localization/Core/cy.json @@ -10,5 +10,49 @@ "AuthenticationSucceededWithUserName": "{0} wedi’i ddilysu’n llwyddiannus", "Artists": "Artistiaid", "AppDeviceValues": "Ap: {0}, Dyfais: {1}", - "Albums": "Albwmau" + "Albums": "Albwmau", + "Genres": "Genres", + "Folders": "Ffolderi", + "Favorites": "Ffefrynnau", + "LabelRunningTimeValue": "Amser rhedeg: {0}", + "TaskOptimizeDatabase": "Cronfa ddata Optimeiddio", + "TaskRefreshChannels": "Adnewyddu Sianeli", + "TaskRefreshPeople": "Adnewyddu Pobl", + "TasksChannelsCategory": "Sianeli Internet", + "VersionNumber": "Fersiwn {0}", + "ScheduledTaskStartedWithName": "{0} wedi dechrau", + "ScheduledTaskFailedWithName": "{0} wedi methu", + "ProviderValue": "Darparwr: {0}", + "NotificationOptionInstallationFailed": "Fethu Gosod", + "NameSeasonUnknown": "Tymor Anhysbys", + "NameSeasonNumber": "Tymor {0}", + "MusicVideos": "Fideos Cerddoriaeth", + "MixedContent": "Cynnwys amrywiol", + "HomeVideos": "Fideos Cartref", + "HeaderNextUp": "Nesaf i Fyny", + "HeaderFavoriteArtists": "Ffefryn Artistiaid", + "HeaderFavoriteAlbums": "Ffefryn Albwmau", + "HeaderContinueWatching": "Parhewch i Weithio", + "TasksApplicationCategory": "Rhaglen", + "TasksLibraryCategory": "Llyfrgell", + "TasksMaintenanceCategory": "Cynnal a Chadw", + "System": "System", + "Plugin": "Ategyn", + "Music": "Cerddoriaeth", + "Latest": "Diweddaraf", + "Inherit": "Etifeddu", + "Forced": "Orfodi", + "Application": "Rhaglen", + "HeaderAlbumArtists": "Artistiaid albwm", + "Sync": "Cysoni", + "Songs": "Caneuon", + "Shows": "Rhaglenni", + "Playlists": "Rhestri Chwarae", + "Photos": "Lluniau", + "ValueSpecialEpisodeName": "Arbennig - {0}", + "Movies": "Ffilmiau", + "Undefined": "Heb ddiffiniad", + "TvShows": "Rhaglenni teledu", + "HeaderLiveTV": "Teledu Byw", + "User": "Defnyddiwr" } diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index 3cadde0a01..8abf7fa660 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/es.json b/Emby.Server.Implementations/Localization/Core/es.json index d3d9d27038..f8c69712e3 100644 --- a/Emby.Server.Implementations/Localization/Core/es.json +++ b/Emby.Server.Implementations/Localization/Core/es.json @@ -15,8 +15,8 @@ "Favorites": "Favoritos", "Folders": "Carpetas", "Genres": "Géneros", - "HeaderAlbumArtists": "Artista del álbum", - "HeaderContinueWatching": "Continuar viendo", + "HeaderAlbumArtists": "Artistas del álbum", + "HeaderContinueWatching": "Seguir viendo", "HeaderFavoriteAlbums": "Álbumes favoritos", "HeaderFavoriteArtists": "Artistas favoritos", "HeaderFavoriteEpisodes": "Episodios favoritos", diff --git a/Emby.Server.Implementations/Localization/Core/es_419.json b/Emby.Server.Implementations/Localization/Core/es_419.json index 010531c9bc..2ca736ad92 100644 --- a/Emby.Server.Implementations/Localization/Core/es_419.json +++ b/Emby.Server.Implementations/Localization/Core/es_419.json @@ -15,7 +15,7 @@ "HeaderFavoriteEpisodes": "Episodios favoritos", "HeaderFavoriteShows": "Programas favoritos", "HeaderContinueWatching": "Continuar viendo", - "HeaderAlbumArtists": "Artistas del álbum", + "HeaderAlbumArtists": "Artistas de álbum", "Genres": "Géneros", "Folders": "Carpetas", "Favorites": "Favoritos", @@ -29,7 +29,7 @@ "TaskRefreshChannelsDescription": "Actualiza la información de canales de Internet.", "TaskRefreshChannels": "Actualizar canales", "TaskCleanTranscodeDescription": "Elimina archivos transcodificados que tengan más de un día.", - "TaskCleanTranscode": "Limpiar directorio de transcodificado", + "TaskCleanTranscode": "Limpiar el directorio de transcodificaciones", "TaskUpdatePluginsDescription": "Descarga e instala actualizaciones para complementos que están configurados para actualizarse automáticamente.", "TaskUpdatePlugins": "Actualizar complementos", "TaskRefreshPeopleDescription": "Actualiza metadatos de actores y directores en tu biblioteca de medios.", @@ -91,7 +91,7 @@ "NameSeasonUnknown": "Temporada desconocida", "NameSeasonNumber": "Temporada {0}", "NameInstallFailed": "Falló la instalación de {0}", - "MusicVideos": "Videos Musicales", + "MusicVideos": "Videos musicales", "Music": "Música", "MixedContent": "Contenido mezclado", "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor", @@ -105,7 +105,7 @@ "Inherit": "Heredar", "HomeVideos": "Videos caseros", "HeaderRecordingGroups": "Grupos de grabación", - "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}", + "FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido desde {0}", "DeviceOnlineWithName": "{0} está conectado", "DeviceOfflineWithName": "{0} se ha desconectado", "ChapterNameValue": "Capítulo {0}", @@ -114,10 +114,10 @@ "Application": "Aplicación", "AppDeviceValues": "App: {0}, Dispositivo: {1}", "TaskCleanActivityLogDescription": "Elimina las entradas del registro de actividad anteriores al periodo configurado.", - "TaskCleanActivityLog": "Limpiar Registro de Actividades", + "TaskCleanActivityLog": "Limpiar registro de actividades", "Undefined": "Sin definir", "Forced": "Forzado", "Default": "Por defecto", - "TaskOptimizeDatabaseDescription": "Compacta la base de datos y restaura el espacio libre. Ejecutar esta tarea después de actualizar las librerías o realizar otros cambios que impliquen modificar las bases de datos puede mejorar la performance.", - "TaskOptimizeDatabase": "Optimización de base de datos" + "TaskOptimizeDatabaseDescription": "Compacta la base de datos y libera espacio. Ejecutar esta tarea después de escanear la biblioteca o hacer otros cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento.", + "TaskOptimizeDatabase": "Optimizar base de datos" } diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json index 71f4a97e54..8db6a0b388 100644 --- a/Emby.Server.Implementations/Localization/Core/et.json +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -102,7 +102,7 @@ "Forced": "Sunnitud", "Folders": "Kaustad", "Favorites": "Lemmikud", - "FailedLoginAttemptWithUserName": "Ebaõnnestunud sisselogimiskatse kasutajalt {0}", + "FailedLoginAttemptWithUserName": "{0} - sisselogimine nurjus", "DeviceOnlineWithName": "{0} on ühendatud", "DeviceOfflineWithName": "{0} katkestas ühenduse", "Default": "Vaikimisi", diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json index 8ab657e5b8..6960ff007a 100644 --- a/Emby.Server.Implementations/Localization/Core/fa.json +++ b/Emby.Server.Implementations/Localization/Core/fa.json @@ -6,7 +6,7 @@ "AuthenticationSucceededWithUserName": "{0} با موفقیت تایید اعتبار شد", "Books": "کتابها", "CameraImageUploadedFrom": "یک عکس جدید از دوربین ارسال شده است {0}", - "Channels": "کانالها", + "Channels": "کانالها", "ChapterNameValue": "قسمت {0}", "Collections": "مجموعهها", "DeviceOfflineWithName": "ارتباط {0} قطع شد", @@ -37,7 +37,7 @@ "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور بروزرسانی شد", "MessageServerConfigurationUpdated": "پیکربندی سرور بروزرسانی شد", "MixedContent": "محتوای مخلوط", - "Movies": "فیلمها", + "Movies": "فیلم ها", "Music": "موسیقی", "MusicVideos": "موزیک ویدیوها", "NameInstallFailed": "{0} نصب با مشکل مواجه شد", @@ -118,5 +118,6 @@ "Default": "پیشفرض", "TaskCleanActivityLogDescription": "ورودیهای قدیمیتر از سن تنظیم شده در سیاهه فعالیت را حذف میکند.", "TaskCleanActivityLog": "پاکسازی سیاهه فعالیت", - "Undefined": "تعریف نشده" + "Undefined": "تعریف نشده", + "TaskOptimizeDatabase": "بهینه سازی پایگاه داده" } diff --git a/Emby.Server.Implementations/Localization/Core/fil.json b/Emby.Server.Implementations/Localization/Core/fil.json index f18a1c0303..99839ae6e8 100644 --- a/Emby.Server.Implementations/Localization/Core/fil.json +++ b/Emby.Server.Implementations/Localization/Core/fil.json @@ -117,5 +117,7 @@ "TaskCleanActivityLogDescription": "Tanggalin ang mga tala ng aktibidad na mas luma sa nakatakda na edad.", "Default": "Default", "Undefined": "Hindi tiyak", - "Forced": "Sapilitan" + "Forced": "Sapilitan", + "TaskOptimizeDatabaseDescription": "Iko-compact ang database at ita-truncate ang free space. Ang pagpapatakbo ng gawaing ito pagkatapos ng pag-scan sa library o paggawa ng iba pang mga pagbabago na nagpapahiwatig ng mga pagbabago sa database ay maaaring magpa-improve ng performance.", + "TaskOptimizeDatabase": "I-optimize ang database" } diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json index d7cda61da6..4df0444e6d 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 c689bc58a5..2588f1e8c0 100644 --- a/Emby.Server.Implementations/Localization/Core/ja.json +++ b/Emby.Server.Implementations/Localization/Core/ja.json @@ -11,12 +11,12 @@ "Collections": "コレクション", "DeviceOfflineWithName": "{0} が切断されました", "DeviceOnlineWithName": "{0} が接続されました", - "FailedLoginAttemptWithUserName": "ログインを試行しましたが {0}によって失敗しました", + "FailedLoginAttemptWithUserName": "ログインを試行しましたが {0} によって失敗しました", "Favorites": "お気に入り", "Folders": "フォルダー", "Genres": "ジャンル", - "HeaderAlbumArtists": "アーティストのアルバム", - "HeaderContinueWatching": "視聴を続ける", + "HeaderAlbumArtists": "アルバムアーティスト", + "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 f3a131d405..f0a07f604c 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 6baedcb2dd..279734c5ee 100644 --- a/Emby.Server.Implementations/Localization/Core/mk.json +++ b/Emby.Server.Implementations/Localization/Core/mk.json @@ -5,7 +5,7 @@ "PluginUninstalledWithName": "{0} беше успешно деинсталирано", "PluginInstalledWithName": "{0} беше успешно инсталирано", "Plugin": "Додатоци", - "Playlists": "Листи", + "Playlists": "Плејлисти", "Photos": "Слики", "NotificationOptionVideoPlaybackStopped": "Видео стопирано", "NotificationOptionVideoPlayback": "Видео пуштено", @@ -97,5 +97,8 @@ "TasksChannelsCategory": "Интернет Канали", "TasksApplicationCategory": "Апликација", "TasksLibraryCategory": "Библиотека", - "TasksMaintenanceCategory": "Одржување" + "TasksMaintenanceCategory": "Одржување", + "Undefined": "Недефинирано", + "Forced": "Принудно", + "Default": "Зададено" } diff --git a/Emby.Server.Implementations/Localization/Core/mn.json b/Emby.Server.Implementations/Localization/Core/mn.json index ab7d423b58..7421d42fb4 100644 --- a/Emby.Server.Implementations/Localization/Core/mn.json +++ b/Emby.Server.Implementations/Localization/Core/mn.json @@ -9,5 +9,6 @@ "Genres": "Төрөл зүйл", "Favorites": "Дуртай", "Collections": "Багц", - "Artists": "Жүжигчин" + "Artists": "Зураачуд", + "Albums": "Цомгууд" } diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json index b2dcf270c1..deb28970c0 100644 --- a/Emby.Server.Implementations/Localization/Core/ms.json +++ b/Emby.Server.Implementations/Localization/Core/ms.json @@ -2,7 +2,7 @@ "Albums": "Album-album", "AppDeviceValues": "Apl: {0}, Peranti: {1}", "Application": "Aplikasi", - "Artists": "Artis", + "Artists": "Artis-artis", "AuthenticationSucceededWithUserName": "{0} berjaya disahkan", "Books": "Buku-buku", "CameraImageUploadedFrom": "Gambar baharu telah dimuat naik melalui {0}", @@ -37,9 +37,9 @@ "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan di bahagian {0} telah dikemas kini", "MessageServerConfigurationUpdated": "Konfigurasi pelayan telah dikemas kini", "MixedContent": "Kandungan campuran", - "Movies": "Filem", + "Movies": "Filem-filem", "Music": "Muzik", - "MusicVideos": "Muzik video", + "MusicVideos": "Video muzik", "NameInstallFailed": "{0} pemasangan gagal", "NameSeasonNumber": "Musim {0}", "NameSeasonUnknown": "Musim Tidak Diketahui", @@ -53,43 +53,43 @@ "NotificationOptionNewLibraryContent": "Kandungan baru telah ditambah", "NotificationOptionPluginError": "Kegagalan plugin", "NotificationOptionPluginInstalled": "Plugin telah dipasang", - "NotificationOptionPluginUninstalled": "Plugin uninstalled", - "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Server restart required", - "NotificationOptionTaskFailed": "Scheduled task failure", - "NotificationOptionUserLockedOut": "User locked out", - "NotificationOptionVideoPlayback": "Video playback started", + "NotificationOptionPluginUninstalled": "Plugin telah dinyahpasang", + "NotificationOptionPluginUpdateInstalled": "Kemaskini plugin telah dipasang", + "NotificationOptionServerRestartRequired": "", + "NotificationOptionTaskFailed": "Kegagalan tugas berjadual", + "NotificationOptionUserLockedOut": "Pengguna telah dikunci", + "NotificationOptionVideoPlayback": "Ulangmain video bermula", "NotificationOptionVideoPlaybackStopped": "Ulangmain video dihentikan", "Photos": "Gambar-gambar", "Playlists": "Senarai main", "Plugin": "Plugin", - "PluginInstalledWithName": "{0} was installed", - "PluginUninstalledWithName": "{0} was uninstalled", - "PluginUpdatedWithName": "{0} was updated", - "ProviderValue": "Provider: {0}", + "PluginInstalledWithName": "{0} telah dipasang", + "PluginUninstalledWithName": "{0} telah dinyahpasang", + "PluginUpdatedWithName": "{0} telah dikemaskini", + "ProviderValue": "Pembekal: {0}", "ScheduledTaskFailedWithName": "{0} gagal", "ScheduledTaskStartedWithName": "{0} bermula", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", - "Shows": "Series", + "ServerNameNeedsToBeRestarted": "{0} perlu di ulangmula", + "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": "Segerak", "System": "Sistem", - "TvShows": "TV Shows", - "User": "User", - "UserCreatedWithName": "User {0} has been created", - "UserDeletedWithName": "User {0} has been deleted", - "UserDownloadingItemWithValues": "{0} is downloading {1}", + "TvShows": "Tayangan TV", + "User": "Pengguna", + "UserCreatedWithName": "Pengguna {0} telah diwujudkan", + "UserDeletedWithName": "Pengguna {0} telah dipadamkan", + "UserDownloadingItemWithValues": "{0} sedang memuat turun {1}", "UserLockedOutWithName": "Pengguna {0} telah dikunci", "UserOfflineFromDevice": "{0} telah terputus dari {1}", "UserOnlineFromDevice": "{0} berada dalam talian dari {1}", "UserPasswordChangedWithName": "Kata laluan telah ditukar bagi pengguna {0}", "UserPolicyUpdatedWithName": "Dasar pengguna telah dikemas kini untuk {0}", - "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}", - "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "UserStartedPlayingItemWithValues": "{0} sedang dimainkan {1} pada {2}", + "UserStoppedPlayingItemWithValues": "{0} telah tamat dimainkan {1} pada {2}", + "ValueHasBeenAddedToLibrary": "{0} telah ditambah ke media library anda", "ValueSpecialEpisodeName": "Khas - {0}", "VersionNumber": "Versi {0}", "TaskCleanActivityLog": "Log Aktiviti Bersih", diff --git a/Emby.Server.Implementations/Localization/Core/ne.json b/Emby.Server.Implementations/Localization/Core/ne.json index 8e820d40c7..8584fc0653 100644 --- a/Emby.Server.Implementations/Localization/Core/ne.json +++ b/Emby.Server.Implementations/Localization/Core/ne.json @@ -69,7 +69,7 @@ "UserDeletedWithName": "प्रयोगकर्ता {0} हटाइएको छ", "UserCreatedWithName": "प्रयोगकर्ता {0} सिर्जना गरिएको छ", "User": "प्रयोगकर्ता", - "PluginInstalledWithName": "", + "PluginInstalledWithName": "{0} सभएको थियो", "StartupEmbyServerIsLoading": "Jellyfin सर्भर लोड हुँदैछ। कृपया छिट्टै फेरि प्रयास गर्नुहोस्।", "Songs": "गीतहरू", "Shows": "शोहरू", diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json index 79f921bcb2..9d512dea16 100644 --- a/Emby.Server.Implementations/Localization/Core/nl.json +++ b/Emby.Server.Implementations/Localization/Core/nl.json @@ -15,7 +15,7 @@ "Favorites": "Favorieten", "Folders": "Mappen", "Genres": "Genres", - "HeaderAlbumArtists": "Artiests Album", + "HeaderAlbumArtists": "Album Artiesten", "HeaderContinueWatching": "Kijken hervatten", "HeaderFavoriteAlbums": "Favoriete albums", "HeaderFavoriteArtists": "Favoriete artiesten", diff --git a/Emby.Server.Implementations/Localization/Core/pa.json b/Emby.Server.Implementations/Localization/Core/pa.json index d1db09232e..4ac57b630d 100644 --- a/Emby.Server.Implementations/Localization/Core/pa.json +++ b/Emby.Server.Implementations/Localization/Core/pa.json @@ -24,7 +24,7 @@ "TasksLibraryCategory": "ਲਾਇਬ੍ਰੇਰੀ", "TasksMaintenanceCategory": "ਰੱਖ-ਰਖਾਅ", "VersionNumber": "ਵਰਜਨ {0}", - "ValueSpecialEpisodeName": "ਵਿਸ਼ੇਸ਼ - {0}", + "ValueSpecialEpisodeName": "ਖਾਸ - {0}", "ValueHasBeenAddedToLibrary": "{0} ਤੁਹਾਡੀ ਮੀਡੀਆ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ", "UserStoppedPlayingItemWithValues": "{0} ਨੇ {2} 'ਤੇ {1} ਖੇਡਣਾ ਪੂਰਾ ਕਰ ਲਿਆ ਹੈ", "UserStartedPlayingItemWithValues": "{0} {2} 'ਤੇ {1} ਖੇਡ ਰਿਹਾ ਹੈ", @@ -43,8 +43,8 @@ "Sync": "ਸਿੰਕ", "SubtitleDownloadFailureFromForItem": "ਉਪਸਿਰਲੇਖ {1} ਲਈ {0} ਤੋਂ ਡਾ toਨਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ", "StartupEmbyServerIsLoading": "ਜੈਲੀਫਿਨ ਸਰਵਰ ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ. ਕਿਰਪਾ ਕਰਕੇ ਜਲਦੀ ਹੀ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ.", - "Songs": "ਗਾਣੇ", - "Shows": "ਸ਼ੋਅਜ਼", + "Songs": "ਗਾਣੇਂ", + "Shows": "ਸ਼ੋਅ", "ServerNameNeedsToBeRestarted": "{0} ਮੁੜ ਚਾਲੂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ", "ScheduledTaskStartedWithName": "{0} ਸ਼ੁਰੂ ਹੋਇਆ", "ScheduledTaskFailedWithName": "{0} ਅਸਫਲ", @@ -53,7 +53,7 @@ "PluginUninstalledWithName": "{0} ਅਣਇੰਸਟੌਲ ਕੀਤਾ ਗਿਆ ਸੀ", "PluginInstalledWithName": "{0} ਲਗਾਇਆ ਗਿਆ ਸੀ", "Plugin": "ਪਲੱਗਇਨ", - "Playlists": "ਪਲੇਲਿਸਟਸ", + "Playlists": "ਪਲੇਸੂਚੀਆਂ", "Photos": "ਫੋਟੋਆਂ", "NotificationOptionVideoPlaybackStopped": "ਵੀਡੀਓ ਪਲੇਬੈਕ ਰੋਕਿਆ ਗਿਆ", "NotificationOptionVideoPlayback": "ਵੀਡੀਓ ਪਲੇਬੈਕ ਸ਼ੁਰੂ ਹੋਇਆ", @@ -102,13 +102,13 @@ "HeaderAlbumArtists": "ਐਲਬਮ ਕਲਾਕਾਰ", "Genres": "ਸ਼ੈਲੀਆਂ", "Forced": "ਮਜਬੂਰ", - "Folders": "ਫੋਲਡਰ", + "Folders": "ਫੋਲਡਰਸ", "Favorites": "ਮਨਪਸੰਦ", "FailedLoginAttemptWithUserName": "ਤੋਂ ਲਾਗਇਨ ਕੋਸ਼ਿਸ਼ ਫੇਲ ਹੋਈ {0}", "DeviceOnlineWithName": "{0} ਜੁੜਿਆ ਹੋਇਆ ਹੈ", "DeviceOfflineWithName": "{0} ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ ਹੈ", - "Default": "ਮੂਲ", - "Collections": "ਸੰਗ੍ਰਹਿ", + "Default": "ਡਿਫੌਲਟ", + "Collections": "ਸੰਗ੍ਰਹਿਣ", "ChapterNameValue": "ਅਧਿਆਇ {0}", "Channels": "ਚੈਨਲ", "CameraImageUploadedFrom": "ਤੋਂ ਇੱਕ ਨਵਾਂ ਕੈਮਰਾ ਚਿੱਤਰ ਅਪਲੋਡ ਕੀਤਾ ਗਿਆ ਹੈ {0}", diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json index e8a32a13e8..4fa8d2bb46 100644 --- a/Emby.Server.Implementations/Localization/Core/pl.json +++ b/Emby.Server.Implementations/Localization/Core/pl.json @@ -15,7 +15,7 @@ "Favorites": "Ulubione", "Folders": "Foldery", "Genres": "Gatunki", - "HeaderAlbumArtists": "Album artysty", + "HeaderAlbumArtists": "Wykonawcy albumów", "HeaderContinueWatching": "Kontynuuj odtwarzanie", "HeaderFavoriteAlbums": "Ulubione albumy", "HeaderFavoriteArtists": "Ulubieni wykonawcy", @@ -47,7 +47,7 @@ "NotificationOptionApplicationUpdateAvailable": "Dostępna aktualizacja aplikacji", "NotificationOptionApplicationUpdateInstalled": "Zaktualizowano aplikację", "NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki", - "NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane", + "NotificationOptionAudioPlaybackStopped": "Odtwarzanie dźwięku zatrzymane", "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia przenośnego", "NotificationOptionInstallationFailed": "Nieudana instalacja", "NotificationOptionNewLibraryContent": "Dodano nową zawartość", @@ -98,7 +98,7 @@ "TaskRefreshChannels": "Odśwież kanały", "TaskCleanTranscodeDescription": "Usuwa transkodowane pliki starsze niż 1 dzień.", "TaskCleanTranscode": "Wyczyść folder transkodowania", - "TaskUpdatePluginsDescription": "Pobiera i instaluje aktualizacje dla pluginów które są skonfigurowane do automatycznej aktualizacji.", + "TaskUpdatePluginsDescription": "Pobiera i instaluje aktualizacje dla pluginów, które są skonfigurowane do automatycznej aktualizacji.", "TaskUpdatePlugins": "Aktualizuj pluginy", "TaskRefreshPeopleDescription": "Odświeża metadane o aktorów i reżyserów w Twojej bibliotece mediów.", "TaskRefreshPeople": "Odśwież obsadę", diff --git a/Emby.Server.Implementations/Localization/Core/pr.json b/Emby.Server.Implementations/Localization/Core/pr.json index e3a3bfaf1c..81aa996d9e 100644 --- a/Emby.Server.Implementations/Localization/Core/pr.json +++ b/Emby.Server.Implementations/Localization/Core/pr.json @@ -1,5 +1,7 @@ { "Books": "Libros", "AuthenticationSucceededWithUserName": "{0} autentificado correctamente", - "Artists": "Artistas" + "Artists": "Artistas", + "Songs": "Shantees", + "Albums": "Ships" } diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json index 3c9ac2c241..a9dbd53ea2 100644 --- a/Emby.Server.Implementations/Localization/Core/pt.json +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -11,7 +11,7 @@ "HeaderFavoriteEpisodes": "Episódios Favoritos", "HeaderFavoriteShows": "Séries Favoritas", "HeaderContinueWatching": "Continuar assistindo", - "HeaderAlbumArtists": "Discos do Artista", + "HeaderAlbumArtists": "Artistas do Álbum", "Genres": "Gêneros", "Folders": "Diretórios", "Favorites": "Favoritos", diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json index 510aac11c6..f8fad7b631 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/sq.json b/Emby.Server.Implementations/Localization/Core/sq.json index 066ef55878..2766dab06a 100644 --- a/Emby.Server.Implementations/Localization/Core/sq.json +++ b/Emby.Server.Implementations/Localization/Core/sq.json @@ -74,7 +74,7 @@ "NameSeasonUnknown": "Sezon i panjohur", "NameSeasonNumber": "Sezoni {0}", "NameInstallFailed": "Instalimi i {0} dështoi", - "MusicVideos": "Video muzikore", + "MusicVideos": "Video Muzikore", "Music": "Muzikë", "Movies": "Filmat", "MixedContent": "Përmbajtje e përzier", @@ -96,7 +96,7 @@ "HeaderFavoriteArtists": "Artistët e preferuar", "HeaderFavoriteAlbums": "Albumet e preferuar", "HeaderContinueWatching": "Vazhdo të shikosh", - "HeaderAlbumArtists": "Artistët e Albumeve", + "HeaderAlbumArtists": "Artistët e albumeve", "Genres": "Zhanret", "Folders": "Skedarët", "Favorites": "Të preferuarat", diff --git a/Emby.Server.Implementations/Localization/Core/sr.json b/Emby.Server.Implementations/Localization/Core/sr.json index 15fb34186b..e31208e807 100644 --- a/Emby.Server.Implementations/Localization/Core/sr.json +++ b/Emby.Server.Implementations/Localization/Core/sr.json @@ -50,7 +50,7 @@ "NameSeasonUnknown": "Непозната сезона", "NameSeasonNumber": "Сезона {0}", "NameInstallFailed": "Инсталација {0} није успела", - "MusicVideos": "Музички спотови", + "MusicVideos": "Музички видео", "Music": "Музика", "Movies": "Филмови", "MixedContent": "Мешовит садржај", @@ -64,7 +64,7 @@ "ItemRemovedWithName": "{0} уклоњено из библиотеке", "ItemAddedWithName": "{0} додато у библиотеку", "Inherit": "Наследи", - "HomeVideos": "Кућни видео", + "HomeVideos": "Кућни Видео", "HeaderRecordingGroups": "Групе снимања", "HeaderNextUp": "Следи", "HeaderLiveTV": "ТВ уживо", @@ -117,5 +117,6 @@ "TaskCleanActivityLog": "Очисти историју активности", "Undefined": "Недефинисано", "Forced": "Принудно", - "Default": "Подразумевано" + "Default": "Подразумевано", + "TaskOptimizeDatabase": "Оптимизуј датабазу" } diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json index 6c772c6a24..f3f6016615 100644 --- a/Emby.Server.Implementations/Localization/Core/sv.json +++ b/Emby.Server.Implementations/Localization/Core/sv.json @@ -15,7 +15,7 @@ "Favorites": "Favoriter", "Folders": "Mappar", "Genres": "Genrer", - "HeaderAlbumArtists": "Artistens album", + "HeaderAlbumArtists": "Albumsartister", "HeaderContinueWatching": "Fortsätt kolla", "HeaderFavoriteAlbums": "Favoritalbum", "HeaderFavoriteArtists": "Favoritartister", @@ -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/ta.json b/Emby.Server.Implementations/Localization/Core/ta.json index d6e9aa8e5a..98d763fcd6 100644 --- a/Emby.Server.Implementations/Localization/Core/ta.json +++ b/Emby.Server.Implementations/Localization/Core/ta.json @@ -21,7 +21,7 @@ "Inherit": "மரபுரிமையாகப் பெறு", "HeaderRecordingGroups": "பதிவு குழுக்கள்", "Folders": "கோப்புறைகள்", - "FailedLoginAttemptWithUserName": "{0} இல் இருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது", + "FailedLoginAttemptWithUserName": "{0} இன் உள்நுழைவு முயற்சி தோல்வியடைந்தது", "DeviceOnlineWithName": "{0} இணைக்கப்பட்டது", "DeviceOfflineWithName": "{0} துண்டிக்கப்பட்டது", "Collections": "தொகுப்புகள்", @@ -85,7 +85,7 @@ "HeaderFavoriteArtists": "பிடித்த கலைஞர்கள்", "HeaderFavoriteAlbums": "பிடித்த ஆல்பங்கள்", "HeaderContinueWatching": "தொடர்ந்து பார்", - "HeaderAlbumArtists": "இசைக் கலைஞர்கள்", + "HeaderAlbumArtists": "கலைஞரின் ஆல்பம்", "Genres": "வகைகள்", "Favorites": "பிடித்தவை", "ChapterNameValue": "அத்தியாயம் {0}", diff --git a/Emby.Server.Implementations/Localization/Core/te.json b/Emby.Server.Implementations/Localization/Core/te.json index 0967ef424b..a9a8ceae0e 100644 --- a/Emby.Server.Implementations/Localization/Core/te.json +++ b/Emby.Server.Implementations/Localization/Core/te.json @@ -1 +1,23 @@ -{} +{ + "ValueSpecialEpisodeName": "ప్రత్యేక - {0}", + "Sync": "సమకాలీకరించు", + "Songs": "పాటలు", + "Shows": "ప్రదర్శనలు", + "Playlists": "ప్లేజాబితాలు", + "Photos": "ఫోటోలు", + "MusicVideos": "మ్యూజిక్ వీడియోలు", + "Music": "సంగీతం", + "Movies": "సినిమాలు", + "HeaderContinueWatching": "చూడటం కొనసాగించండి", + "HeaderAlbumArtists": "ఆల్బమ్ కళాకారులు", + "Genres": "శైలులు", + "Forced": "బలవంతంగా", + "Folders": "ఫోల్డర్లు", + "Favorites": "ఇష్టమైనవి", + "Default": "డిఫాల్ట్", + "Collections": "సేకరణలు", + "Channels": "ఛానెల్లు", + "Books": "పుస్తకాలు", + "Artists": "కళాకారులు", + "Albums": "ఆల్బమ్లు" +} diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json index a5ff3031d7..b7ece8d5fc 100644 --- a/Emby.Server.Implementations/Localization/Core/vi.json +++ b/Emby.Server.Implementations/Localization/Core/vi.json @@ -3,7 +3,7 @@ "Favorites": "Yêu Thích", "Folders": "Thư Mục", "Genres": "Thể Loại", - "HeaderAlbumArtists": "Album Nghệ sĩ", + "HeaderAlbumArtists": "Album nghệ sĩ", "HeaderContinueWatching": "Xem Tiếp", "HeaderLiveTV": "TV Trực Tiếp", "Movies": "Phim", @@ -103,7 +103,7 @@ "HeaderFavoriteEpisodes": "Tập Phim Yêu Thích", "HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích", "HeaderFavoriteAlbums": "Album Ưa Thích", - "FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập thất bại từ {0}", + "FailedLoginAttemptWithUserName": "Đăng nhập không thành công thử từ {0}", "DeviceOnlineWithName": "{0} đã kết nối", "DeviceOfflineWithName": "{0} đã ngắt kết nối", "ChapterNameValue": "Phân Cảnh {0}", diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index f9df627245..ac4eb644b7 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-CN.json +++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json @@ -11,7 +11,7 @@ "Collections": "合集", "DeviceOfflineWithName": "{0} 已断开", "DeviceOnlineWithName": "{0} 已连接", - "FailedLoginAttemptWithUserName": "来自 {0} 的失败登入", + "FailedLoginAttemptWithUserName": "从 {0} 尝试登录失败", "Favorites": "我的最爱", "Folders": "文件夹", "Genres": "风格", diff --git a/Emby.Server.Implementations/Localization/Core/zu.json b/Emby.Server.Implementations/Localization/Core/zu.json index 0967ef424b..b5f4b920f3 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/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 9cdbbb6a3e..dbd70342a5 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -310,7 +310,7 @@ namespace Emby.Server.Implementations.Localization return _dictionaries.GetOrAdd( culture, - (key, localizationManager) => localizationManager.GetDictionary(Prefix, key, DefaultCulture + ".json").GetAwaiter().GetResult(), + static (key, localizationManager) => localizationManager.GetDictionary(Prefix, key, DefaultCulture + ".json").GetAwaiter().GetResult(), this); } diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index ac6606d39a..6e1dc725d4 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -120,7 +121,7 @@ namespace Emby.Server.Implementations.MediaEncoder var path = GetChapterImagePath(video, chapter.StartPositionTicks); - if (!currentImages.Contains(path, StringComparer.OrdinalIgnoreCase)) + if (!currentImages.Contains(path, StringComparison.OrdinalIgnoreCase)) { if (extractImages) { @@ -219,7 +220,7 @@ namespace Emby.Server.Implementations.MediaEncoder { var deadImages = images .Except(chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i)), StringComparer.OrdinalIgnoreCase) - .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i), StringComparer.OrdinalIgnoreCase)) + .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i), StringComparison.OrdinalIgnoreCase)) .ToList(); foreach (var image in deadImages) diff --git a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs index 8b1cee89d1..8ec9f61616 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/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index 09ea6271d9..8b185419f3 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -143,7 +144,7 @@ namespace Emby.Server.Implementations.ScheduledTasks var key = video.Path + video.DateModified.Ticks; - var extract = !previouslyFailedImages.Contains(key, StringComparer.OrdinalIgnoreCase); + var extract = !previouslyFailedImages.Contains(key, StringComparison.OrdinalIgnoreCase); try { diff --git a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs index 059211a0b9..1bac2600ca 100644 --- a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs +++ b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Serialization private static XmlSerializer GetSerializer(Type type) => _serializers.GetOrAdd( type.FullName ?? throw new ArgumentException($"Invalid type {type}."), - (_, t) => new XmlSerializer(t), + static (_, t) => new XmlSerializer(t), type); /// <summary> diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 341d2c8e61..d10a24bbc6 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 4d990c8718..a878312944 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/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index ef95ebf943..24d592525d 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Net.Http; using System.Net.Http.Json; @@ -19,7 +20,6 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Updates; using Microsoft.Extensions.Logging; @@ -47,7 +47,6 @@ namespace Emby.Server.Implementations.Updates /// </summary> /// <value>The application host.</value> private readonly IServerApplicationHost _applicationHost; - private readonly IZipClient _zipClient; private readonly object _currentInstallationsLock = new object(); /// <summary> @@ -69,7 +68,6 @@ namespace Emby.Server.Implementations.Updates /// <param name="eventManager">The <see cref="IEventManager"/>.</param> /// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/>.</param> /// <param name="config">The <see cref="IServerConfigurationManager"/>.</param> - /// <param name="zipClient">The <see cref="IZipClient"/>.</param> /// <param name="pluginManager">The <see cref="IPluginManager"/>.</param> public InstallationManager( ILogger<InstallationManager> logger, @@ -78,7 +76,6 @@ namespace Emby.Server.Implementations.Updates IEventManager eventManager, IHttpClientFactory httpClientFactory, IServerConfigurationManager config, - IZipClient zipClient, IPluginManager pluginManager) { _currentInstallations = new List<(InstallationInfo, CancellationTokenSource)>(); @@ -90,7 +87,6 @@ namespace Emby.Server.Implementations.Updates _eventManager = eventManager; _httpClientFactory = httpClientFactory; _config = config; - _zipClient = zipClient; _jsonSerializerOptions = JsonDefaults.Options; _pluginManager = pluginManager; } @@ -560,7 +556,8 @@ namespace Emby.Server.Implementations.Updates } stream.Position = 0; - _zipClient.ExtractAllFromZip(stream, targetDir, true); + using var reader = new ZipArchive(stream); + reader.ExtractToDirectory(targetDir, true); await _pluginManager.GenerateManifest(package.PackageInfo, package.Version, targetDir, status).ConfigureAwait(false); _pluginManager.ImportPluginFrom(targetDir); } |
