diff options
Diffstat (limited to 'Emby.Server.Implementations')
17 files changed, 166 insertions, 234 deletions
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index f3e3a6397..686944a28 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1138,7 +1138,10 @@ namespace Emby.Server.Implementations.Dto if (episodeSeries != null) { dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, episodeSeries, ImageType.Primary); - AttachPrimaryImageAspectRatio(dto, episodeSeries); + if (!dto.ImageTags.ContainsKey(ImageType.Primary)) + { + AttachPrimaryImageAspectRatio(dto, episodeSeries); + } } } @@ -1185,7 +1188,10 @@ namespace Emby.Server.Implementations.Dto if (series != null) { dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, series, ImageType.Primary); - AttachPrimaryImageAspectRatio(dto, series); + if (!dto.ImageTags.ContainsKey(ImageType.Primary)) + { + AttachPrimaryImageAspectRatio(dto, series); + } } } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 91c4648c6..9e9452f32 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -31,7 +31,7 @@ <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" /> diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index d62e2eefe..024404ceb 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -185,11 +185,11 @@ namespace Emby.Server.Implementations.HttpServer.Security updateToken = true; } - authInfo.IsApiKey = true; + authInfo.IsApiKey = false; } else { - authInfo.IsApiKey = false; + authInfo.IsApiKey = true; } if (updateToken) diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs deleted file mode 100644 index d4e790c9a..000000000 --- a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Data.Events; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Net; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.Library -{ - /// <summary> - /// A library post scan/refresh task for pre-fetching remote images. - /// </summary> - public class ImageFetcherPostScanTask : ILibraryPostScanTask - { - private readonly ILibraryManager _libraryManager; - private readonly IProviderManager _providerManager; - private readonly ILogger<ImageFetcherPostScanTask> _logger; - private readonly SemaphoreSlim _imageFetcherLock; - - private ConcurrentDictionary<Guid, (BaseItem item, ItemUpdateType updateReason)> _queuedItems; - - /// <summary> - /// Initializes a new instance of the <see cref="ImageFetcherPostScanTask"/> class. - /// </summary> - /// <param name="libraryManager">An instance of <see cref="ILibraryManager"/>.</param> - /// <param name="providerManager">An instance of <see cref="IProviderManager"/>.</param> - /// <param name="logger">An instance of <see cref="ILogger{ImageFetcherPostScanTask}"/>.</param> - public ImageFetcherPostScanTask( - ILibraryManager libraryManager, - IProviderManager providerManager, - ILogger<ImageFetcherPostScanTask> logger) - { - _libraryManager = libraryManager; - _providerManager = providerManager; - _logger = logger; - _queuedItems = new ConcurrentDictionary<Guid, (BaseItem item, ItemUpdateType updateReason)>(); - _imageFetcherLock = new SemaphoreSlim(1, 1); - _libraryManager.ItemAdded += OnLibraryManagerItemAddedOrUpdated; - _libraryManager.ItemUpdated += OnLibraryManagerItemAddedOrUpdated; - _providerManager.RefreshCompleted += OnProviderManagerRefreshCompleted; - } - - /// <inheritdoc /> - public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - // Sometimes a library scan will cause this to run twice if there's an item refresh going on. - await _imageFetcherLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - var now = DateTime.UtcNow; - var itemGuids = _queuedItems.Keys.ToList(); - - for (var i = 0; i < itemGuids.Count; i++) - { - if (!_queuedItems.TryGetValue(itemGuids[i], out var queuedItem)) - { - continue; - } - - var itemId = queuedItem.item.Id.ToString("N", CultureInfo.InvariantCulture); - var itemType = queuedItem.item.GetType(); - _logger.LogDebug( - "Updating remote images for item {ItemId} with media type {ItemMediaType}", - itemId, - itemType); - try - { - await _libraryManager.UpdateImagesAsync(queuedItem.item, queuedItem.updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to fetch images for {Type} item with id {ItemId}", itemType, itemId); - } - - _queuedItems.TryRemove(queuedItem.item.Id, out _); - } - - if (itemGuids.Count > 0) - { - _logger.LogInformation( - "Finished updating/pre-fetching {NumberOfImages} images. Elapsed time: {TimeElapsed}s.", - itemGuids.Count.ToString(CultureInfo.InvariantCulture), - (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); - } - else - { - _logger.LogDebug("No images were updated."); - } - } - finally - { - _imageFetcherLock.Release(); - } - } - - private void OnLibraryManagerItemAddedOrUpdated(object sender, ItemChangeEventArgs itemChangeEventArgs) - { - if (!_queuedItems.ContainsKey(itemChangeEventArgs.Item.Id) && itemChangeEventArgs.Item.ImageInfos.Length > 0) - { - _queuedItems.AddOrUpdate( - itemChangeEventArgs.Item.Id, - (itemChangeEventArgs.Item, itemChangeEventArgs.UpdateReason), - (key, existingValue) => existingValue); - } - } - - private void OnProviderManagerRefreshCompleted(object sender, GenericEventArgs<BaseItem> e) - { - if (!_queuedItems.ContainsKey(e.Argument.Id) && e.Argument.ImageInfos.Length > 0) - { - _queuedItems.AddOrUpdate( - e.Argument.Id, - (e.Argument, ItemUpdateType.None), - (key, existingValue) => existingValue); - } - - // The RefreshCompleted event is a bit awkward in that it seems to _only_ be fired on - // the item that was refreshed regardless of children refreshes. So we take it as a signal - // that the refresh is entirely completed. - Run(null, CancellationToken.None).GetAwaiter().GetResult(); - } - } -} diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 5b926b0f4..db27862ce 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -42,7 +42,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Library; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Tasks; using MediaBrowser.Providers.MediaInfo; @@ -1955,9 +1954,12 @@ namespace Emby.Server.Implementations.Library } /// <inheritdoc /> - public Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) + public async Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { - RunMetadataSavers(items, updateReason); + foreach (var item in items) + { + await RunMetadataSavers(item, updateReason).ConfigureAwait(false); + } _itemRepository.SaveItems(items, cancellationToken); @@ -1988,25 +1990,22 @@ namespace Emby.Server.Implementations.Library } } } - - return Task.CompletedTask; } /// <inheritdoc /> public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) => UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken); - public void RunMetadataSavers(IReadOnlyList<BaseItem> items, ItemUpdateType updateReason) + public Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason) { - foreach (var item in items) + if (item.IsFileProtocol) { - if (item.IsFileProtocol) - { - ProviderManager.SaveMetadata(item, updateReason); - } - - item.DateLastSaved = DateTime.UtcNow; + ProviderManager.SaveMetadata(item, updateReason); } + + item.DateLastSaved = DateTime.UtcNow; + + return UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate); } /// <summary> diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index f51657c63..e4221dd50 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -139,13 +139,13 @@ namespace Emby.Server.Implementations.Library return list .OrderBy(i => { - var index = orders.IndexOf(i.Id.ToString("N", CultureInfo.InvariantCulture)); + var index = orders.IndexOf(i.Id.ToString("D", CultureInfo.InvariantCulture)); if (index == -1 && i is UserView view && view.DisplayParentId != Guid.Empty) { - index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture)); + index = orders.IndexOf(view.DisplayParentId.ToString("D", CultureInfo.InvariantCulture)); } return index == -1 ? int.MaxValue : index; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 1084ddf74..90e6cc966 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -611,25 +611,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings CancellationToken cancellationToken, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) { - try + var response = await _httpClientFactory.CreateClient(NamedClient.Default) + .SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false); + if (response.IsSuccessStatusCode) { - return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false); + return response; } - catch (HttpRequestException ex) - { - _tokens.Clear(); - if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500) - { - enableRetry = false; - } - - if (!enableRetry) - { - throw; - } + // Response is automatically disposed in the calling function, + // so dispose manually if not returning. + response.Dispose(); + if (!enableRetry || (int)response.StatusCode >= 500) + { + throw new HttpRequestException( + string.Format(CultureInfo.InvariantCulture, "Request failed: {0}", response.ReasonPhrase), + null, + response.StatusCode); } + _tokens.Clear(); options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false)); return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false); } @@ -647,6 +647,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + hashedPassword + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false); if (string.Equals(root.message, "OK", StringComparison.Ordinal)) @@ -701,6 +702,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings try { using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false); + httpResponse.EnsureSuccessStatusCode(); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(stream).ConfigureAwait(false); @@ -709,7 +711,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings } catch (HttpRequestException ex) { - // Apparently we're supposed to swallow this + // SchedulesDirect returns 400 if no lineups are configured. if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) { return false; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 8c9bb6ba0..7842be716 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1928,7 +1928,7 @@ namespace Emby.Server.Implementations.LiveTv foreach (var programDto in currentProgramDtos) { - if (currentChannelsDict.TryGetValue(programDto.ChannelId, out BaseItemDto channelDto)) + if (programDto.ChannelId.HasValue && currentChannelsDict.TryGetValue(programDto.ChannelId.Value, out BaseItemDto channelDto)) { channelDto.CurrentProgram = programDto; } @@ -2018,7 +2018,7 @@ namespace Emby.Server.Implementations.LiveTv info.DayPattern = _tvDtoService.GetDayPattern(info.Days); info.Name = program.Name; - info.ChannelId = programDto.ChannelId; + info.ChannelId = programDto.ChannelId ?? Guid.Empty; info.ChannelName = programDto.ChannelName; info.StartDate = program.StartDate; info.Name = program.Name; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs new file mode 100644 index 000000000..740cbb66e --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs @@ -0,0 +1,21 @@ +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + internal class Channels + { + public string GuideNumber { get; set; } + + public string GuideName { get; set; } + + public string VideoCodec { get; set; } + + public string AudioCodec { get; set; } + + public string URL { get; set; } + + public bool Favorite { get; set; } + + public bool DRM { get; set; } + + public bool HD { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs new file mode 100644 index 000000000..09d77f838 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs @@ -0,0 +1,40 @@ +using System; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + internal class DiscoverResponse + { + public string FriendlyName { get; set; } + + public string ModelNumber { get; set; } + + public string FirmwareName { get; set; } + + public string FirmwareVersion { get; set; } + + public string DeviceID { get; set; } + + public string DeviceAuth { get; set; } + + public string BaseURL { get; set; } + + public string LineupURL { get; set; } + + public int TunerCount { get; set; } + + public bool SupportsTranscoding + { + get + { + var model = ModelNumber ?? string.Empty; + + if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) + { + return true; + } + + return false; + } + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b6444b172..5ef83f274 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -8,10 +8,12 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -37,6 +39,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly INetworkManager _networkManager; private readonly IStreamHelper _streamHelper; + private readonly JsonSerializerOptions _jsonOptions; + private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>(); public HdHomerunHost( @@ -56,6 +60,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _socketFactory = socketFactory; _networkManager = networkManager; _streamHelper = streamHelper; + + _jsonOptions = JsonDefaults.GetOptions(); } public string Name => "HD Homerun"; @@ -67,13 +73,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private string GetChannelId(TunerHostInfo info, Channels i) => ChannelIdPrefix + i.GuideNumber; - private async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) + internal async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) { var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, cancellationToken: cancellationToken) + var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, _jsonOptions, cancellationToken) .ConfigureAwait(false) ?? new List<Channels>(); if (info.ImportFavoritesOnly) @@ -100,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Id = GetChannelId(info, i), IsFavorite = i.Favorite, TunerHostId = info.Id, - IsHD = i.HD == 1, + IsHD = i.HD, AudioCodec = i.AudioCodec, VideoCodec = i.VideoCodec, ChannelType = ChannelType.TV, @@ -109,7 +115,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }).Cast<ChannelInfo>().ToList(); } - private async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken) + internal async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken) { var cacheKey = info.Id; @@ -127,10 +133,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun try { using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .GetAsync(GetApiUrl(info) + "/discover.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken) .ConfigureAwait(false); + response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, cancellationToken: cancellationToken) + var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, _jsonOptions, cancellationToken) .ConfigureAwait(false); if (!string.IsNullOrEmpty(cacheKey)) @@ -328,25 +335,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return new Uri(url).AbsoluteUri.TrimEnd('/'); } - private class Channels - { - public string GuideNumber { get; set; } - - public string GuideName { get; set; } - - public string VideoCodec { get; set; } - - public string AudioCodec { get; set; } - - public string URL { get; set; } - - public bool Favorite { get; set; } - - public bool DRM { get; set; } - - public int HD { get; set; } - } - protected EncodingOptions GetEncodingOptions() { return Config.GetConfiguration<EncodingOptions>("encoding"); @@ -674,42 +662,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public class DiscoverResponse - { - public string FriendlyName { get; set; } - - public string ModelNumber { get; set; } - - public string FirmwareName { get; set; } - - public string FirmwareVersion { get; set; } - - public string DeviceID { get; set; } - - public string DeviceAuth { get; set; } - - public string BaseURL { get; set; } - - public string LineupURL { get; set; } - - public int TunerCount { get; set; } - - public bool SupportsTranscoding - { - get - { - var model = ModelNumber ?? string.Empty; - - if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) - { - return true; - } - - return false; - } - } - } - public async Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken) { lock (_modelCache) @@ -762,7 +714,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return list; } - private async Task<TunerHostInfo> TryGetTunerHostInfo(string url, CancellationToken cancellationToken) + internal async Task<TunerHostInfo> TryGetTunerHostInfo(string url, CancellationToken cancellationToken) { var hostInfo = new TunerHostInfo { @@ -774,6 +726,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun hostInfo.DeviceId = modelInfo.DeviceID; hostInfo.FriendlyName = modelInfo.FriendlyName; + hostInfo.TunerCount = modelInfo.TunerCount; return hostInfo; } diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index 66681f025..343e067b7 100644 --- a/Emby.Server.Implementations/Localization/Core/sl-SI.json +++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json @@ -113,5 +113,10 @@ "TasksApplicationCategory": "Aplikacija", "TasksLibraryCategory": "Knjižnica", "TasksMaintenanceCategory": "Vzdrževanje", - "TaskDownloadMissingSubtitlesDescription": "Na podlagi nastavitev metapodatkov poišče manjkajoče podnapise na internetu." + "TaskDownloadMissingSubtitlesDescription": "Na podlagi nastavitev metapodatkov poišče manjkajoče podnapise na internetu.", + "TaskCleanActivityLogDescription": "Počisti zapise v dnevniku aktivnosti starejše od nastavljenega časa.", + "TaskCleanActivityLog": "Počisti dnevnik aktivnosti", + "Undefined": "Nedoločen", + "Forced": "Prisilno", + "Default": "Privzeto" } diff --git a/Emby.Server.Implementations/Properties/AssemblyInfo.cs b/Emby.Server.Implementations/Properties/AssemblyInfo.cs index a1933f66e..cb7972173 100644 --- a/Emby.Server.Implementations/Properties/AssemblyInfo.cs +++ b/Emby.Server.Implementations/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -14,6 +15,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] +[assembly: InternalsVisibleTo("Jellyfin.Server.Implementations.Tests")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b3965fcca..885f65c64 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -128,6 +128,9 @@ namespace Emby.Server.Implementations.Session /// <inheritdoc /> public event EventHandler<SessionEventArgs> SessionActivity; + /// <inheritdoc /> + public event EventHandler<SessionEventArgs> SessionControllerConnected; + /// <summary> /// Gets all connections. /// </summary> @@ -313,6 +316,19 @@ namespace Emby.Server.Implementations.Session } /// <inheritdoc /> + public void OnSessionControllerConnected(SessionInfo info) + { + EventHelper.QueueEventIfNotNull( + SessionControllerConnected, + this, + new SessionEventArgs + { + SessionInfo = info + }, + _logger); + } + + /// <inheritdoc /> public void CloseIfNeeded(SessionInfo session) { if (!session.SessionControllers.Any(i => i.IsSessionActive)) diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 169eaefd8..39c369a01 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -133,6 +133,8 @@ namespace Emby.Server.Implementations.Session var controller = (WebSocketController)controllerInfo.Item1; controller.AddWebSocket(connection); + + _sessionManager.OnSessionControllerConnected(session); } /// <summary> diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index 348213ee1..1d87036a2 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.SyncPlay _sessionManager = sessionManager; _libraryManager = libraryManager; _logger = loggerFactory.CreateLogger<SyncPlayManager>(); - _sessionManager.SessionStarted += OnSessionManagerSessionStarted; + _sessionManager.SessionControllerConnected += OnSessionControllerConnected; } /// <inheritdoc /> @@ -329,11 +329,11 @@ namespace Emby.Server.Implementations.SyncPlay return; } - _sessionManager.SessionStarted -= OnSessionManagerSessionStarted; + _sessionManager.SessionControllerConnected -= OnSessionControllerConnected; _disposed = true; } - private void OnSessionManagerSessionStarted(object sender, SessionEventArgs e) + private void OnSessionControllerConnected(object sender, SessionEventArgs e) { var session = e.SessionInfo; diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index ef346dd5d..ae2fa3ce1 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -12,7 +12,6 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; -using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; @@ -190,6 +189,22 @@ namespace Emby.Server.Implementations.Updates continue; } + for (var i = package.versions.Count - 1; i >= 0; i--) + { + // Remove versions with a target abi that is greater then the current application version. + if (Version.TryParse(package.versions[i].targetAbi, out var targetAbi) + && _applicationHost.ApplicationVersion < targetAbi) + { + package.versions.RemoveAt(i); + } + } + + // Don't add a package that doesn't have any compatible versions. + if (package.versions.Count == 0) + { + continue; + } + var existing = FilterPackages(result, package.name, packageGuid).FirstOrDefault(); if (existing != null) { @@ -407,6 +422,7 @@ namespace Emby.Server.Implementations.Updates using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(new Uri(package.SourceUrl), cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // CA5351: Do Not Use Broken Cryptographic Algorithms |
