diff options
Diffstat (limited to 'Emby.Server.Implementations')
27 files changed, 296 insertions, 208 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8ed51a194..e7efc81d7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -47,6 +47,7 @@ using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Udp; using Emby.Server.Implementations.Updates; using Jellyfin.Api.Helpers; +using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.Networking.Configuration; using Jellyfin.Networking.Manager; using MediaBrowser.Common; @@ -973,7 +974,7 @@ namespace Emby.Server.Implementations yield return typeof(IServerApplicationHost).Assembly; // Include composable parts in the Providers assembly - yield return typeof(ProviderUtils).Assembly; + yield return typeof(ProviderManager).Assembly; // Include composable parts in the Photos assembly yield return typeof(PhotoProvider).Assembly; @@ -999,6 +1000,9 @@ namespace Emby.Server.Implementations // Network yield return typeof(NetworkManager).Assembly; + // Hls + yield return typeof(DynamicHlsPlaylistGenerator).Assembly; + foreach (var i in GetAssembliesWithPartsInternal()) { yield return i; diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 43c8a451b..a107e7a52 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -264,11 +264,10 @@ namespace Emby.Server.Implementations.Channels } } - return new QueryResult<Channel> - { - Items = all, - TotalRecordCount = totalCount - }; + return new QueryResult<Channel>( + query.StartIndex, + totalCount, + all); } /// <inheritdoc /> @@ -285,11 +284,10 @@ namespace Emby.Server.Implementations.Channels // TODO Fix The co-variant conversion (internalResult.Items) between Folder[] and BaseItem[], this can generate runtime issues. var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user); - var result = new QueryResult<BaseItemDto> - { - Items = returnItems, - TotalRecordCount = internalResult.TotalRecordCount - }; + var result = new QueryResult<BaseItemDto>( + query.StartIndex, + internalResult.TotalRecordCount, + returnItems); return result; } @@ -333,7 +331,7 @@ namespace Emby.Server.Implementations.Channels private Channel GetChannelEntity(IChannel channel) { - return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).Result; + return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).GetAwaiter().GetResult(); } private MediaSourceInfo[] GetSavedMediaSources(BaseItem item) @@ -620,11 +618,10 @@ namespace Emby.Server.Implementations.Channels var returnItems = _dtoService.GetBaseItemDtos(items, query.DtoOptions, query.User); - var result = new QueryResult<BaseItemDto> - { - Items = returnItems, - TotalRecordCount = totalRecordCount - }; + var result = new QueryResult<BaseItemDto>( + query.StartIndex, + totalRecordCount, + returnItems); return result; } @@ -786,11 +783,10 @@ namespace Emby.Server.Implementations.Channels var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, query.DtoOptions, query.User); - var result = new QueryResult<BaseItemDto> - { - Items = returnItems, - TotalRecordCount = internalResult.TotalRecordCount - }; + var result = new QueryResult<BaseItemDto>( + query.StartIndex, + internalResult.TotalRecordCount, + returnItems); return result; } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 5ab9e02fe..1da9b4650 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2810,11 +2810,10 @@ namespace Emby.Server.Implementations.Data if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0)) { var returnList = GetItemList(query); - return new QueryResult<BaseItem> - { - Items = returnList, - TotalRecordCount = returnList.Count - }; + return new QueryResult<BaseItem>( + query.StartIndex, + returnList.Count, + returnList); } var now = DateTime.UtcNow; @@ -2978,6 +2977,7 @@ namespace Emby.Server.Implementations.Data ReadTransactionMode); } + result.StartIndex = query.StartIndex ?? 0; result.Items = list; return result; } @@ -3265,11 +3265,10 @@ namespace Emby.Server.Implementations.Data if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0)) { var returnList = GetItemIdsList(query); - return new QueryResult<Guid> - { - Items = returnList, - TotalRecordCount = returnList.Count - }; + return new QueryResult<Guid>( + query.StartIndex, + returnList.Count, + returnList); } var now = DateTime.UtcNow; @@ -3395,6 +3394,7 @@ namespace Emby.Server.Implementations.Data LogQueryTime("GetItemIds", commandText, now); + result.StartIndex = query.StartIndex ?? 0; result.Items = list; return result; } @@ -5599,6 +5599,7 @@ AND Type = @InternalPersonType)"); result.TotalRecordCount = list.Count; } + result.StartIndex = query.StartIndex ?? 0; result.Items = list; return result; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 7ba34e74a..f5ca006dd 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -458,11 +458,6 @@ namespace Emby.Server.Implementations.Dto } } - private string GetDtoId(BaseItem item) - { - return item.Id.ToString("N", CultureInfo.InvariantCulture); - } - private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item) { if (!string.IsNullOrEmpty(item.Album)) @@ -584,7 +579,7 @@ namespace Emby.Server.Implementations.Dto if (dictionary.TryGetValue(person.Name, out Person entity)) { baseItemPerson.PrimaryImageTag = GetTagAndFillBlurhash(dto, entity, ImageType.Primary); - baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture); + baseItemPerson.Id = entity.Id; if (dto.ImageBlurHashes != null) { // Only add BlurHash for the person's image. @@ -1102,12 +1097,13 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.LocalTrailerCount)) { - allExtras ??= item.GetExtras().ToArray(); - dto.LocalTrailerCount = allExtras.Count(i => i.ExtraType == ExtraType.Trailer); - if (item is IHasTrailers hasTrailers) { - dto.LocalTrailerCount += hasTrailers.GetTrailerCount(); + dto.LocalTrailerCount = hasTrailers.GetTrailerCount(); + } + else + { + dto.LocalTrailerCount = (allExtras ?? item.GetExtras()).Count(i => i.ExtraType == ExtraType.Trailer); } } @@ -1323,7 +1319,7 @@ namespace Emby.Server.Implementations.Dto if (image != null) { - dto.ParentLogoItemId = GetDtoId(parent); + dto.ParentLogoItemId = parent.Id; dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image); } } @@ -1334,7 +1330,7 @@ namespace Emby.Server.Implementations.Dto if (image != null) { - dto.ParentArtItemId = GetDtoId(parent); + dto.ParentArtItemId = parent.Id; dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image); } } @@ -1345,7 +1341,7 @@ namespace Emby.Server.Implementations.Dto if (image != null) { - dto.ParentThumbItemId = GetDtoId(parent); + dto.ParentThumbItemId = parent.Id; dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image); } } @@ -1356,7 +1352,7 @@ namespace Emby.Server.Implementations.Dto if (images.Count > 0) { - dto.ParentBackdropItemId = GetDtoId(parent); + dto.ParentBackdropItemId = parent.Id; dto.ParentBackdropImageTags = GetTagsAndFillBlurhashes(dto, parent, ImageType.Backdrop, images); } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 1e09a98cf..3226a3b19 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -31,7 +31,7 @@ <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" 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="prometheus-net.DotNetRuntime" Version="4.2.3" /> <PackageReference Include="sharpcompress" Version="0.30.1" /> <PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" /> <PackageReference Include="DotNet.Glob" Version="3.1.3" /> @@ -55,6 +55,10 @@ <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> + <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> + </PackageReference> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index 7958eb8f5..8a0e627b9 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -42,6 +42,10 @@ namespace Emby.Server.Implementations.Images { includeItemTypes = new[] { BaseItemKind.MusicAlbum }; } + else if (string.Equals(viewType, CollectionType.MusicVideos, StringComparison.Ordinal)) + { + includeItemTypes = new[] { BaseItemKind.MusicVideo }; + } else if (string.Equals(viewType, CollectionType.Books, StringComparison.Ordinal)) { includeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook }; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index bd0c178fd..064fd2372 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1360,10 +1360,10 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItems(query); } - return new QueryResult<BaseItem> - { - Items = _itemRepository.GetItemList(query) - }; + return new QueryResult<BaseItem>( + query.StartIndex, + null, + _itemRepository.GetItemList(query)); } public List<Guid> GetItemIds(InternalItemsQuery query) @@ -1493,10 +1493,10 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItems(query); } - return new QueryResult<BaseItem> - { - Items = _itemRepository.GetItemList(query) - }; + return new QueryResult<BaseItem>( + query.StartIndex, + null, + _itemRepository.GetItemList(query)); } private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents) @@ -2014,16 +2014,16 @@ namespace Emby.Server.Implementations.Library public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) => UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken); - public Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason) + public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason) { if (item.IsFileProtocol) { - ProviderManager.SaveMetadata(item, updateReason); + await ProviderManager.SaveMetadataAsync(item, updateReason).ConfigureAwait(false); } item.DateLastSaved = DateTime.UtcNow; - return UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate); + await UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); } /// <summary> @@ -2686,7 +2686,7 @@ namespace Emby.Server.Implementations.Library }; } - public IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) + public IEnumerable<BaseItem> FindExtras(BaseItem owner, IReadOnlyList<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) { var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions); if (ownerVideoInfo == null) diff --git a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs index 3d06ceb5e..807913b5d 100644 --- a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs @@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Library.Resolvers private readonly IItemResolver[] _videoResolvers; /// <summary> - /// Initializes an new instance of the <see cref="ExtraResolver"/> class. + /// Initializes a new instance of the <see cref="ExtraResolver"/> class. /// </summary> /// <param name="namingOptions">An instance of <see cref="NamingOptions"/>.</param> public ExtraResolver(NamingOptions namingOptions) diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 1a9295dc8..be1460928 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies CollectionType.Movies, CollectionType.HomeVideos, CollectionType.MusicVideos, - CollectionType.Movies, + CollectionType.TvShows, CollectionType.Photos }; @@ -128,10 +128,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return movie?.ExtraType == null ? movie : null; } - // Owned items will be caught by the video extra resolver if (args.Parent == null) { - return null; + return base.Resolve(args); } if (IsInvalid(args.Parent, collectionType)) @@ -222,6 +221,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return ResolveVideos<Movie>(parent, files, true, collectionType, true); } + if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) + { + return ResolveVideos<Episode>(parent, files, true, collectionType, true); + } + return null; } diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 55911933a..70d9cbc98 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -48,12 +48,10 @@ namespace Emby.Server.Implementations.Library results = results.GetRange(0, Math.Min(query.Limit.Value, results.Count)); } - return new QueryResult<SearchHintInfo> - { - TotalRecordCount = totalRecordCount, - - Items = results - }; + return new QueryResult<SearchHintInfo>( + query.StartIndex, + totalRecordCount, + results); } private static void AddIfMissing(List<BaseItemKind> list, BaseItemKind value) diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs new file mode 100644 index 000000000..320685b1f --- /dev/null +++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.Library; + +/// <summary> +/// The splashscreen post scan task. +/// </summary> +public class SplashscreenPostScanTask : ILibraryPostScanTask +{ + private readonly IItemRepository _itemRepository; + private readonly IImageEncoder _imageEncoder; + private readonly ILogger<SplashscreenPostScanTask> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="SplashscreenPostScanTask"/> class. + /// </summary> + /// <param name="itemRepository">Instance of the <see cref="IItemRepository"/> interface.</param> + /// <param name="imageEncoder">Instance of the <see cref="IImageEncoder"/> interface.</param> + /// <param name="logger">Instance of the <see cref="ILogger{SplashscreenPostScanTask}"/> interface.</param> + public SplashscreenPostScanTask( + IItemRepository itemRepository, + IImageEncoder imageEncoder, + ILogger<SplashscreenPostScanTask> logger) + { + _itemRepository = itemRepository; + _imageEncoder = imageEncoder; + _logger = logger; + } + + /// <inheritdoc /> + public Task Run(IProgress<double> progress, CancellationToken cancellationToken) + { + var posters = GetItemsWithImageType(ImageType.Primary).Select(x => x.GetImages(ImageType.Primary).First().Path).ToList(); + var backdrops = GetItemsWithImageType(ImageType.Thumb).Select(x => x.GetImages(ImageType.Thumb).First().Path).ToList(); + if (backdrops.Count == 0) + { + // Thumb images fit better because they include the title in the image but are not provided with TMDb. + // Using backdrops as a fallback to generate an image at all + _logger.LogDebug("No thumb images found. Using backdrops to generate splashscreen"); + backdrops = GetItemsWithImageType(ImageType.Backdrop).Select(x => x.GetImages(ImageType.Backdrop).First().Path).ToList(); + } + + _imageEncoder.CreateSplashscreen(posters, backdrops); + return Task.CompletedTask; + } + + private IReadOnlyList<BaseItem> GetItemsWithImageType(ImageType imageType) + { + // TODO make included libraries configurable + return _itemRepository.GetItemList(new InternalItemsQuery + { + CollapseBoxSetItems = false, + Recursive = true, + DtoOptions = new DtoOptions(false), + ImageTypes = new[] { imageType }, + Limit = 30, + // TODO max parental rating configurable + MaxParentalRating = 10, + OrderBy = new[] + { + (ItemSortBy.Random, SortOrder.Ascending) + }, + IncludeItemTypes = new[] { BaseItemKind.Movie, BaseItemKind.Series } + }); + } +} diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 6937cc097..b2d25fdae 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + await using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -56,14 +56,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV using var durationToken = new CancellationTokenSource(duration); using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); var linkedCancellationToken = cancellationTokenSource.Token; - - await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream()); - await _streamHelper.CopyToAsync( - fileStream, - output, - IODefaults.CopyToBufferSize, - 1000, - linkedCancellationToken).ConfigureAwait(false); + var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream()); + await using (fileStream.ConfigureAwait(false)) + { + await _streamHelper.CopyToAsync( + fileStream, + output, + IODefaults.CopyToBufferSize, + 1000, + linkedCancellationToken).ConfigureAwait(false); + } } _logger.LogInformation("Recording completed: {FilePath}", targetFile); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index e7834ffd6..bba584854 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1819,16 +1819,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (timer.IsProgramSeries) { - SaveSeriesNfo(timer, seriesPath); - SaveVideoNfo(timer, recordingPath, program, false); + await SaveSeriesNfoAsync(timer, seriesPath).ConfigureAwait(false); + await SaveVideoNfoAsync(timer, recordingPath, program, false).ConfigureAwait(false); } else if (!timer.IsMovie || timer.IsSports || timer.IsNews) { - SaveVideoNfo(timer, recordingPath, program, true); + await SaveVideoNfoAsync(timer, recordingPath, program, true).ConfigureAwait(false); } else { - SaveVideoNfo(timer, recordingPath, program, false); + await SaveVideoNfoAsync(timer, recordingPath, program, false).ConfigureAwait(false); } await SaveRecordingImages(recordingPath, program).ConfigureAwait(false); @@ -1839,7 +1839,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private void SaveSeriesNfo(TimerInfo timer, string seriesPath) + private async Task SaveSeriesNfoAsync(TimerInfo timer, string seriesPath) { var nfoPath = Path.Combine(seriesPath, "tvshow.nfo"); @@ -1848,61 +1848,62 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) + await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8 + Encoding = Encoding.UTF8, + Async = true }; - using (var writer = XmlWriter.Create(stream, settings)) + await using (var writer = XmlWriter.Create(stream, settings)) { - writer.WriteStartDocument(true); - writer.WriteStartElement("tvshow"); + await writer.WriteStartDocumentAsync(true).ConfigureAwait(false); + await writer.WriteStartElementAsync(null, "tvshow", null).ConfigureAwait(false); string id; if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out id)) { - writer.WriteElementString("id", id); + await writer.WriteElementStringAsync(null, "id", null, id).ConfigureAwait(false); } if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out id)) { - writer.WriteElementString("imdb_id", id); + await writer.WriteElementStringAsync(null, "imdb_id", null, id).ConfigureAwait(false); } if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out id)) { - writer.WriteElementString("tmdbid", id); + await writer.WriteElementStringAsync(null, "tmdbid", null, id).ConfigureAwait(false); } if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Zap2It.ToString(), out id)) { - writer.WriteElementString("zap2itid", id); + await writer.WriteElementStringAsync(null, "zap2itid", null, id).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(timer.Name)) { - writer.WriteElementString("title", timer.Name); + await writer.WriteElementStringAsync(null, "title", null, timer.Name).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(timer.OfficialRating)) { - writer.WriteElementString("mpaa", timer.OfficialRating); + await writer.WriteElementStringAsync(null, "mpaa", null, timer.OfficialRating).ConfigureAwait(false); } foreach (var genre in timer.Genres) { - writer.WriteElementString("genre", genre); + await writer.WriteElementStringAsync(null, "genre", null, genre).ConfigureAwait(false); } - writer.WriteEndElement(); - writer.WriteEndDocument(); + await writer.WriteEndElementAsync().ConfigureAwait(false); + await writer.WriteEndDocumentAsync().ConfigureAwait(false); } } } - private void SaveVideoNfo(TimerInfo timer, string recordingPath, BaseItem item, bool lockData) + private async Task SaveVideoNfoAsync(TimerInfo timer, string recordingPath, BaseItem item, bool lockData) { var nfoPath = Path.ChangeExtension(recordingPath, ".nfo"); @@ -1911,29 +1912,30 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) + await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8 + Encoding = Encoding.UTF8, + Async = true }; var options = _config.GetNfoConfiguration(); var isSeriesEpisode = timer.IsProgramSeries; - using (var writer = XmlWriter.Create(stream, settings)) + await using (var writer = XmlWriter.Create(stream, settings)) { - writer.WriteStartDocument(true); + await writer.WriteStartDocumentAsync(true).ConfigureAwait(false); if (isSeriesEpisode) { - writer.WriteStartElement("episodedetails"); + await writer.WriteStartElementAsync(null, "episodedetails", null).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(timer.EpisodeTitle)) { - writer.WriteElementString("title", timer.EpisodeTitle); + await writer.WriteElementStringAsync(null, "title", null, timer.EpisodeTitle).ConfigureAwait(false); } var premiereDate = item.PremiereDate ?? (!timer.IsRepeat ? DateTime.UtcNow : null); @@ -1942,76 +1944,84 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var formatString = options.ReleaseDateFormat; - writer.WriteElementString( + await writer.WriteElementStringAsync( + null, "aired", - premiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)); + null, + premiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false); } if (item.IndexNumber.HasValue) { - writer.WriteElementString("episode", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)); + await writer.WriteElementStringAsync(null, "episode", null, item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); } if (item.ParentIndexNumber.HasValue) { - writer.WriteElementString("season", item.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture)); + await writer.WriteElementStringAsync(null, "season", null, item.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); } } else { - writer.WriteStartElement("movie"); + await writer.WriteStartElementAsync(null, "movie", null); if (!string.IsNullOrWhiteSpace(item.Name)) { - writer.WriteElementString("title", item.Name); + await writer.WriteElementStringAsync(null, "title", null, item.Name).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(item.OriginalTitle)) { - writer.WriteElementString("originaltitle", item.OriginalTitle); + await writer.WriteElementStringAsync(null, "originaltitle", null, item.OriginalTitle).ConfigureAwait(false); } if (item.PremiereDate.HasValue) { var formatString = options.ReleaseDateFormat; - writer.WriteElementString( + await writer.WriteElementStringAsync( + null, "premiered", - item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)); - writer.WriteElementString( + null, + item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false); + await writer.WriteElementStringAsync( + null, "releasedate", - item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)); + null, + item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false); } } - writer.WriteElementString( + await writer.WriteElementStringAsync( + null, "dateadded", - DateTime.Now.ToString(DateAddedFormat, CultureInfo.InvariantCulture)); + null, + DateTime.Now.ToString(DateAddedFormat, CultureInfo.InvariantCulture)).ConfigureAwait(false); if (item.ProductionYear.HasValue) { - writer.WriteElementString("year", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture)); + await writer.WriteElementStringAsync(null, "year", null, item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); } if (!string.IsNullOrEmpty(item.OfficialRating)) { - writer.WriteElementString("mpaa", item.OfficialRating); + await writer.WriteElementStringAsync(null, "mpaa", null, item.OfficialRating).ConfigureAwait(false); } var overview = (item.Overview ?? string.Empty) .StripHtml() .Replace(""", "'", StringComparison.Ordinal); - writer.WriteElementString("plot", overview); + await writer.WriteElementStringAsync(null, "plot", null, overview).ConfigureAwait(false); if (item.CommunityRating.HasValue) { - writer.WriteElementString("rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)); + await writer.WriteElementStringAsync(null, "rating", null, item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); } foreach (var genre in item.Genres) { - writer.WriteElementString("genre", genre); + await writer.WriteElementStringAsync(null, "genre", null, genre).ConfigureAwait(false); } var people = item.Id.Equals(Guid.Empty) ? new List<PersonInfo>() : _libraryManager.GetPeople(item); @@ -2023,7 +2033,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV foreach (var person in directors) { - writer.WriteElementString("director", person); + await writer.WriteElementStringAsync(null, "director", null, person).ConfigureAwait(false); } var writers = people @@ -2034,19 +2044,19 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV foreach (var person in writers) { - writer.WriteElementString("writer", person); + await writer.WriteElementStringAsync(null, "writer", null, person).ConfigureAwait(false); } foreach (var person in writers) { - writer.WriteElementString("credits", person); + await writer.WriteElementStringAsync(null, "credits", null, person).ConfigureAwait(false); } var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection); if (!string.IsNullOrEmpty(tmdbCollection)) { - writer.WriteElementString("collectionnumber", tmdbCollection); + await writer.WriteElementStringAsync(null, "collectionnumber", null, tmdbCollection).ConfigureAwait(false); } var imdb = item.GetProviderId(MetadataProvider.Imdb); @@ -2054,10 +2064,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { if (!isSeriesEpisode) { - writer.WriteElementString("id", imdb); + await writer.WriteElementStringAsync(null, "id", null, imdb).ConfigureAwait(false); } - writer.WriteElementString("imdbid", imdb); + await writer.WriteElementStringAsync(null, "imdbid", null, imdb).ConfigureAwait(false); // No need to lock if we have identified the content already lockData = false; @@ -2066,7 +2076,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var tvdb = item.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdb)) { - writer.WriteElementString("tvdbid", tvdb); + await writer.WriteElementStringAsync(null, "tvdbid", null, tvdb).ConfigureAwait(false); // No need to lock if we have identified the content already lockData = false; @@ -2075,7 +2085,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var tmdb = item.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdb)) { - writer.WriteElementString("tmdbid", tmdb); + await writer.WriteElementStringAsync(null, "tmdbid", null, tmdb).ConfigureAwait(false); // No need to lock if we have identified the content already lockData = false; @@ -2083,26 +2093,26 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (lockData) { - writer.WriteElementString("lockdata", true.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); + await writer.WriteElementStringAsync(null, "lockdata", null, "true").ConfigureAwait(false); } if (item.CriticRating.HasValue) { - writer.WriteElementString("criticrating", item.CriticRating.Value.ToString(CultureInfo.InvariantCulture)); + await writer.WriteElementStringAsync(null, "criticrating", null, item.CriticRating.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(item.Tagline)) { - writer.WriteElementString("tagline", item.Tagline); + await writer.WriteElementStringAsync(null, "tagline", null, item.Tagline).ConfigureAwait(false); } foreach (var studio in item.Studios) { - writer.WriteElementString("studio", studio); + await writer.WriteElementStringAsync(null, "studio", null, studio).ConfigureAwait(false); } - writer.WriteEndElement(); - writer.WriteEndDocument(); + await writer.WriteEndElementAsync().ConfigureAwait(false); + await writer.WriteEndDocumentAsync().ConfigureAwait(false); } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 7fa47e7db..f1d4b6097 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly ILogger _logger; private readonly IMediaEncoder _mediaEncoder; private readonly IServerApplicationPaths _appPaths; - private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(); + private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); private readonly IServerConfigurationManager _serverConfigurationManager; private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; private bool _hasExited; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index 323b96021..fbce7af2d 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.LiveTv try { dto.ParentThumbImageTag = _imageProcessor.GetImageCacheTag(librarySeries, image); - dto.ParentThumbItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture); + dto.ParentThumbItemId = librarySeries.Id; } catch (Exception ex) { @@ -193,7 +193,7 @@ namespace Emby.Server.Implementations.LiveTv { _imageProcessor.GetImageCacheTag(librarySeries, image) }; - dto.ParentBackdropItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture); + dto.ParentBackdropItemId = librarySeries.Id; } catch (Exception ex) { @@ -240,7 +240,7 @@ namespace Emby.Server.Implementations.LiveTv _imageProcessor.GetImageCacheTag(program, image) }; - dto.ParentBackdropItemId = program.Id.ToString("N", CultureInfo.InvariantCulture); + dto.ParentBackdropItemId = program.Id; } catch (Exception ex) { diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index aa3598c8b..6a9a3077c 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -857,11 +857,10 @@ namespace Emby.Server.Implementations.LiveTv var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user); - return new QueryResult<BaseItemDto> - { - Items = returnArray, - TotalRecordCount = queryResult.TotalRecordCount - }; + return new QueryResult<BaseItemDto>( + query.StartIndex, + queryResult.TotalRecordCount, + returnArray); } public QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken) @@ -910,29 +909,27 @@ namespace Emby.Server.Implementations.LiveTv programs = programs.Take(query.Limit.Value); } - return new QueryResult<BaseItem> - { - Items = programs.ToArray(), - TotalRecordCount = totalCount - }; + return new QueryResult<BaseItem>( + query.StartIndex, + totalCount, + programs.ToArray()); } - public QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken) + public Task<QueryResult<BaseItemDto>> GetRecommendedProgramsAsync(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken) { if (!(query.IsAiring ?? false)) { - return GetPrograms(query, options, cancellationToken).Result; + return GetPrograms(query, options, cancellationToken); } RemoveFields(options); var internalResult = GetRecommendedProgramsInternal(query, options, cancellationToken); - return new QueryResult<BaseItemDto> - { - Items = _dtoService.GetBaseItemDtos(internalResult.Items, options, query.User), - TotalRecordCount = internalResult.TotalRecordCount - }; + return Task.FromResult(new QueryResult<BaseItemDto>( + query.StartIndex, + internalResult.TotalRecordCount, + _dtoService.GetBaseItemDtos(internalResult.Items, options, query.User))); } private int GetRecommendationScore(LiveTvProgram program, User user, bool factorChannelWatchCount) @@ -1541,11 +1538,10 @@ namespace Emby.Server.Implementations.LiveTv var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); - return new QueryResult<BaseItemDto> - { - Items = returnArray, - TotalRecordCount = internalResult.TotalRecordCount - }; + return new QueryResult<BaseItemDto>( + query.StartIndex, + internalResult.TotalRecordCount, + returnArray); } private async Task<QueryResult<TimerInfo>> GetTimersInternal(TimerQuery query, CancellationToken cancellationToken) @@ -1615,11 +1611,7 @@ namespace Emby.Server.Implementations.LiveTv .OrderBy(i => i.StartDate) .ToArray(); - return new QueryResult<TimerInfo> - { - Items = returnArray, - TotalRecordCount = returnArray.Length - }; + return new QueryResult<TimerInfo>(returnArray); } public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken) @@ -1701,11 +1693,7 @@ namespace Emby.Server.Implementations.LiveTv .OrderBy(i => i.StartDate) .ToArray(); - return new QueryResult<TimerInfoDto> - { - Items = returnArray, - TotalRecordCount = returnArray.Length - }; + return new QueryResult<TimerInfoDto>(returnArray); } public async Task CancelTimer(string id) @@ -1801,11 +1789,7 @@ namespace Emby.Server.Implementations.LiveTv .Select(i => i.Item1) .ToArray(); - return new QueryResult<SeriesTimerInfo> - { - Items = returnArray, - TotalRecordCount = returnArray.Length - }; + return new QueryResult<SeriesTimerInfo>(returnArray); } public async Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken) @@ -1855,11 +1839,7 @@ namespace Emby.Server.Implementations.LiveTv }) .ToArray(); - return new QueryResult<SeriesTimerInfoDto> - { - Items = returnArray, - TotalRecordCount = returnArray.Length - }; + return new QueryResult<SeriesTimerInfoDto>(returnArray); } public BaseItem GetLiveTvChannel(TimerInfo timer, ILiveTvService service) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index a5edd35cc..6195c7648 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - var taskCompletionSource = new TaskCompletionSource<bool>(); + var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); _ = StartStreaming( udpClient, @@ -186,7 +186,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var resolved = false; - using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read)) + var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read); + await using (fileStream.ConfigureAwait(false)) { while (true) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 5581ba87c..2748794b3 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -97,7 +97,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public Stream GetStream() { - var stream = GetInputStream(TempFilePath); + var stream = new FileStream( + TempFilePath, + FileMode.Open, + FileAccess.Read, + FileShare.ReadWrite, + IODefaults.FileStreamBufferSize, + FileOptions.SequentialScan | FileOptions.Asynchronous); + bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; if (seekFile) { @@ -107,15 +114,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return stream; } - protected FileStream GetInputStream(string path) - => new FileStream( - path, - FileMode.Open, - FileAccess.Read, - FileShare.ReadWrite, - IODefaults.FileStreamBufferSize, - FileOptions.SequentialScan | FileOptions.Asynchronous); - protected async Task DeleteTempFiles(string path, int retryCount = 0) { if (retryCount == 0) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index ab4beb15b..e84e1e074 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -73,7 +73,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts SetTempFilePath("ts"); - var taskCompletionSource = new TaskCompletionSource<bool>(); + var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json index 25f51db16..65a31e676 100644 --- a/Emby.Server.Implementations/Localization/Core/cs.json +++ b/Emby.Server.Implementations/Localization/Core/cs.json @@ -23,7 +23,7 @@ "HeaderFavoriteShows": "Oblíbené seriály", "HeaderFavoriteSongs": "Oblíbená hudba", "HeaderLiveTV": "Televize", - "HeaderNextUp": "Nadcházející", + "HeaderNextUp": "Další díly", "HeaderRecordingGroups": "Skupiny nahrávek", "HomeVideos": "Domácí videa", "Inherit": "Zdědit", diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index bfafe7650..e56ae6071 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -1,7 +1,7 @@ { "Albums": "Albums", "AppDeviceValues": "Application : {0}, Appareil : {1}", - "Application": "Applications", + "Application": "Application", "Artists": "Artistes", "AuthenticationSucceededWithUserName": "{0} authentifié avec succès", "Books": "Livres", diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json index f8fad7b63..8af5449a7 100644 --- a/Emby.Server.Implementations/Localization/Core/ro.json +++ b/Emby.Server.Implementations/Localization/Core/ro.json @@ -117,5 +117,7 @@ "TaskCleanActivityLog": "Curăță Jurnalul de Activitate", "Undefined": "Nedefinit", "Forced": "Forțat", - "Default": "Implicit" + "Default": "Implicit", + "TaskOptimizeDatabaseDescription": "Compactează baza de date și trunchiază spațiul liber. Rularea acestei sarcini după scanarea bibliotecii sau după efectuarea altor modificări care implică modificări ale bazei de date poate îmbunătăți performanța.", + "TaskOptimizeDatabase": "Optimizează baza de date" } diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json index 89fbb84b6..bed67fa4f 100644 --- a/Emby.Server.Implementations/Localization/Core/th.json +++ b/Emby.Server.Implementations/Localization/Core/th.json @@ -118,5 +118,6 @@ "TaskCleanActivityLog": "ล้างบันทึกกิจกรรม", "Undefined": "ไม่ได้กำหนด", "Forced": "บังคับใช้", - "TaskOptimizeDatabase": "ปรับฐานข้อมูลให้เหมาะสม" + "TaskOptimizeDatabase": "ปรับปรุงประสิทธิภาพฐานข้อมูล", + "TaskOptimizeDatabaseDescription": "ลดขนาดการจัดเก็บฐานข้อมูล ใช้งานคำสั่งนี้หลังจากสแกนไลบรารีหรือหลังจากการเปลี่ยนแปลงฐานข้อมูล อาจจะทำให้ระบบทำงานเร็วขึ้น" } diff --git a/Emby.Server.Implementations/Localization/Core/ug.json b/Emby.Server.Implementations/Localization/Core/ug.json new file mode 100644 index 000000000..aea93c7fa --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/ug.json @@ -0,0 +1,9 @@ +{ + "ChapterNameValue": "باب {0}", + "Channels": "قانال", + "CameraImageUploadedFrom": "{0} ئورۇندىن يېڭى سۈرەت چىقىرىلدى", + "Books": "كىتاب", + "AuthenticationSucceededWithUserName": "تىزىملىتىش مۇۋەپپەقىيەتلىك بول", + "Artists": "سەنئەتكار", + "Albums": "پىلاستىنكا" +} diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs index 0c451ccb6..bbbca4fc0 100644 --- a/Emby.Server.Implementations/Net/UdpSocket.cs +++ b/Emby.Server.Implementations/Net/UdpSocket.cs @@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.Net { ThrowIfDisposed(); - var taskCompletion = new TaskCompletionSource<SocketReceiveResult>(); + var taskCompletion = new TaskCompletionSource<SocketReceiveResult>(TaskCreationOptions.RunContinuationsAsynchronously); bool isResultSet = false; Action<IAsyncResult> callback = callbackResult => @@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.Net { ThrowIfDisposed(); - var taskCompletion = new TaskCompletionSource<int>(); + var taskCompletion = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); bool isResultSet = false; Action<IAsyncResult> callback = callbackResult => diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs index f7b3cfedc..7c27ae384 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs @@ -25,8 +25,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// <summary> /// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class. /// </summary> - /// <param name="libraryManager">The library manager.</param> - /// <param name="localization">The localization manager.</param> + /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> + /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param> public RefreshMediaLibraryTask(ILibraryManager libraryManager, ILocalizationManager localization) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index c994ffc90..a18af27f3 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -304,11 +304,10 @@ namespace Emby.Server.Implementations.TV items = items.Take(query.Limit.Value); } - return new QueryResult<BaseItem> - { - TotalRecordCount = totalCount, - Items = items.ToArray() - }; + return new QueryResult<BaseItem>( + query.StartIndex, + totalCount, + items.ToArray()); } } } |
