diff options
Diffstat (limited to 'Emby.Server.Implementations')
30 files changed, 442 insertions, 158 deletions
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs index f0c267627..c06cd8510 100644 --- a/Emby.Server.Implementations/ConfigurationOptions.cs +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -19,7 +19,8 @@ namespace Emby.Server.Implementations { FfmpegAnalyzeDurationKey, "200M" }, { PlaylistsAllowDuplicatesKey, bool.FalseString }, { BindToUnixSocketKey, bool.FalseString }, - { SqliteCacheSizeKey, "20000" } + { SqliteCacheSizeKey, "20000" }, + { SqliteDisableSecondLevelCacheKey, bool.FalseString } }; } } diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index b1c99227c..5291999dc 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Threading; using Jellyfin.Extensions; using Microsoft.Data.Sqlite; using Microsoft.Extensions.Logging; @@ -13,6 +14,8 @@ namespace Emby.Server.Implementations.Data public abstract class BaseSqliteRepository : IDisposable { private bool _disposed = false; + private SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); + private SqliteConnection _writeConnection; /// <summary> /// Initializes a new instance of the <see cref="BaseSqliteRepository"/> class. @@ -29,17 +32,6 @@ namespace Emby.Server.Implementations.Data protected string DbFilePath { get; set; } /// <summary> - /// Gets or sets the number of write connections to create. - /// </summary> - /// <value>Path to the DB file.</value> - protected int WriteConnectionsCount { get; set; } = 1; - - /// <summary> - /// Gets or sets the number of read connections to create. - /// </summary> - protected int ReadConnectionsCount { get; set; } = 1; - - /// <summary> /// Gets the logger. /// </summary> /// <value>The logger.</value> @@ -98,9 +90,55 @@ namespace Emby.Server.Implementations.Data } } - protected SqliteConnection GetConnection() + protected ManagedConnection GetConnection(bool readOnly = false) { - var connection = new SqliteConnection($"Filename={DbFilePath}"); + if (!readOnly) + { + _writeLock.Wait(); + if (_writeConnection is not null) + { + return new ManagedConnection(_writeConnection, _writeLock); + } + + var writeConnection = new SqliteConnection($"Filename={DbFilePath};Pooling=False"); + writeConnection.Open(); + + if (CacheSize.HasValue) + { + writeConnection.Execute("PRAGMA cache_size=" + CacheSize.Value); + } + + if (!string.IsNullOrWhiteSpace(LockingMode)) + { + writeConnection.Execute("PRAGMA locking_mode=" + LockingMode); + } + + if (!string.IsNullOrWhiteSpace(JournalMode)) + { + writeConnection.Execute("PRAGMA journal_mode=" + JournalMode); + } + + if (JournalSizeLimit.HasValue) + { + writeConnection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value); + } + + if (Synchronous.HasValue) + { + writeConnection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value); + } + + if (PageSize.HasValue) + { + writeConnection.Execute("PRAGMA page_size=" + PageSize.Value); + } + + writeConnection.Execute("PRAGMA temp_store=" + (int)TempStore); + + return new ManagedConnection(_writeConnection = writeConnection, _writeLock); + } + + var connection = new SqliteConnection($"Filename={DbFilePath};Mode=ReadOnly"); connection.Open(); if (CacheSize.HasValue) @@ -135,17 +173,17 @@ namespace Emby.Server.Implementations.Data connection.Execute("PRAGMA temp_store=" + (int)TempStore); - return connection; + return new ManagedConnection(connection, null); } - public SqliteCommand PrepareStatement(SqliteConnection connection, string sql) + public SqliteCommand PrepareStatement(ManagedConnection connection, string sql) { var command = connection.CreateCommand(); command.CommandText = sql; return command; } - protected bool TableExists(SqliteConnection connection, string name) + protected bool TableExists(ManagedConnection connection, string name) { using var statement = PrepareStatement(connection, "select DISTINCT tbl_name from sqlite_master"); foreach (var row in statement.ExecuteQuery()) @@ -159,7 +197,7 @@ namespace Emby.Server.Implementations.Data return false; } - protected List<string> GetColumnNames(SqliteConnection connection, string table) + protected List<string> GetColumnNames(ManagedConnection connection, string table) { var columnNames = new List<string>(); @@ -174,7 +212,7 @@ namespace Emby.Server.Implementations.Data return columnNames; } - protected void AddColumn(SqliteConnection connection, string table, string columnName, string type, List<string> existingColumnNames) + protected void AddColumn(ManagedConnection connection, string table, string columnName, string type, List<string> existingColumnNames) { if (existingColumnNames.Contains(columnName, StringComparison.OrdinalIgnoreCase)) { @@ -207,6 +245,24 @@ namespace Emby.Server.Implementations.Data return; } + if (dispose) + { + _writeLock.Wait(); + try + { + _writeConnection.Dispose(); + } + finally + { + _writeLock.Release(); + } + + _writeLock.Dispose(); + } + + _writeConnection = null; + _writeLock = null; + _disposed = true; } } diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs new file mode 100644 index 000000000..860950b30 --- /dev/null +++ b/Emby.Server.Implementations/Data/ManagedConnection.cs @@ -0,0 +1,62 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; +using System.Threading; +using Microsoft.Data.Sqlite; + +namespace Emby.Server.Implementations.Data; + +public sealed class ManagedConnection : IDisposable +{ + private readonly SemaphoreSlim? _writeLock; + + private SqliteConnection _db; + + private bool _disposed = false; + + public ManagedConnection(SqliteConnection db, SemaphoreSlim? writeLock) + { + _db = db; + _writeLock = writeLock; + } + + public SqliteTransaction BeginTransaction() + => _db.BeginTransaction(); + + public SqliteCommand CreateCommand() + => _db.CreateCommand(); + + public void Execute(string commandText) + => _db.Execute(commandText); + + public SqliteCommand PrepareStatement(string sql) + => _db.PrepareStatement(sql); + + public IEnumerable<SqliteDataReader> Query(string commandText) + => _db.Query(commandText); + + public void Dispose() + { + if (_disposed) + { + return; + } + + if (_writeLock is null) + { + // Read connections are managed with an internal pool + _db.Dispose(); + } + else + { + // Write lock is managed by BaseSqliteRepository + // Don't dispose here + _writeLock.Release(); + } + + _db = null!; + + _disposed = true; + } +} diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 34d753093..81ee55d26 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -327,7 +327,6 @@ namespace Emby.Server.Implementations.Data DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); CacheSize = configuration.GetSqliteCacheSize(); - ReadConnectionsCount = Environment.ProcessorCount * 2; } /// <inheritdoc /> @@ -601,7 +600,7 @@ namespace Emby.Server.Implementations.Data transaction.Commit(); } - private void SaveItemsInTransaction(SqliteConnection db, IEnumerable<(BaseItem Item, List<Guid> AncestorIds, BaseItem TopParent, string UserDataKey, List<string> InheritedTags)> tuples) + private void SaveItemsInTransaction(ManagedConnection db, IEnumerable<(BaseItem Item, List<Guid> AncestorIds, BaseItem TopParent, string UserDataKey, List<string> InheritedTags)> tuples) { using (var saveItemStatement = PrepareStatement(db, SaveItemCommandText)) using (var deleteAncestorsStatement = PrepareStatement(db, "delete from AncestorIds where ItemId=@ItemId")) @@ -1261,7 +1260,7 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, _retrieveItemColumnsSelectQuery)) { statement.TryBind("@guid", id); @@ -1298,16 +1297,15 @@ namespace Emby.Server.Implementations.Data && type != typeof(Book) && type != typeof(LiveTvProgram) && type != typeof(AudioBook) - && type != typeof(Audio) && type != typeof(MusicAlbum); } private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query) { - return GetItem(reader, query, HasProgramAttributes(query), HasEpisodeAttributes(query), HasServiceName(query), HasStartDate(query), HasTrailerTypes(query), HasArtistFields(query), HasSeriesFields(query)); + return GetItem(reader, query, HasProgramAttributes(query), HasEpisodeAttributes(query), HasServiceName(query), HasStartDate(query), HasTrailerTypes(query), HasArtistFields(query), HasSeriesFields(query), false); } - private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query, bool enableProgramAttributes, bool hasEpisodeAttributes, bool hasServiceName, bool queryHasStartDate, bool hasTrailerTypes, bool hasArtistFields, bool hasSeriesFields) + private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query, bool enableProgramAttributes, bool hasEpisodeAttributes, bool hasServiceName, bool queryHasStartDate, bool hasTrailerTypes, bool hasArtistFields, bool hasSeriesFields, bool skipDeserialization) { var typeString = reader.GetString(0); @@ -1320,7 +1318,7 @@ namespace Emby.Server.Implementations.Data BaseItem item = null; - if (TypeRequiresDeserialization(type)) + if (TypeRequiresDeserialization(type) && !skipDeserialization) { try { @@ -1888,7 +1886,7 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); var chapters = new List<ChapterInfo>(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { statement.TryBind("@ItemId", item.Id); @@ -1907,7 +1905,7 @@ namespace Emby.Server.Implementations.Data { CheckDisposed(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) { statement.TryBind("@ItemId", item.Id); @@ -1981,7 +1979,7 @@ namespace Emby.Server.Implementations.Data transaction.Commit(); } - private void InsertChapters(Guid idBlob, IReadOnlyList<ChapterInfo> chapters, SqliteConnection db) + private void InsertChapters(Guid idBlob, IReadOnlyList<ChapterInfo> chapters, ManagedConnection db) { var startIndex = 0; var limit = 100; @@ -2470,7 +2468,7 @@ namespace Emby.Server.Implementations.Data var commandText = commandTextBuilder.ToString(); using (new QueryTimeLogger(Logger, commandText)) - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) @@ -2538,7 +2536,7 @@ namespace Emby.Server.Implementations.Data var commandText = commandTextBuilder.ToString(); var items = new List<BaseItem>(); using (new QueryTimeLogger(Logger, commandText)) - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) @@ -2562,7 +2560,7 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, query.SkipDeserialization); if (item is not null) { items.Add(item); @@ -2746,7 +2744,7 @@ namespace Emby.Server.Implementations.Data var list = new List<BaseItem>(); var result = new QueryResult<BaseItem>(); - using var connection = GetConnection(); + using var connection = GetConnection(true); using var transaction = connection.BeginTransaction(); if (!isReturningZeroItems) { @@ -2774,7 +2772,7 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, false); if (item is not null) { list.Add(item); @@ -2928,7 +2926,7 @@ namespace Emby.Server.Implementations.Data var commandText = commandTextBuilder.ToString(); var list = new List<Guid>(); using (new QueryTimeLogger(Logger, commandText)) - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) @@ -4477,7 +4475,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type transaction.Commit(); } - private void ExecuteWithSingleParam(SqliteConnection db, string query, Guid value) + private void ExecuteWithSingleParam(ManagedConnection db, string query, Guid value) { using (var statement = PrepareStatement(db, query)) { @@ -4510,7 +4508,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type } var list = new List<string>(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText.ToString())) { // Run this again to bind the params @@ -4548,7 +4546,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type } var list = new List<PersonInfo>(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText.ToString())) { // Run this again to bind the params @@ -4633,7 +4631,7 @@ AND Type = @InternalPersonType)"); return whereClauses; } - private void UpdateAncestors(Guid itemId, List<Guid> ancestorIds, SqliteConnection db, SqliteCommand deleteAncestorsStatement) + private void UpdateAncestors(Guid itemId, List<Guid> ancestorIds, ManagedConnection db, SqliteCommand deleteAncestorsStatement) { if (itemId.IsEmpty()) { @@ -4788,7 +4786,7 @@ AND Type = @InternalPersonType)"); var list = new List<string>(); using (new QueryTimeLogger(Logger, commandText)) - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, commandText)) { foreach (var row in statement.ExecuteQuery()) @@ -4988,8 +4986,8 @@ AND Type = @InternalPersonType)"); var list = new List<(BaseItem, ItemCounts)>(); var result = new QueryResult<(BaseItem, ItemCounts)>(); using (new QueryTimeLogger(Logger, commandText)) - using (var connection = GetConnection()) - using (var transaction = connection.BeginTransaction(deferred: true)) + using (var connection = GetConnection(true)) + using (var transaction = connection.BeginTransaction()) { if (!isReturningZeroItems) { @@ -5021,7 +5019,7 @@ AND Type = @InternalPersonType)"); foreach (var row in statement.ExecuteQuery()) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, false); if (item is not null) { var countStartColumn = columns.Count - 1; @@ -5149,7 +5147,7 @@ AND Type = @InternalPersonType)"); return list; } - private void UpdateItemValues(Guid itemId, List<(int MagicNumber, string Value)> values, SqliteConnection db) + private void UpdateItemValues(Guid itemId, List<(int MagicNumber, string Value)> values, ManagedConnection db) { if (itemId.IsEmpty()) { @@ -5168,7 +5166,7 @@ AND Type = @InternalPersonType)"); InsertItemValues(itemId, values, db); } - private void InsertItemValues(Guid id, List<(int MagicNumber, string Value)> values, SqliteConnection db) + private void InsertItemValues(Guid id, List<(int MagicNumber, string Value)> values, ManagedConnection db) { const int Limit = 100; var startIndex = 0; @@ -5222,24 +5220,25 @@ AND Type = @InternalPersonType)"); throw new ArgumentNullException(nameof(itemId)); } - ArgumentNullException.ThrowIfNull(people); - CheckDisposed(); using var connection = GetConnection(); using var transaction = connection.BeginTransaction(); - // First delete chapters + // Delete all existing people first using var command = connection.CreateCommand(); command.CommandText = "delete from People where ItemId=@ItemId"; command.TryBind("@ItemId", itemId); command.ExecuteNonQuery(); - InsertPeople(itemId, people, connection); + if (people is not null) + { + InsertPeople(itemId, people, connection); + } transaction.Commit(); } - private void InsertPeople(Guid id, List<PersonInfo> people, SqliteConnection db) + private void InsertPeople(Guid id, List<PersonInfo> people, ManagedConnection db) { const int Limit = 100; var startIndex = 0; @@ -5335,7 +5334,7 @@ AND Type = @InternalPersonType)"); cmdText += " order by StreamIndex ASC"; - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) { var list = new List<MediaStream>(); @@ -5388,7 +5387,7 @@ AND Type = @InternalPersonType)"); transaction.Commit(); } - private void InsertMediaStreams(Guid id, IReadOnlyList<MediaStream> streams, SqliteConnection db) + private void InsertMediaStreams(Guid id, IReadOnlyList<MediaStream> streams, ManagedConnection db) { const int Limit = 10; var startIndex = 0; @@ -5722,7 +5721,7 @@ AND Type = @InternalPersonType)"); cmdText += " order by AttachmentIndex ASC"; var list = new List<MediaAttachment>(); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, cmdText)) { statement.TryBind("@ItemId", query.ItemId); @@ -5772,7 +5771,7 @@ AND Type = @InternalPersonType)"); private void InsertMediaAttachments( Guid id, IReadOnlyList<MediaAttachment> attachments, - SqliteConnection db, + ManagedConnection db, CancellationToken cancellationToken) { const int InsertAtOnce = 10; diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 20359e4ad..634eaf85e 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -86,7 +86,7 @@ namespace Emby.Server.Implementations.Data } } - private void ImportUserIds(SqliteConnection db, IEnumerable<User> users) + private void ImportUserIds(ManagedConnection db, IEnumerable<User> users) { var userIdsWithUserData = GetAllUserIdsWithUserData(db); @@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Data } } - private List<Guid> GetAllUserIdsWithUserData(SqliteConnection db) + private List<Guid> GetAllUserIdsWithUserData(ManagedConnection db) { var list = new List<Guid>(); @@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.Data } } - private static void SaveUserData(SqliteConnection db, long internalUserId, string key, UserItemData userData) + private static void SaveUserData(ManagedConnection db, long internalUserId, string key, UserItemData userData) { using (var statement = db.PrepareStatement("replace into UserDatas (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)")) { @@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.Data ArgumentException.ThrowIfNullOrEmpty(key); - using (var connection = GetConnection()) + using (var connection = GetConnection(true)) { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId")) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index cca835e4f..953fe19e0 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1029,7 +1029,7 @@ namespace Emby.Server.Implementations.Library } } - private async Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false) + public async Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false) { await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); @@ -2812,8 +2812,10 @@ namespace Emby.Server.Implementations.Library } _itemRepository.UpdatePeople(item.Id, people); - - await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false); + if (people is not null) + { + await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false); + } } public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex, bool removeOnFailure) diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 1bdae7f62..f7270bec1 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Emby.Naming.Audio; using Emby.Naming.Common; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities.Audio; @@ -85,6 +86,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } var albumResolver = new MusicAlbumResolver(_logger, _namingOptions, _directoryService); + var albumParser = new AlbumParser(_namingOptions); var directories = args.FileSystemChildren.Where(i => i.IsDirectory); @@ -100,6 +102,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } } + // If the folder is a multi-disc folder, then it is not an artist folder + if (albumParser.IsMultiPart(fileSystemInfo.FullName)) + { + return; + } + // If we contain a music album assume we are an artist folder if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, _directoryService)) { diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index ff4a88162..abf2d0115 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -54,7 +54,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV { IndexNumber = seasonParserResult.SeasonNumber, SeriesId = series.Id, - SeriesName = series.Name + SeriesName = series.Name, + Path = seasonParserResult.IsSeasonFolder ? path : null }; if (!season.IndexNumber.HasValue || !seasonParserResult.IsSeasonFolder) @@ -78,27 +79,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV } } - if (season.IndexNumber.HasValue) + if (season.IndexNumber.HasValue && string.IsNullOrEmpty(season.Name)) { var seasonNumber = season.IndexNumber.Value; - if (string.IsNullOrEmpty(season.Name)) - { - var seasonNames = series.GetSeasonNames(); - if (seasonNames.TryGetValue(seasonNumber, out var seasonName)) - { - season.Name = seasonName; - } - else - { - season.Name = seasonNumber == 0 ? - args.LibraryOptions.SeasonZeroDisplayName : - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("NameSeasonNumber"), - seasonNumber, - args.LibraryOptions.PreferredMetadataLanguage); - } - } + season.Name = seasonNumber == 0 ? + args.LibraryOptions.SeasonZeroDisplayName : + string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("NameSeasonNumber"), + seasonNumber, + args.LibraryOptions.PreferredMetadataLanguage); } return season; diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json index b5e2c9b6b..e871a4362 100644 --- a/Emby.Server.Implementations/Localization/Core/da.json +++ b/Emby.Server.Implementations/Localization/Core/da.json @@ -17,7 +17,7 @@ "Genres": "Genrer", "HeaderAlbumArtists": "Albumkunstnere", "HeaderContinueWatching": "Fortsæt afspilning", - "HeaderFavoriteAlbums": "Favoritalbummer", + "HeaderFavoriteAlbums": "Favoritalbum", "HeaderFavoriteArtists": "Favoritkunstnere", "HeaderFavoriteEpisodes": "Yndlingsafsnit", "HeaderFavoriteShows": "Yndlingsserier", @@ -87,21 +87,21 @@ "UserOnlineFromDevice": "{0} er online fra {1}", "UserPasswordChangedWithName": "Adgangskode er ændret for brugeren {0}", "UserPolicyUpdatedWithName": "Brugerpolitikken er blevet opdateret for {0}", - "UserStartedPlayingItemWithValues": "{0} har påbegyndt afspilning af {1}", + "UserStartedPlayingItemWithValues": "{0} afspiller {1} på {2}", "UserStoppedPlayingItemWithValues": "{0} har afsluttet afspilning af {1} på {2}", "ValueHasBeenAddedToLibrary": "{0} er blevet tilføjet til dit mediebibliotek", "ValueSpecialEpisodeName": "Special - {0}", "VersionNumber": "Version {0}", "TaskDownloadMissingSubtitlesDescription": "Søger på internettet efter manglende undertekster baseret på metadata-konfigurationen.", "TaskDownloadMissingSubtitles": "Hent manglende undertekster", - "TaskUpdatePluginsDescription": "Henter og installerer opdateringer for plugins, som er indstillet til at blive opdateret automatisk.", + "TaskUpdatePluginsDescription": "Henter og installerer opdateringer for plugins, som er konfigurerede til at blive opdateret automatisk.", "TaskUpdatePlugins": "Opdater Plugins", "TaskCleanLogsDescription": "Sletter log-filer som er mere end {0} dage gamle.", "TaskCleanLogs": "Ryd Log-mappe", "TaskRefreshLibraryDescription": "Scanner dit mediebibliotek for nye filer og opdateret metadata.", "TaskRefreshLibrary": "Scan Mediebibliotek", "TaskCleanCacheDescription": "Sletter cache-filer som systemet ikke længere bruger.", - "TaskCleanCache": "Ryd Cache-mappe", + "TaskCleanCache": "Ryd cache-mappe", "TasksChannelsCategory": "Internetkanaler", "TasksApplicationCategory": "Applikation", "TasksLibraryCategory": "Bibliotek", @@ -128,5 +128,7 @@ "TaskRefreshTrickplayImages": "Generér Trickplay Billeder", "TaskRefreshTrickplayImagesDescription": "Laver trickplay forhåndsvisninger for videoer i aktiverede biblioteker.", "TaskCleanCollectionsAndPlaylists": "Ryd op i samlinger og afspilningslister", - "TaskCleanCollectionsAndPlaylistsDescription": "Fjerner enheder fra samlinger og afspilningslister der ikke eksisterer længere." + "TaskCleanCollectionsAndPlaylistsDescription": "Fjerner elementer fra samlinger og afspilningslister der ikke eksisterer længere.", + "TaskAudioNormalizationDescription": "Skanner filer for data vedrørende audio-normalisering.", + "TaskAudioNormalization": "Audio-normalisering" } diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json index 68a0180eb..ce98979e6 100644 --- a/Emby.Server.Implementations/Localization/Core/de.json +++ b/Emby.Server.Implementations/Localization/Core/de.json @@ -126,7 +126,7 @@ "External": "Extern", "HearingImpaired": "Hörgeschädigt", "TaskRefreshTrickplayImages": "Trickplay-Bilder generieren", - "TaskRefreshTrickplayImagesDescription": "Erstellt eine Trickplay-Vorschau für Videos in aktivierten Bibliotheken.", + "TaskRefreshTrickplayImagesDescription": "Erstellt ein Trickplay-Vorschauen für Videos in aktivierten Bibliotheken.", "TaskCleanCollectionsAndPlaylists": "Sammlungen und Playlisten aufräumen", "TaskCleanCollectionsAndPlaylistsDescription": "Lösche nicht mehr vorhandene Einträge aus den Sammlungen und Playlisten.", "TaskAudioNormalization": "Audio Normalisierung", diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json index d4151adf3..e9ace71a5 100644 --- a/Emby.Server.Implementations/Localization/Core/es-MX.json +++ b/Emby.Server.Implementations/Localization/Core/es-MX.json @@ -11,7 +11,7 @@ "Collections": "Colecciones", "DeviceOfflineWithName": "{0} se ha desconectado", "DeviceOnlineWithName": "{0} está conectado", - "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}", + "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}", "Favorites": "Favoritos", "Folders": "Carpetas", "Genres": "Géneros", diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json index f9d62d54e..13e007b4c 100644 --- a/Emby.Server.Implementations/Localization/Core/es.json +++ b/Emby.Server.Implementations/Localization/Core/es.json @@ -11,7 +11,7 @@ "Collections": "Colecciones", "DeviceOfflineWithName": "{0} se ha desconectado", "DeviceOnlineWithName": "{0} está conectado", - "FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión desde {0}", + "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}", "Favorites": "Favoritos", "Folders": "Carpetas", "Genres": "Géneros", diff --git a/Emby.Server.Implementations/Localization/Core/es_419.json b/Emby.Server.Implementations/Localization/Core/es_419.json index c6863ff36..e7deefbb0 100644 --- a/Emby.Server.Implementations/Localization/Core/es_419.json +++ b/Emby.Server.Implementations/Localization/Core/es_419.json @@ -112,7 +112,7 @@ "CameraImageUploadedFrom": "Una nueva imagen de cámara ha sido subida desde {0}", "AuthenticationSucceededWithUserName": "{0} autenticado con éxito", "Application": "Aplicación", - "AppDeviceValues": "App: {0}, Dispositivo: {1}", + "AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}", "TaskCleanActivityLogDescription": "Elimina las entradas del registro de actividad anteriores al periodo configurado.", "TaskCleanActivityLog": "Limpiar registro de actividades", "Undefined": "Sin definir", @@ -125,5 +125,9 @@ "TaskKeyframeExtractor": "Extractor de Fotogramas Clave", "HearingImpaired": "Discapacidad auditiva", "TaskRefreshTrickplayImagesDescription": "Crea previsualizaciones para la barra de reproducción en las bibliotecas habilitadas.", - "TaskRefreshTrickplayImages": "Generar imágenes de la barra de reproducción" + "TaskRefreshTrickplayImages": "Generar imágenes de la barra de reproducción", + "TaskAudioNormalization": "Normalización de audio", + "TaskCleanCollectionsAndPlaylistsDescription": "Quita elementos que ya no existen de colecciones y listas de reproducción.", + "TaskAudioNormalizationDescription": "Analiza los archivos para normalizar el audio.", + "TaskCleanCollectionsAndPlaylists": "Limpieza de colecciones y listas de reproducción" } diff --git a/Emby.Server.Implementations/Localization/Core/es_DO.json b/Emby.Server.Implementations/Localization/Core/es_DO.json index 0f4c7438f..8cdd06b7c 100644 --- a/Emby.Server.Implementations/Localization/Core/es_DO.json +++ b/Emby.Server.Implementations/Localization/Core/es_DO.json @@ -12,14 +12,118 @@ "Application": "Aplicación", "AppDeviceValues": "App: {0}, Dispositivo: {1}", "HeaderContinueWatching": "Continuar Viendo", - "HeaderAlbumArtists": "Artistas del Álbum", + "HeaderAlbumArtists": "Artistas del álbum", "Genres": "Géneros", "Folders": "Carpetas", "Favorites": "Favoritos", - "FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido de {0}", + "FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido desde {0}", "HeaderFavoriteSongs": "Canciones Favoritas", "HeaderFavoriteEpisodes": "Episodios Favoritos", "HeaderFavoriteArtists": "Artistas Favoritos", "External": "Externo", - "Default": "Predeterminado" + "Default": "Predeterminado", + "Movies": "Películas", + "MessageNamedServerConfigurationUpdatedWithValue": "La sección {0} de la configuración ha sido actualizada", + "MixedContent": "Contenido mixto", + "Music": "Música", + "NotificationOptionCameraImageUploaded": "Imagen de la cámara subida", + "NotificationOptionServerRestartRequired": "Se necesita reiniciar el servidor", + "NotificationOptionVideoPlayback": "Reproducción de video iniciada", + "Sync": "Sincronizar", + "Shows": "Series", + "UserDownloadingItemWithValues": "{0} está descargando {1}", + "UserOfflineFromDevice": "{0} se ha desconectado desde {1}", + "UserOnlineFromDevice": "{0} está en línea desde {1}", + "TasksChannelsCategory": "Canales de Internet", + "TaskRefreshChannelsDescription": "Actualiza la información de canales de Internet.", + "TaskDownloadMissingSubtitles": "Descargar subtítulos faltantes", + "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.", + "TaskKeyframeExtractorDescription": "Extrae Fotogramas Clave de los archivos de vídeo para crear Listas de Reproducción HLS más precisas. Esta tarea puede durar mucho tiempo.", + "TaskAudioNormalization": "Normalización de audio", + "TaskAudioNormalizationDescription": "Escanear archivos para la normalización de data.", + "TaskCleanCollectionsAndPlaylists": "Limpiar colecciones y listas de reproducción", + "TaskCleanCollectionsAndPlaylistsDescription": "Remover elementos de colecciones y listas de reproducción que no existen.", + "TvShows": "Series de TV", + "UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}", + "TaskRefreshChannels": "Actualizar canales", + "Photos": "Fotos", + "HeaderFavoriteShows": "Programas favoritos", + "TaskCleanActivityLog": "Limpiar registro de actividades", + "UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}", + "System": "Sistema", + "User": "Usuario", + "Forced": "Forzado", + "PluginInstalledWithName": "{0} ha sido instalado", + "HeaderFavoriteAlbums": "Álbumes favoritos", + "TaskUpdatePlugins": "Actualizar Plugins", + "Latest": "Recientes", + "UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}", + "Songs": "Canciones", + "NotificationOptionPluginError": "Falla de plugin", + "ScheduledTaskStartedWithName": "{0} iniciado", + "TasksApplicationCategory": "Aplicación", + "UserDeletedWithName": "El usuario {0} ha sido eliminado", + "TaskRefreshChapterImages": "Extraer imágenes de los capítulos", + "TaskUpdatePluginsDescription": "Descarga e instala actualizaciones para plugins que están configurados para actualizarse automáticamente.", + "TaskRefreshPeopleDescription": "Actualiza metadatos de actores y directores en tu biblioteca de medios.", + "NotificationOptionUserLockedOut": "Usuario bloqueado", + "TaskCleanTranscodeDescription": "Elimina archivos transcodificados que tengan más de un día.", + "TaskCleanTranscode": "Limpiar el directorio de transcodificaciones", + "NotificationOptionPluginUpdateInstalled": "Actualización de plugin instalada", + "NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida", + "TasksLibraryCategory": "Biblioteca", + "NotificationOptionPluginInstalled": "Plugin instalado", + "UserPolicyUpdatedWithName": "La política de usuario ha sido actualizada para {0}", + "VersionNumber": "Versión {0}", + "HeaderNextUp": "A continuación", + "ValueHasBeenAddedToLibrary": "{0} se ha añadido a tu biblioteca", + "LabelIpAddressValue": "Dirección IP: {0}", + "NameSeasonNumber": "Temporada {0}", + "NotificationOptionNewLibraryContent": "Nuevo contenido agregado", + "Plugin": "Plugin", + "NotificationOptionAudioPlayback": "Reproducción de audio iniciada", + "NotificationOptionTaskFailed": "Falló la tarea programada", + "LabelRunningTimeValue": "Tiempo en ejecución: {0}", + "SubtitleDownloadFailureFromForItem": "Falló la descarga de subtítulos desde {0} para {1}", + "TaskRefreshLibrary": "Escanear biblioteca de medios", + "ServerNameNeedsToBeRestarted": "{0} debe ser reiniciado", + "TasksMaintenanceCategory": "Mantenimiento", + "ProviderValue": "Proveedor: {0}", + "UserCreatedWithName": "El usuario {0} ha sido creado", + "PluginUninstalledWithName": "{0} ha sido desinstalado", + "ValueSpecialEpisodeName": "Especial - {0}", + "ScheduledTaskFailedWithName": "{0} falló", + "TaskCleanLogs": "Limpiar directorio de registros", + "NameInstallFailed": "Falló la instalación de {0}", + "UserLockedOutWithName": "El usuario {0} ha sido bloqueado", + "TaskRefreshLibraryDescription": "Escanea tu biblioteca de medios para encontrar archivos nuevos y actualizar los metadatos.", + "StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo en un momento.", + "Playlists": "Listas de reproducción", + "TaskDownloadMissingSubtitlesDescription": "Busca subtítulos faltantes en Internet basándose en la configuración de metadatos.", + "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor", + "TaskRefreshPeople": "Actualizar personas", + "NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida", + "HeaderLiveTV": "TV en vivo", + "NameSeasonUnknown": "Temporada desconocida", + "NotificationOptionInstallationFailed": "Fallo de instalación", + "NotificationOptionPluginUninstalled": "Plugin desinstalado", + "TaskCleanCache": "Limpiar directorio caché", + "TaskRefreshChapterImagesDescription": "Crea miniaturas para videos que tienen capítulos.", + "Inherit": "Heredar", + "HeaderRecordingGroups": "Grupos de grabación", + "ItemAddedWithName": "{0} fue agregado a la biblioteca", + "TaskOptimizeDatabase": "Optimizar base de datos", + "TaskKeyframeExtractor": "Extractor de Fotogramas Clave", + "HearingImpaired": "Discapacidad auditiva", + "HomeVideos": "Videos caseros", + "ItemRemovedWithName": "{0} fue removido de la biblioteca", + "MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado", + "MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}", + "MusicVideos": "Videos musicales", + "NewVersionIsAvailable": "Una nueva versión de Jellyfin está disponible para descargar.", + "PluginUpdatedWithName": "{0} ha sido actualizado", + "Undefined": "Sin definir", + "TaskCleanActivityLogDescription": "Elimina las entradas del registro de actividad anteriores al periodo configurado.", + "TaskCleanCacheDescription": "Elimina archivos caché que ya no son necesarios para el sistema.", + "TaskCleanLogsDescription": "Elimina archivos de registro con más de {0} días de antigüedad." } diff --git a/Emby.Server.Implementations/Localization/Core/ga.json b/Emby.Server.Implementations/Localization/Core/ga.json index 28e54bff5..b511ed6ba 100644 --- a/Emby.Server.Implementations/Localization/Core/ga.json +++ b/Emby.Server.Implementations/Localization/Core/ga.json @@ -1,3 +1,16 @@ { - "Albums": "Albaim" + "Albums": "Albaim", + "Artists": "Ealaíontóir", + "AuthenticationSucceededWithUserName": "{0} fíordheimhnithe", + "Books": "leabhair", + "CameraImageUploadedFrom": "Tá íomhá ceamara nua uaslódáilte ó {0}", + "Channels": "Cainéil", + "ChapterNameValue": "Caibidil {0}", + "Collections": "Bailiúcháin", + "Default": "Mainneachtain", + "DeviceOfflineWithName": "scoireadh {0}", + "DeviceOnlineWithName": "{0} ceangailte", + "External": "Forimeallach", + "FailedLoginAttemptWithUserName": "Iarracht ar theip ar fhíordheimhniú ó {0}", + "Favorites": "Ceanáin" } diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json index 26eab392e..c8e036424 100644 --- a/Emby.Server.Implementations/Localization/Core/he.json +++ b/Emby.Server.Implementations/Localization/Core/he.json @@ -126,5 +126,9 @@ "External": "חיצוני", "HearingImpaired": "לקוי שמיעה", "TaskRefreshTrickplayImages": "יצירת תמונות המחשה", - "TaskRefreshTrickplayImagesDescription": "יוצר תמונות המחשה לסרטונים שפעילים בספריות." + "TaskRefreshTrickplayImagesDescription": "יוצר תמונות המחשה לסרטונים שפעילים בספריות.", + "TaskAudioNormalization": "נרמול שמע", + "TaskCleanCollectionsAndPlaylistsDescription": "מנקה פריטים לא קיימים מאוספים ורשימות השמעה.", + "TaskAudioNormalizationDescription": "מחפש קבצי נורמליזציה של שמע.", + "TaskCleanCollectionsAndPlaylists": "מנקה אוספים ורשימות השמעה" } diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json index 5d5bb3324..31d6aaedb 100644 --- a/Emby.Server.Implementations/Localization/Core/hu.json +++ b/Emby.Server.Implementations/Localization/Core/hu.json @@ -18,14 +18,14 @@ "HeaderAlbumArtists": "Album előadók", "HeaderContinueWatching": "Megtekintés folytatása", "HeaderFavoriteAlbums": "Kedvenc Albumok", - "HeaderFavoriteArtists": "Kedvenc előadók", - "HeaderFavoriteEpisodes": "Kedvenc epizódok", - "HeaderFavoriteShows": "Kedvenc sorozatok", - "HeaderFavoriteSongs": "Kedvenc dalok", + "HeaderFavoriteArtists": "Kedvenc Előadók", + "HeaderFavoriteEpisodes": "Kedvenc Epizódok", + "HeaderFavoriteShows": "Kedvenc Sorozatok", + "HeaderFavoriteSongs": "Kedvenc Dalok", "HeaderLiveTV": "Élő TV", "HeaderNextUp": "Következik", - "HeaderRecordingGroups": "Felvételi csoportok", - "HomeVideos": "Otthoni videók", + "HeaderRecordingGroups": "Felvevő Csoportok", + "HomeVideos": "Otthoni Videók", "Inherit": "Örökölt", "ItemAddedWithName": "{0} hozzáadva a könyvtárhoz", "ItemRemovedWithName": "{0} eltávolítva a könyvtárból", diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json index 78a443348..b925a482b 100644 --- a/Emby.Server.Implementations/Localization/Core/id.json +++ b/Emby.Server.Implementations/Localization/Core/id.json @@ -81,7 +81,7 @@ "Movies": "Film", "MessageServerConfigurationUpdated": "Konfigurasi server telah diperbarui", "MessageNamedServerConfigurationUpdatedWithValue": "Bagian konfigurasi server {0} telah diperbarui", - "FailedLoginAttemptWithUserName": "Gagal melakukan login dari {0}", + "FailedLoginAttemptWithUserName": "Gagal upaya login dari {0}", "CameraImageUploadedFrom": "Sebuah gambar kamera baru telah diunggah dari {0}", "DeviceOfflineWithName": "{0} telah terputus", "DeviceOnlineWithName": "{0} telah terhubung", @@ -125,5 +125,9 @@ "External": "Luar", "HearingImpaired": "Gangguan Pendengaran", "TaskRefreshTrickplayImages": "Hasilkan Gambar Trickplay", - "TaskRefreshTrickplayImagesDescription": "Buat pratinjau trickplay untuk video di perpustakaan yang diaktifkan." + "TaskRefreshTrickplayImagesDescription": "Buat pratinjau trickplay untuk video di perpustakaan yang diaktifkan.", + "TaskAudioNormalizationDescription": "Pindai file untuk data normalisasi audio.", + "TaskAudioNormalization": "Normalisasi Audio", + "TaskCleanCollectionsAndPlaylists": "Bersihkan koleksi dan daftar putar", + "TaskCleanCollectionsAndPlaylistsDescription": "Menghapus item dari koleksi dan daftar putar yang sudah tidak ada." } diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index 783aecec7..0e694af02 100644 --- a/Emby.Server.Implementations/Localization/Core/it.json +++ b/Emby.Server.Implementations/Localization/Core/it.json @@ -51,10 +51,10 @@ "NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata", "NotificationOptionInstallationFailed": "Installazione fallita", "NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto", - "NotificationOptionPluginError": "Errore del Plug-in", - "NotificationOptionPluginInstalled": "Plug-in installato", - "NotificationOptionPluginUninstalled": "Plug-in disinstallato", - "NotificationOptionPluginUpdateInstalled": "Aggiornamento del plug-in installato", + "NotificationOptionPluginError": "Errore del plugin", + "NotificationOptionPluginInstalled": "Plugin installato", + "NotificationOptionPluginUninstalled": "Plugin disinstallato", + "NotificationOptionPluginUpdateInstalled": "Aggiornamento plugin installato", "NotificationOptionServerRestartRequired": "Riavvio del server necessario", "NotificationOptionTaskFailed": "Operazione pianificata fallita", "NotificationOptionUserLockedOut": "Utente bloccato", @@ -68,10 +68,10 @@ "PluginUpdatedWithName": "{0} è stato aggiornato", "ProviderValue": "Provider: {0}", "ScheduledTaskFailedWithName": "{0} fallito", - "ScheduledTaskStartedWithName": "{0} avviati", + "ScheduledTaskStartedWithName": "{0} avviato", "ServerNameNeedsToBeRestarted": "{0} deve essere riavviato", "Shows": "Serie TV", - "Songs": "Canzoni", + "Songs": "Brani", "StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.", "SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}", "SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}", @@ -87,48 +87,48 @@ "UserOnlineFromDevice": "{0} è online su {1}", "UserPasswordChangedWithName": "La password è stata cambiata per l'utente {0}", "UserPolicyUpdatedWithName": "La policy dell'utente è stata aggiornata per {0}", - "UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di \"{1}\" su {2}", + "UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di {1} su {2}", "UserStoppedPlayingItemWithValues": "{0} ha interrotto la riproduzione di {1} su {2}", "ValueHasBeenAddedToLibrary": "{0} è stato aggiunto alla tua libreria multimediale", "ValueSpecialEpisodeName": "Speciale - {0}", "VersionNumber": "Versione {0}", - "TaskRefreshChannelsDescription": "Aggiorna le informazioni dei canali Internet.", + "TaskRefreshChannelsDescription": "Aggiorna le informazioni dei canali internet.", "TaskDownloadMissingSubtitlesDescription": "Cerca su internet i sottotitoli mancanti basandosi sulle configurazioni dei metadati.", "TaskDownloadMissingSubtitles": "Scarica i sottotitoli mancanti", - "TaskRefreshChannels": "Aggiorna i canali", - "TaskCleanTranscodeDescription": "Cancella i file di transcode più vecchi di un giorno.", - "TaskCleanTranscode": "Svuota la cartella del transcoding", - "TaskUpdatePluginsDescription": "Scarica e installa gli aggiornamenti per i plugin che sono stati configurati per essere aggiornati contemporaneamente.", - "TaskUpdatePlugins": "Aggiorna i Plugin", - "TaskRefreshPeopleDescription": "Aggiorna i metadati per gli attori e registi nella tua libreria multimediale.", - "TaskRefreshPeople": "Aggiornamento Persone", + "TaskRefreshChannels": "Aggiorna canali", + "TaskCleanTranscodeDescription": "Cancella i file di transcodifica più vecchi di un giorno.", + "TaskCleanTranscode": "Svuota la cartella della transcodifica", + "TaskUpdatePluginsDescription": "Scarica e installa gli aggiornamenti per i plugin configurati per l'aggiornamento automatico.", + "TaskUpdatePlugins": "Aggiorna i plugin", + "TaskRefreshPeopleDescription": "Aggiorna i metadati degli attori e registi nella tua libreria.", + "TaskRefreshPeople": "Aggiorna Persone", "TaskCleanLogsDescription": "Rimuovi i file di log più vecchi di {0} giorni.", "TaskCleanLogs": "Pulisci la cartella dei log", - "TaskRefreshLibraryDescription": "Analizza la tua libreria multimediale per nuovi file e rinnova i metadati.", - "TaskRefreshLibrary": "Scan Librerie", - "TaskRefreshChapterImagesDescription": "Crea le thumbnail per i video che hanno capitoli.", + "TaskRefreshLibraryDescription": "Scansiona la libreria alla ricerca di nuovi file e aggiorna i metadati.", + "TaskRefreshLibrary": "Scansione della libreria", + "TaskRefreshChapterImagesDescription": "Crea le miniature per i video che hanno capitoli.", "TaskRefreshChapterImages": "Estrai immagini capitolo", "TaskCleanCacheDescription": "Cancella i file di cache non più necessari al sistema.", - "TaskCleanCache": "Pulisci la directory della cache", + "TaskCleanCache": "Pulisci la cartella della cache", "TasksChannelsCategory": "Canali su Internet", "TasksApplicationCategory": "Applicazione", "TasksLibraryCategory": "Libreria", "TasksMaintenanceCategory": "Manutenzione", "TaskCleanActivityLog": "Attività di Registro Completate", - "TaskCleanActivityLogDescription": "Elimina gli inserimenti nel registro delle attività più vecchie dell’età configurata.", + "TaskCleanActivityLogDescription": "Elimina le voci del registro delle attività più vecchie dell’età configurata.", "Undefined": "Non Definito", "Forced": "Forzato", "Default": "Predefinito", - "TaskOptimizeDatabaseDescription": "Compatta Database e tronca spazi liberi. Eseguire questa azione dopo la scansione o dopo aver fatto altri cambiamenti inerenti il database potrebbe aumentarne la performance.", - "TaskOptimizeDatabase": "Ottimizza Database", + "TaskOptimizeDatabaseDescription": "Compatta database e tronca spazi liberi. Eseguire questa azione dopo la scansione o dopo aver fatto altre modifiche inerenti il database potrebbe aumentarne le prestazioni.", + "TaskOptimizeDatabase": "Ottimizza database", "TaskKeyframeExtractor": "Estrattore di Keyframe", "TaskKeyframeExtractorDescription": "Estrae i keyframe dai video per creare migliori playlist HLS. Questa procedura potrebbe richiedere molto tempo.", "External": "Esterno", - "HearingImpaired": "con problemi di udito", + "HearingImpaired": "Non Udenti", "TaskRefreshTrickplayImages": "Genera immagini Trickplay", "TaskRefreshTrickplayImagesDescription": "Crea anteprime trickplay per i video nelle librerie abilitate.", - "TaskCleanCollectionsAndPlaylists": "Ripulire le raccolte e le playlist", - "TaskCleanCollectionsAndPlaylistsDescription": "Rimuove gli elementi dalle raccolte e dalle playlist che non esistono più.", - "TaskAudioNormalization": "Normalizzazione Audio", - "TaskAudioNormalizationDescription": "Scansione files per normalizzazione audio." + "TaskCleanCollectionsAndPlaylists": "Ripulire le collezioni e le playlist", + "TaskCleanCollectionsAndPlaylistsDescription": "Rimuove gli elementi dalle collezioni e dalle playlist che non esistono più.", + "TaskAudioNormalization": "Normalizzazione dell'audio", + "TaskAudioNormalizationDescription": "Scansiona i file alla ricerca dei dati per la normalizzazione dell'audio." } diff --git a/Emby.Server.Implementations/Localization/Core/lv.json b/Emby.Server.Implementations/Localization/Core/lv.json index 6e58ef834..78c3d0a40 100644 --- a/Emby.Server.Implementations/Localization/Core/lv.json +++ b/Emby.Server.Implementations/Localization/Core/lv.json @@ -17,7 +17,7 @@ "Inherit": "Pārmantot", "AppDeviceValues": "Lietotne: {0}, Ierīce: {1}", "VersionNumber": "Versija {0}", - "ValueHasBeenAddedToLibrary": "{0} ir ticis pievienots jūsu multvides bibliotēkai", + "ValueHasBeenAddedToLibrary": "{0} tika pievienots jūsu multvides bibliotēkai", "UserStoppedPlayingItemWithValues": "{0} ir beidzis atskaņot {1} uz {2}", "UserStartedPlayingItemWithValues": "{0} atskaņo {1} uz {2}", "UserPasswordChangedWithName": "Lietotāja {0} parole tika nomainīta", @@ -76,7 +76,7 @@ "Genres": "Žanri", "Folders": "Mapes", "Favorites": "Izlase", - "FailedLoginAttemptWithUserName": "Neizdevies ieiešanas mēģinājums no {0}", + "FailedLoginAttemptWithUserName": "Neveiksmīgs ielogošanos mēģinājums no {0}", "DeviceOnlineWithName": "Savienojums ar {0} ir izveidots", "DeviceOfflineWithName": "Savienojums ar {0} ir pārtraukts", "Collections": "Kolekcijas", @@ -95,7 +95,7 @@ "TaskRefreshChapterImages": "Izvilkt nodaļu attēlus", "TasksApplicationCategory": "Lietotne", "TasksLibraryCategory": "Bibliotēka", - "TaskDownloadMissingSubtitlesDescription": "Internetā meklē trūkstošus subtitrus balstoties uz metadatu uzstādījumiem.", + "TaskDownloadMissingSubtitlesDescription": "Meklē trūkstošus subtitrus internēta balstoties uz metadatu uzstādījumiem.", "TaskDownloadMissingSubtitles": "Lejupielādēt trūkstošos subtitrus", "TaskRefreshChannelsDescription": "Atjauno interneta kanālu informāciju.", "TaskRefreshChannels": "Atjaunot kanālus", @@ -105,8 +105,8 @@ "TaskUpdatePlugins": "Atjaunot paplašinājumus", "TaskRefreshPeopleDescription": "Atjauno metadatus aktieriem un direktoriem jūsu multivides bibliotēkā.", "TaskRefreshPeople": "Atjaunot cilvēkus", - "TaskCleanLogsDescription": "Nodzēš logdatnes, kas ir senākas par {0} dienām.", - "TaskCleanLogs": "Iztīrīt logdatņu mapi", + "TaskCleanLogsDescription": "Nodzēš žurnāla ierakstus, kas ir senāki par {0} dienām.", + "TaskCleanLogs": "Iztīrīt žurnālu mapi", "TaskRefreshLibraryDescription": "Skenē jūsu multivides bibliotēku, lai atrastu jaunas datnes, un atsvaidzina metadatus.", "TaskRefreshLibrary": "Skenēt multivides bibliotēku", "TaskRefreshChapterImagesDescription": "Izveido sīktēlus priekš video ar sadaļām.", @@ -125,5 +125,9 @@ "TaskKeyframeExtractor": "Atslēgkadru ekstraktors", "TaskKeyframeExtractorDescription": "Ekstraktē atslēgkadrus no video failiem lai izveidotu precīzākus HLS atskaņošanas sarakstus. Šis process var būt ilgs.", "TaskRefreshTrickplayImages": "Ģenerēt partīšanas attēlus", - "TaskRefreshTrickplayImagesDescription": "Izveido priekšskatījumus videoklipu pārtīšanai iespējotajās bibliotēkās." + "TaskRefreshTrickplayImagesDescription": "Izveido priekšskatījumus videoklipu pārtīšanai iespējotajās bibliotēkās.", + "TaskAudioNormalization": "Audio normalizācija", + "TaskCleanCollectionsAndPlaylistsDescription": "Noņem elemēntus no kolekcijām un atskaņošanas sarakstiem, kuri vairs neeksistē.", + "TaskAudioNormalizationDescription": "Skanē failus priekš audio normālizācijas informācijas.", + "TaskCleanCollectionsAndPlaylists": "Notīrīt kolekcijas un atskaņošanas sarakstus" } diff --git a/Emby.Server.Implementations/Localization/Core/ml.json b/Emby.Server.Implementations/Localization/Core/ml.json index 28c7dd190..5c3449381 100644 --- a/Emby.Server.Implementations/Localization/Core/ml.json +++ b/Emby.Server.Implementations/Localization/Core/ml.json @@ -6,7 +6,7 @@ "ChapterNameValue": "അധ്യായം {0}", "DeviceOfflineWithName": "{0} വിച്ഛേദിച്ചു", "DeviceOnlineWithName": "{0} ബന്ധിപ്പിച്ചു", - "FailedLoginAttemptWithUserName": "{0} - എന്നതിൽ നിന്നുള്ള പ്രവേശന ശ്രമം പരാജയപ്പെട്ടു", + "FailedLoginAttemptWithUserName": "{0}ൽ നിന്നുള്ള പ്രവേശന ശ്രമം പരാജയപ്പെട്ടു", "Forced": "നിർബന്ധിച്ചു", "HeaderFavoriteAlbums": "പ്രിയപ്പെട്ട ആൽബങ്ങൾ", "HeaderFavoriteArtists": "പ്രിയപ്പെട്ട കലാകാരന്മാർ", @@ -125,5 +125,9 @@ "TaskKeyframeExtractorDescription": "കൂടുതൽ കൃത്യമായ HLS പ്ലേലിസ്റ്റുകൾ സൃഷ്ടിക്കുന്നതിന് വീഡിയോ ഫയലുകളിൽ നിന്ന് കീഫ്രെയിമുകൾ എക്സ്ട്രാക്റ്റ് ചെയ്യുന്നു. ഈ പ്രവർത്തനം പൂർത്തിയാവാൻ കുറച്ചധികം സമയം എടുത്തേക്കാം.", "TaskKeyframeExtractor": "കീഫ്രെയിം എക്സ്ട്രാക്റ്റർ", "TaskCleanCollectionsAndPlaylistsDescription": "നിലവിലില്ലാത്ത ശേഖരങ്ങളിൽ നിന്നും പ്ലേലിസ്റ്റുകളിൽ നിന്നും ഇനങ്ങൾ നീക്കംചെയ്യുന്നു.", - "TaskCleanCollectionsAndPlaylists": "ശേഖരങ്ങളും പ്ലേലിസ്റ്റുകളും വൃത്തിയാക്കുക" + "TaskCleanCollectionsAndPlaylists": "ശേഖരങ്ങളും പ്ലേലിസ്റ്റുകളും വൃത്തിയാക്കുക", + "TaskAudioNormalization": "സാധാരണ ശബ്ദ നിലയിലെത്തിലെത്തിക്കുക", + "TaskAudioNormalizationDescription": "സാധാരണ ശബ്ദ നിലയിലെത്തിലെത്തിക്കുന്ന ഡാറ്റയ്ക്കായി ഫയലുകൾ സ്കാൻ ചെയ്യുക.", + "TaskRefreshTrickplayImages": "ട്രിക്ക് പ്ലേ ചിത്രങ്ങൾ സൃഷ്ടിക്കുക", + "TaskRefreshTrickplayImagesDescription": "പ്രവർത്തനക്ഷമമാക്കിയ ലൈബ്രറികളിൽ വീഡിയോകൾക്കായി ട്രിക്ക്പ്ലേ പ്രിവ്യൂകൾ സൃഷ്ടിക്കുന്നു." } diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index b6c15d871..b66818ddc 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -126,5 +126,9 @@ "External": "Ekstern", "HearingImpaired": "Hørselshemmet", "TaskRefreshTrickplayImages": "Generer Trickplay bilder", - "TaskRefreshTrickplayImagesDescription": "Oppretter trickplay-forhåndsvisninger for videoer i aktiverte biblioteker." + "TaskRefreshTrickplayImagesDescription": "Oppretter trickplay-forhåndsvisninger for videoer i aktiverte biblioteker.", + "TaskCleanCollectionsAndPlaylists": "Rydd kolleksjoner og spillelister", + "TaskAudioNormalization": "Lyd Normalisering", + "TaskAudioNormalizationDescription": "Skan filer for lyd normaliserende data", + "TaskCleanCollectionsAndPlaylistsDescription": "Fjerner elementer fra kolleksjoner og spillelister som ikke lengere finnes" } diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json index 537a6d3f2..cd0120fc7 100644 --- a/Emby.Server.Implementations/Localization/Core/ro.json +++ b/Emby.Server.Implementations/Localization/Core/ro.json @@ -78,7 +78,7 @@ "Genres": "Genuri", "Folders": "Dosare", "Favorites": "Favorite", - "FailedLoginAttemptWithUserName": "Încercare de conectare nereușită de la {0}", + "FailedLoginAttemptWithUserName": "Încercare de conectare eșuată pentru {0}", "DeviceOnlineWithName": "{0} este conectat", "DeviceOfflineWithName": "{0} s-a deconectat", "Collections": "Colecții", diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json index 2cf0a04e0..f40c4478a 100644 --- a/Emby.Server.Implementations/Localization/Core/sv.json +++ b/Emby.Server.Implementations/Localization/Core/sv.json @@ -127,7 +127,8 @@ "HearingImpaired": "Hörselskadad", "TaskRefreshTrickplayImages": "Generera Trickplay-bilder", "TaskRefreshTrickplayImagesDescription": "Skapar trickplay-förhandsvisningar för videor i aktiverade bibliotek.", - "TaskCleanCollectionsAndPlaylists": "Rensa samlingar och spellistor", + "TaskCleanCollectionsAndPlaylists": "Rensa upp samlingar och spellistor", "TaskAudioNormalization": "Ljudnormalisering", - "TaskCleanCollectionsAndPlaylistsDescription": "Tar bort objekt från samlingar och spellistor som inte längre finns." + "TaskCleanCollectionsAndPlaylistsDescription": "Tar bort objekt från samlingar och spellistor som inte längre finns.", + "TaskAudioNormalizationDescription": "Skannar filer för ljudnormaliseringsdata." } diff --git a/Emby.Server.Implementations/Localization/Core/uz.json b/Emby.Server.Implementations/Localization/Core/uz.json index 43935f224..a1b3035f3 100644 --- a/Emby.Server.Implementations/Localization/Core/uz.json +++ b/Emby.Server.Implementations/Localization/Core/uz.json @@ -8,5 +8,20 @@ "Channels": "Kanallar", "Books": "Kitoblar", "Artists": "Ijrochilar", - "Albums": "Albomlar" + "Albums": "Albomlar", + "AuthenticationSucceededWithUserName": "{0} muvaffaqiyatli tasdiqlandi", + "AppDeviceValues": "Ilova: {0}, Qurilma: {1}", + "Application": "Ilova", + "CameraImageUploadedFrom": "{0}dan yangi kamera rasmi yuklandi", + "DeviceOnlineWithName": "{0} ulangan", + "ItemRemovedWithName": "{0} kutbxonadan o'chirildi", + "External": "Tashqi", + "FailedLoginAttemptWithUserName": "Muvafaqiyatsiz kirishlar soni {0}", + "Forced": "Majburiy", + "ChapterNameValue": "{0}chi bo'lim", + "DeviceOfflineWithName": "{0} aloqa uzildi", + "HeaderLiveTV": "Jonli TV", + "HeaderNextUp": "Keyingisi", + "ItemAddedWithName": "{0} kutbxonaga qo'shildi", + "LabelIpAddressValue": "IP manzil: {0}" } diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json index af9b54ad1..4bedfe3b2 100644 --- a/Emby.Server.Implementations/Localization/Core/vi.json +++ b/Emby.Server.Implementations/Localization/Core/vi.json @@ -103,11 +103,11 @@ "HeaderFavoriteEpisodes": "Tập Phim Yêu Thích", "HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích", "HeaderFavoriteAlbums": "Album Ưa Thích", - "FailedLoginAttemptWithUserName": "Đăng nhập không thành công thử từ {0}", + "FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập không thành công từ {0}", "DeviceOnlineWithName": "{0} đã kết nối", "DeviceOfflineWithName": "{0} đã ngắt kết nối", "ChapterNameValue": "Phân Cảnh {0}", - "Channels": "Các Kênh", + "Channels": "Kênh", "CameraImageUploadedFrom": "Một hình ảnh máy ảnh mới đã được tải lên từ {0}", "Books": "Sách", "AuthenticationSucceededWithUserName": "{0} xác thực thành công", @@ -127,5 +127,7 @@ "TaskRefreshTrickplayImages": "Tạo Ảnh Xem Trước Trickplay", "TaskRefreshTrickplayImagesDescription": "Tạo bản xem trước trịckplay cho video trong thư viện đã bật.", "TaskCleanCollectionsAndPlaylists": "Dọn dẹp bộ sưu tập và danh sách phát", - "TaskCleanCollectionsAndPlaylistsDescription": "Xóa các mục khỏi bộ sưu tập và danh sách phát không còn tồn tại." + "TaskCleanCollectionsAndPlaylistsDescription": "Xóa các mục khỏi bộ sưu tập và danh sách phát không còn tồn tại.", + "TaskAudioNormalization": "Chuẩn Hóa Âm Thanh", + "TaskAudioNormalizationDescription": "Quét tập tin để tìm dữ liệu chuẩn hóa âm thanh." } diff --git a/Emby.Server.Implementations/Localization/Core/zh-TW.json b/Emby.Server.Implementations/Localization/Core/zh-TW.json index 4f77eea3b..f06bbc591 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-TW.json +++ b/Emby.Server.Implementations/Localization/Core/zh-TW.json @@ -127,5 +127,7 @@ "TaskRefreshTrickplayImages": "生成快轉縮圖", "TaskRefreshTrickplayImagesDescription": "為啟用快轉縮圖的媒體庫生成快轉縮圖。", "TaskCleanCollectionsAndPlaylists": "清理系列和播放清單", - "TaskCleanCollectionsAndPlaylistsDescription": "清理系列和播放清單中已不存在的項目。" + "TaskCleanCollectionsAndPlaylistsDescription": "清理系列和播放清單中已不存在的項目。", + "TaskAudioNormalization": "音量標準化", + "TaskAudioNormalizationDescription": "掃描文件以找出音量標準化資料。" } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs index 04d6ed0f2..7f3a8e291 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -8,6 +8,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -69,7 +70,7 @@ public partial class AudioNormalizationTask : IScheduledTask /// <inheritdoc /> public string Key => "AudioNormalization"; - [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")] + [GeneratedRegex(@"^\s+I:\s+(.*?)\s+LUFS")] private static partial Regex LUFSRegex(); /// <inheritdoc /> @@ -179,16 +180,17 @@ public partial class AudioNormalizationTask : IScheduledTask } using var reader = process.StandardError; - var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - MatchCollection split = LUFSRegex().Matches(output); - - if (split.Count != 0) + await foreach (var line in reader.ReadAllLinesAsync(cancellationToken)) { - return float.Parse(split[0].Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + Match match = LUFSRegex().Match(line); + + if (match.Success) + { + return float.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + } } - _logger.LogError("Failed to find LUFS value in output:\n{Output}", output); + _logger.LogError("Failed to find LUFS value in output"); return null; } } diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 10d5b4f97..3dda5fdee 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1202,7 +1202,8 @@ namespace Emby.Server.Implementations.Session new DtoOptions(false) { EnableImages = false - }) + }, + user.DisplayMissingEpisodes) .Where(i => !i.IsVirtualItem) .SkipWhile(i => !i.Id.Equals(episode.Id)) .ToList(); diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 34c9e86f2..c1a615666 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.TV } string? presentationUniqueKey = null; - int? limit = null; + int? limit = request.Limit; if (!request.SeriesId.IsNullOrEmpty()) { if (_libraryManager.GetItemById(request.SeriesId.Value) is Series series) |
