aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.config/dotnet-tools.json2
-rw-r--r--.github/workflows/ci-codeql-analysis.yml6
-rw-r--r--CONTRIBUTORS.md4
-rw-r--r--Directory.Packages.props17
-rw-r--r--Emby.Naming/Emby.Naming.csproj4
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs668
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/hi.json14
-rw-r--r--Emby.Server.Implementations/Localization/Core/id.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/mr.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-BR.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/tr.json4
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs15
-rw-r--r--Jellyfin.Data/Jellyfin.Data.csproj4
-rw-r--r--Jellyfin.Server.Implementations/Activity/ActivityManager.cs10
-rw-r--r--Jellyfin.Server.Implementations/Security/AuthenticationManager.cs13
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj1
-rw-r--r--MediaBrowser.Common/Net/NetworkUtils.cs51
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs3
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj1
-rw-r--r--MediaBrowser.Model/Providers/ExternalIdMediaType.cs7
-rw-r--r--README.md2
-rw-r--r--debian/control2
-rw-r--r--deployment/Dockerfile.debian.amd642
-rw-r--r--deployment/Dockerfile.debian.arm642
-rw-r--r--deployment/Dockerfile.debian.armhf2
-rw-r--r--deployment/Dockerfile.docker.amd642
-rw-r--r--deployment/Dockerfile.docker.arm642
-rw-r--r--deployment/Dockerfile.docker.armhf2
-rw-r--r--deployment/Dockerfile.linux.amd642
-rw-r--r--deployment/Dockerfile.linux.amd64-musl2
-rw-r--r--deployment/Dockerfile.linux.arm642
-rw-r--r--deployment/Dockerfile.linux.armhf2
-rw-r--r--deployment/Dockerfile.linux.musl-linux-arm642
-rw-r--r--deployment/Dockerfile.macos.amd642
-rw-r--r--deployment/Dockerfile.macos.arm642
-rw-r--r--deployment/Dockerfile.portable2
-rw-r--r--deployment/Dockerfile.windows.amd642
-rwxr-xr-xdeployment/build.debian.amd644
-rwxr-xr-xdeployment/build.debian.arm644
-rwxr-xr-xdeployment/build.debian.armhf4
-rwxr-xr-xdeployment/build.ubuntu.amd644
-rwxr-xr-xdeployment/build.ubuntu.arm644
-rwxr-xr-xdeployment/build.ubuntu.armhf4
-rw-r--r--fedora/jellyfin.spec2
-rw-r--r--tests/Jellyfin.Networking.Tests/NetworkParseTests.cs5
47 files changed, 395 insertions, 512 deletions
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 37aa7721e..c03564f97 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
- "version": "7.0.13",
+ "version": "8.0.0",
"commands": [
"dotnet-ef"
]
diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml
index 7e3059153..2a60d1805 100644
--- a/.github/workflows/ci-codeql-analysis.yml
+++ b/.github/workflows/ci-codeql-analysis.yml
@@ -27,11 +27,11 @@ jobs:
dotnet-version: '8.0.x'
- name: Initialize CodeQL
- uses: github/codeql-action/init@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6
+ uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
- uses: github/codeql-action/autobuild@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6
+ uses: github/codeql-action/autobuild@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6
+ uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index fff7136b8..d208879d1 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -172,6 +172,8 @@
- [sleepycatcoding](https://github.com/sleepycatcoding)
- [scampower3](https://github.com/scampower3)
- [Chris-Codes-It] (https://github.com/Chris-Codes-It)
+ - [Pithaya](https://github.com/Pithaya)
+ - [Çağrı Sakaoğlu](https://github.com/ilovepilav)
# Emby Contributors
@@ -242,4 +244,4 @@
- [Jakob Kukla](https://github.com/jakobkukla)
- [Utku Özdemir](https://github.com/utkuozdemir)
- [JPUC1143](https://github.com/Jpuc1143/)
- - [0x25CBFC4F](https://github.com/0x25CBFC4F) \ No newline at end of file
+ - [0x25CBFC4F](https://github.com/0x25CBFC4F)
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 0d7dbf12c..b5bf510f5 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,8 +5,8 @@
<!-- Run "dotnet list package (dash,dash)outdated" to see the latest versions of each package.-->
<ItemGroup Label="Package Dependencies">
<PackageVersion Include="AutoFixture.AutoMoq" Version="4.18.0" />
- <PackageVersion Include="AutoFixture.Xunit2" Version="4.18.0" />
- <PackageVersion Include="AutoFixture" Version="4.18.0" />
+ <PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1" />
+ <PackageVersion Include="AutoFixture" Version="4.18.1" />
<PackageVersion Include="BDInfo" Version="0.7.6.2" />
<PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.3.0" />
<PackageVersion Include="BlurHashSharp" Version="1.3.0" />
@@ -48,23 +48,22 @@
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
- <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="MimeTypes" Version="2.4.0" />
<PackageVersion Include="Mono.Nat" Version="3.0.4" />
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="NEbml" Version="0.11.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="PlaylistsNET" Version="1.4.0" />
- <PackageVersion Include="prometheus-net.AspNetCore" Version="8.1.0" />
+ <PackageVersion Include="prometheus-net.AspNetCore" Version="8.1.1" />
<PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.0" />
- <PackageVersion Include="prometheus-net" Version="8.1.0" />
- <PackageVersion Include="Serilog.AspNetCore" Version="7.0.0" />
+ <PackageVersion Include="prometheus-net" Version="8.1.1" />
+ <PackageVersion Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="3.1.0" />
- <PackageVersion Include="Serilog.Settings.Configuration" Version="7.0.1" />
+ <PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0" />
- <PackageVersion Include="Serilog.Sinks.Console" Version="5.0.0" />
+ <PackageVersion Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" />
- <PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.0" />
+ <PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.1" />
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
<PackageVersion Include="SharpFuzz" Version="2.1.1" />
<PackageVersion Include="SkiaSharp" Version="2.88.5" />
diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj
index 47f260550..97015efd0 100644
--- a/Emby.Naming/Emby.Naming.csproj
+++ b/Emby.Naming/Emby.Naming.csproj
@@ -41,10 +41,6 @@
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
- <ItemGroup>
- <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
- </ItemGroup>
-
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="IDisposableAnalyzers">
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index be36bbd2c..a83d7a410 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -1,7 +1,3 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -23,476 +19,382 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
-namespace Emby.Server.Implementations.EntryPoints
+namespace Emby.Server.Implementations.EntryPoints;
+
+/// <summary>
+/// A <see cref="IServerEntryPoint"/> that notifies users when libraries are updated.
+/// </summary>
+public sealed class LibraryChangedNotifier : IServerEntryPoint
{
- public class LibraryChangedNotifier : IServerEntryPoint
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _configurationManager;
+ private readonly IProviderManager _providerManager;
+ private readonly ISessionManager _sessionManager;
+ private readonly IUserManager _userManager;
+ private readonly ILogger<LibraryChangedNotifier> _logger;
+
+ private readonly object _libraryChangedSyncLock = new();
+ private readonly List<Folder> _foldersAddedTo = new();
+ private readonly List<Folder> _foldersRemovedFrom = new();
+ private readonly List<BaseItem> _itemsAdded = new();
+ private readonly List<BaseItem> _itemsRemoved = new();
+ private readonly List<BaseItem> _itemsUpdated = new();
+ private readonly ConcurrentDictionary<Guid, DateTime> _lastProgressMessageTimes = new();
+
+ private Timer? _libraryUpdateTimer;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LibraryChangedNotifier"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The <see cref="ILibraryManager"/>.</param>
+ /// <param name="configurationManager">The <see cref="IServerConfigurationManager"/>.</param>
+ /// <param name="sessionManager">The <see cref="ISessionManager"/>.</param>
+ /// <param name="userManager">The <see cref="IUserManager"/>.</param>
+ /// <param name="logger">The <see cref="ILogger"/>.</param>
+ /// <param name="providerManager">The <see cref="IProviderManager"/>.</param>
+ public LibraryChangedNotifier(
+ ILibraryManager libraryManager,
+ IServerConfigurationManager configurationManager,
+ ISessionManager sessionManager,
+ IUserManager userManager,
+ ILogger<LibraryChangedNotifier> logger,
+ IProviderManager providerManager)
{
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _configurationManager;
- private readonly IProviderManager _providerManager;
- private readonly ISessionManager _sessionManager;
- private readonly IUserManager _userManager;
- private readonly ILogger<LibraryChangedNotifier> _logger;
-
- /// <summary>
- /// The library changed sync lock.
- /// </summary>
- private readonly object _libraryChangedSyncLock = new object();
-
- private readonly List<Folder> _foldersAddedTo = new List<Folder>();
- private readonly List<Folder> _foldersRemovedFrom = new List<Folder>();
- private readonly List<BaseItem> _itemsAdded = new List<BaseItem>();
- private readonly List<BaseItem> _itemsRemoved = new List<BaseItem>();
- private readonly List<BaseItem> _itemsUpdated = new List<BaseItem>();
- private readonly ConcurrentDictionary<Guid, DateTime> _lastProgressMessageTimes = new ConcurrentDictionary<Guid, DateTime>();
-
- public LibraryChangedNotifier(
- ILibraryManager libraryManager,
- IServerConfigurationManager configurationManager,
- ISessionManager sessionManager,
- IUserManager userManager,
- ILogger<LibraryChangedNotifier> logger,
- IProviderManager providerManager)
- {
- _libraryManager = libraryManager;
- _configurationManager = configurationManager;
- _sessionManager = sessionManager;
- _userManager = userManager;
- _logger = logger;
- _providerManager = providerManager;
- }
+ _libraryManager = libraryManager;
+ _configurationManager = configurationManager;
+ _sessionManager = sessionManager;
+ _userManager = userManager;
+ _logger = logger;
+ _providerManager = providerManager;
+ }
- /// <summary>
- /// Gets or sets the library update timer.
- /// </summary>
- /// <value>The library update timer.</value>
- private Timer LibraryUpdateTimer { get; set; }
+ /// <inheritdoc />
+ public Task RunAsync()
+ {
+ _libraryManager.ItemAdded += OnLibraryItemAdded;
+ _libraryManager.ItemUpdated += OnLibraryItemUpdated;
+ _libraryManager.ItemRemoved += OnLibraryItemRemoved;
- public Task RunAsync()
- {
- _libraryManager.ItemAdded += OnLibraryItemAdded;
- _libraryManager.ItemUpdated += OnLibraryItemUpdated;
- _libraryManager.ItemRemoved += OnLibraryItemRemoved;
+ _providerManager.RefreshCompleted += OnProviderRefreshCompleted;
+ _providerManager.RefreshStarted += OnProviderRefreshStarted;
+ _providerManager.RefreshProgress += OnProviderRefreshProgress;
- _providerManager.RefreshCompleted += OnProviderRefreshCompleted;
- _providerManager.RefreshStarted += OnProviderRefreshStarted;
- _providerManager.RefreshProgress += OnProviderRefreshProgress;
+ return Task.CompletedTask;
+ }
- return Task.CompletedTask;
- }
+ private void OnProviderRefreshProgress(object? sender, GenericEventArgs<Tuple<BaseItem, double>> e)
+ {
+ var item = e.Argument.Item1;
- private void OnProviderRefreshProgress(object sender, GenericEventArgs<Tuple<BaseItem, double>> e)
+ if (!EnableRefreshMessage(item))
{
- var item = e.Argument.Item1;
+ return;
+ }
- if (!EnableRefreshMessage(item))
+ var progress = e.Argument.Item2;
+
+ if (_lastProgressMessageTimes.TryGetValue(item.Id, out var lastMessageSendTime))
+ {
+ if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000)
{
return;
}
+ }
- var progress = e.Argument.Item2;
+ _lastProgressMessageTimes.AddOrUpdate(item.Id, _ => DateTime.UtcNow, (_, _) => DateTime.UtcNow);
- if (_lastProgressMessageTimes.TryGetValue(item.Id, out var lastMessageSendTime))
- {
- if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000)
- {
- return;
- }
- }
+ var dict = new Dictionary<string, string>();
+ dict["ItemId"] = item.Id.ToString("N", CultureInfo.InvariantCulture);
+ dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture);
- _lastProgressMessageTimes.AddOrUpdate(item.Id, _ => DateTime.UtcNow, (_, _) => DateTime.UtcNow);
+ try
+ {
+ _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, dict, CancellationToken.None);
+ }
+ catch
+ {
+ }
- var dict = new Dictionary<string, string>();
- dict["ItemId"] = item.Id.ToString("N", CultureInfo.InvariantCulture);
- dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture);
+ var collectionFolders = _libraryManager.GetCollectionFolders(item);
+
+ foreach (var collectionFolder in collectionFolders)
+ {
+ var collectionFolderDict = new Dictionary<string, string>
+ {
+ ["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
+ ["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture)
+ };
try
{
- _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, dict, CancellationToken.None);
+ _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, collectionFolderDict, CancellationToken.None);
}
catch
{
}
+ }
+ }
- var collectionFolders = _libraryManager.GetCollectionFolders(item);
+ private void OnProviderRefreshStarted(object? sender, GenericEventArgs<BaseItem> e)
+ {
+ OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0)));
+ }
- foreach (var collectionFolder in collectionFolders)
- {
- var collectionFolderDict = new Dictionary<string, string>
- {
- ["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
- ["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture)
- };
-
- try
- {
- _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, collectionFolderDict, CancellationToken.None);
- }
- catch
- {
- }
- }
- }
+ private void OnProviderRefreshCompleted(object? sender, GenericEventArgs<BaseItem> e)
+ {
+ OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100)));
- private void OnProviderRefreshStarted(object sender, GenericEventArgs<BaseItem> e)
- {
- OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0)));
- }
+ _lastProgressMessageTimes.TryRemove(e.Argument.Id, out _);
+ }
- private void OnProviderRefreshCompleted(object sender, GenericEventArgs<BaseItem> e)
- {
- OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100)));
+ private static bool EnableRefreshMessage(BaseItem item)
+ => item is Folder { IsRoot: false, IsTopParent: true }
+ and not (AggregateFolder or UserRootFolder or UserView or Channel);
- _lastProgressMessageTimes.TryRemove(e.Argument.Id, out _);
- }
+ private void OnLibraryItemAdded(object? sender, ItemChangeEventArgs e)
+ => OnLibraryChange(e.Item, e.Parent, _itemsAdded, _foldersAddedTo);
- private static bool EnableRefreshMessage(BaseItem item)
+ private void OnLibraryItemUpdated(object? sender, ItemChangeEventArgs e)
+ => OnLibraryChange(e.Item, e.Parent, _itemsUpdated, null);
+
+ private void OnLibraryItemRemoved(object? sender, ItemChangeEventArgs e)
+ => OnLibraryChange(e.Item, e.Parent, _itemsRemoved, _foldersRemovedFrom);
+
+ private void OnLibraryChange(BaseItem item, BaseItem parent, List<BaseItem> itemsList, List<Folder>? foldersList)
+ {
+ if (!FilterItem(item))
{
- if (item is not Folder folder)
- {
- return false;
- }
+ return;
+ }
- if (folder.IsRoot)
- {
- return false;
- }
+ lock (_libraryChangedSyncLock)
+ {
+ var updateDuration = TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration);
- if (folder is AggregateFolder || folder is UserRootFolder)
+ if (_libraryUpdateTimer is null)
{
- return false;
+ _libraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, updateDuration, Timeout.InfiniteTimeSpan);
}
-
- if (folder is UserView || folder is Channel)
+ else
{
- return false;
+ _libraryUpdateTimer.Change(updateDuration, Timeout.InfiniteTimeSpan);
}
- if (!folder.IsTopParent)
+ if (foldersList is not null && parent is Folder folder)
{
- return false;
+ foldersList.Add(folder);
}
- return true;
+ itemsList.Add(item);
}
+ }
- /// <summary>
- /// Handles the ItemAdded event of the libraryManager control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
- private void OnLibraryItemAdded(object sender, ItemChangeEventArgs e)
+ private async void LibraryUpdateTimerCallback(object? state)
+ {
+ List<Folder> foldersAddedTo;
+ List<Folder> foldersRemovedFrom;
+ List<BaseItem> itemsUpdated;
+ List<BaseItem> itemsAdded;
+ List<BaseItem> itemsRemoved;
+ lock (_libraryChangedSyncLock)
{
- if (!FilterItem(e.Item))
- {
- return;
- }
+ // Remove dupes in case some were saved multiple times
+ foldersAddedTo = _foldersAddedTo
+ .DistinctBy(x => x.Id)
+ .ToList();
- lock (_libraryChangedSyncLock)
+ foldersRemovedFrom = _foldersRemovedFrom
+ .DistinctBy(x => x.Id)
+ .ToList();
+
+ itemsUpdated = _itemsUpdated
+ .Where(i => !_itemsAdded.Contains(i))
+ .DistinctBy(x => x.Id)
+ .ToList();
+
+ itemsAdded = _itemsAdded.ToList();
+ itemsRemoved = _itemsRemoved.ToList();
+
+ if (_libraryUpdateTimer is not null)
{
- if (LibraryUpdateTimer is null)
- {
- LibraryUpdateTimer = new Timer(
- LibraryUpdateTimerCallback,
- null,
- TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration),
- Timeout.InfiniteTimeSpan);
- }
- else
- {
- LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan);
- }
-
- if (e.Item.GetParent() is Folder parent)
- {
- _foldersAddedTo.Add(parent);
- }
-
- _itemsAdded.Add(e.Item);
+ _libraryUpdateTimer.Dispose();
+ _libraryUpdateTimer = null;
}
+
+ _itemsAdded.Clear();
+ _itemsRemoved.Clear();
+ _itemsUpdated.Clear();
+ _foldersAddedTo.Clear();
+ _foldersRemovedFrom.Clear();
}
- /// <summary>
- /// Handles the ItemUpdated event of the libraryManager control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
- private void OnLibraryItemUpdated(object sender, ItemChangeEventArgs e)
+ await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ private async Task SendChangeNotifications(
+ List<BaseItem> itemsAdded,
+ List<BaseItem> itemsUpdated,
+ List<BaseItem> itemsRemoved,
+ List<Folder> foldersAddedTo,
+ List<Folder> foldersRemovedFrom,
+ CancellationToken cancellationToken)
+ {
+ var userIds = _sessionManager.Sessions
+ .Select(i => i.UserId)
+ .Where(i => !i.Equals(default))
+ .Distinct()
+ .ToArray();
+
+ foreach (var userId in userIds)
{
- if (!FilterItem(e.Item))
- {
- return;
- }
+ LibraryUpdateInfo info;
- lock (_libraryChangedSyncLock)
+ try
{
- if (LibraryUpdateTimer is null)
- {
- LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan);
- }
- else
- {
- LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan);
- }
-
- _itemsUpdated.Add(e.Item);
+ info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, userId);
}
- }
-
- /// <summary>
- /// Handles the ItemRemoved event of the libraryManager control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
- private void OnLibraryItemRemoved(object sender, ItemChangeEventArgs e)
- {
- if (!FilterItem(e.Item))
+ catch (Exception ex)
{
+ _logger.LogError(ex, "Error in GetLibraryUpdateInfo");
return;
}
- lock (_libraryChangedSyncLock)
+ if (info.IsEmpty)
{
- if (LibraryUpdateTimer is null)
- {
- LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan);
- }
- else
- {
- LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan);
- }
-
- if (e.Parent is Folder parent)
- {
- _foldersRemovedFrom.Add(parent);
- }
-
- _itemsRemoved.Add(e.Item);
+ continue;
}
- }
- /// <summary>
- /// Libraries the update timer callback.
- /// </summary>
- /// <param name="state">The state.</param>
- private async void LibraryUpdateTimerCallback(object state)
- {
- List<Folder> foldersAddedTo;
- List<Folder> foldersRemovedFrom;
- List<BaseItem> itemsUpdated;
- List<BaseItem> itemsAdded;
- List<BaseItem> itemsRemoved;
- lock (_libraryChangedSyncLock)
+ try
{
- // Remove dupes in case some were saved multiple times
- foldersAddedTo = _foldersAddedTo
- .DistinctBy(x => x.Id)
- .ToList();
-
- foldersRemovedFrom = _foldersRemovedFrom
- .DistinctBy(x => x.Id)
- .ToList();
-
- itemsUpdated = _itemsUpdated
- .Where(i => !_itemsAdded.Contains(i))
- .DistinctBy(x => x.Id)
- .ToList();
-
- itemsAdded = _itemsAdded.ToList();
- itemsRemoved = _itemsRemoved.ToList();
-
- if (LibraryUpdateTimer is not null)
- {
- LibraryUpdateTimer.Dispose();
- LibraryUpdateTimer = null;
- }
-
- _itemsAdded.Clear();
- _itemsRemoved.Clear();
- _itemsUpdated.Clear();
- _foldersAddedTo.Clear();
- _foldersRemovedFrom.Clear();
+ await _sessionManager.SendMessageToUserSessions(
+ new List<Guid> { userId },
+ SessionMessageType.LibraryChanged,
+ info,
+ cancellationToken)
+ .ConfigureAwait(false);
}
-
- await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Sends the change notifications.
- /// </summary>
- /// <param name="itemsAdded">The items added.</param>
- /// <param name="itemsUpdated">The items updated.</param>
- /// <param name="itemsRemoved">The items removed.</param>
- /// <param name="foldersAddedTo">The folders added to.</param>
- /// <param name="foldersRemovedFrom">The folders removed from.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- private async Task SendChangeNotifications(List<BaseItem> itemsAdded, List<BaseItem> itemsUpdated, List<BaseItem> itemsRemoved, List<Folder> foldersAddedTo, List<Folder> foldersRemovedFrom, CancellationToken cancellationToken)
- {
- var userIds = _sessionManager.Sessions
- .Select(i => i.UserId)
- .Where(i => !i.Equals(default))
- .Distinct()
- .ToArray();
-
- foreach (var userId in userIds)
+ catch (Exception ex)
{
- LibraryUpdateInfo info;
-
- try
- {
- info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, userId);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error in GetLibraryUpdateInfo");
- return;
- }
-
- if (info.IsEmpty)
- {
- continue;
- }
-
- try
- {
- await _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, SessionMessageType.LibraryChanged, info, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error sending LibraryChanged message");
- }
+ _logger.LogError(ex, "Error sending LibraryChanged message");
}
}
+ }
- /// <summary>
- /// Gets the library update info.
- /// </summary>
- /// <param name="itemsAdded">The items added.</param>
- /// <param name="itemsUpdated">The items updated.</param>
- /// <param name="itemsRemoved">The items removed.</param>
- /// <param name="foldersAddedTo">The folders added to.</param>
- /// <param name="foldersRemovedFrom">The folders removed from.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>LibraryUpdateInfo.</returns>
- private LibraryUpdateInfo GetLibraryUpdateInfo(List<BaseItem> itemsAdded, List<BaseItem> itemsUpdated, List<BaseItem> itemsRemoved, List<Folder> foldersAddedTo, List<Folder> foldersRemovedFrom, Guid userId)
- {
- var user = _userManager.GetUserById(userId);
-
- var newAndRemoved = new List<BaseItem>();
- newAndRemoved.AddRange(foldersAddedTo);
- newAndRemoved.AddRange(foldersRemovedFrom);
-
- var allUserRootChildren = _libraryManager.GetUserRootFolder().GetChildren(user, true).OfType<Folder>().ToList();
-
- return new LibraryUpdateInfo
- {
- ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
-
- ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
-
- ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
+ private LibraryUpdateInfo GetLibraryUpdateInfo(
+ List<BaseItem> itemsAdded,
+ List<BaseItem> itemsUpdated,
+ List<BaseItem> itemsRemoved,
+ List<Folder> foldersAddedTo,
+ List<Folder> foldersRemovedFrom,
+ Guid userId)
+ {
+ var user = _userManager.GetUserById(userId);
+ ArgumentNullException.ThrowIfNull(user);
- FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
+ var newAndRemoved = new List<BaseItem>();
+ newAndRemoved.AddRange(foldersAddedTo);
+ newAndRemoved.AddRange(foldersRemovedFrom);
- FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
+ var allUserRootChildren = _libraryManager.GetUserRootFolder()
+ .GetChildren(user, true)
+ .OfType<Folder>()
+ .ToList();
- CollectionFolders = GetTopParentIds(newAndRemoved, allUserRootChildren).ToArray()
- };
- }
-
- private static bool FilterItem(BaseItem item)
+ return new LibraryUpdateInfo
{
- if (!item.IsFolder && !item.HasPathProtocol)
- {
- return false;
- }
-
- if (item is IItemByName && item is not MusicArtist)
- {
- return false;
- }
+ ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .Distinct()
+ .ToArray(),
+ ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .Distinct()
+ .ToArray(),
+ ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .Distinct()
+ .ToArray(),
+ FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .Distinct()
+ .ToArray(),
+ FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .Distinct()
+ .ToArray(),
+ CollectionFolders = GetTopParentIds(newAndRemoved, allUserRootChildren).ToArray()
+ };
+ }
- return item.SourceType == SourceType.Library;
+ private static bool FilterItem(BaseItem item)
+ {
+ if (!item.IsFolder && !item.HasPathProtocol)
+ {
+ return false;
}
- private IEnumerable<string> GetTopParentIds(List<BaseItem> items, List<Folder> allUserRootChildren)
+ if (item is IItemByName && item is not MusicArtist)
{
- var list = new List<string>();
+ return false;
+ }
- foreach (var item in items)
- {
- // If the physical root changed, return the user root
- if (item is AggregateFolder)
- {
- continue;
- }
-
- foreach (var folder in allUserRootChildren)
- {
- list.Add(folder.Id.ToString("N", CultureInfo.InvariantCulture));
- }
- }
+ return item.SourceType == SourceType.Library;
+ }
- return list.Distinct(StringComparer.Ordinal);
- }
+ private IEnumerable<string> GetTopParentIds(List<BaseItem> items, List<Folder> allUserRootChildren)
+ {
+ var list = new List<string>();
- /// <summary>
- /// Translates the physical item to user library.
- /// </summary>
- /// <typeparam name="T">The type of item.</typeparam>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <param name="includeIfNotFound">if set to <c>true</c> [include if not found].</param>
- /// <returns>IEnumerable{``0}.</returns>
- private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, bool includeIfNotFound = false)
- where T : BaseItem
+ foreach (var item in items)
{
// If the physical root changed, return the user root
if (item is AggregateFolder)
{
- return new[] { _libraryManager.GetUserRootFolder() as T };
+ continue;
}
- // Return it only if it's in the user's library
- if (includeIfNotFound || item.IsVisibleStandalone(user))
+ foreach (var folder in allUserRootChildren)
{
- return new[] { item };
+ list.Add(folder.Id.ToString("N", CultureInfo.InvariantCulture));
}
+ }
- return Array.Empty<T>();
+ return list.Distinct(StringComparer.Ordinal);
+ }
+
+ private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, bool includeIfNotFound = false)
+ where T : BaseItem
+ {
+ // If the physical root changed, return the user root
+ if (item is AggregateFolder)
+ {
+ return _libraryManager.GetUserRootFolder() is T t ? new[] { t } : Array.Empty<T>();
}
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
+ // Return it only if it's in the user's library
+ if (includeIfNotFound || item.IsVisibleStandalone(user))
{
- Dispose(true);
- GC.SuppressFinalize(this);
+ return new[] { item };
}
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
+ return Array.Empty<T>();
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ _libraryManager.ItemAdded -= OnLibraryItemAdded;
+ _libraryManager.ItemUpdated -= OnLibraryItemUpdated;
+ _libraryManager.ItemRemoved -= OnLibraryItemRemoved;
+
+ _providerManager.RefreshCompleted -= OnProviderRefreshCompleted;
+ _providerManager.RefreshStarted -= OnProviderRefreshStarted;
+ _providerManager.RefreshProgress -= OnProviderRefreshProgress;
+
+ if (_libraryUpdateTimer is not null)
{
- if (dispose)
- {
- if (LibraryUpdateTimer is not null)
- {
- LibraryUpdateTimer.Dispose();
- LibraryUpdateTimer = null;
- }
-
- _libraryManager.ItemAdded -= OnLibraryItemAdded;
- _libraryManager.ItemUpdated -= OnLibraryItemUpdated;
- _libraryManager.ItemRemoved -= OnLibraryItemRemoved;
-
- _providerManager.RefreshCompleted -= OnProviderRefreshCompleted;
- _providerManager.RefreshStarted -= OnProviderRefreshStarted;
- _providerManager.RefreshProgress -= OnProviderRefreshProgress;
- }
+ _libraryUpdateTimer.Dispose();
+ _libraryUpdateTimer = null;
}
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 93d50e6e3..ecdc01a3d 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -124,5 +124,6 @@
"TaskKeyframeExtractorDescription": "يستخرج الإطارات الرئيسية من ملفات الفيديو لكي ينشئ قوائم تشغيل بث HTTP المباشر. قد تستمر هذه العملية لوقت طويل.",
"TaskKeyframeExtractor": "مستخرج الإطار الرئيسي",
"External": "خارجي",
- "HearingImpaired": "ضعاف السمع"
+ "HearingImpaired": "ضعاف السمع",
+ "TaskRefreshTrickplayImages": "توليد صور Trickplay"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hi.json b/Emby.Server.Implementations/Localization/Core/hi.json
index 47d3eeac5..3f4dea523 100644
--- a/Emby.Server.Implementations/Localization/Core/hi.json
+++ b/Emby.Server.Implementations/Localization/Core/hi.json
@@ -12,17 +12,17 @@
"HeaderAlbumArtists": "एल्बम कलाकार",
"Genres": "शैली",
"Forced": "बलपूर्वक",
- "Folders": "फोल्डेरें",
+ "Folders": "फ़ोल्डरें",
"Favorites": "पसंदीदा",
- "FailedLoginAttemptWithUserName": "लॉगिन असफल हुआ, पुनः {0} से प्रयास करें",
+ "FailedLoginAttemptWithUserName": "{0} से लॉगिन असफल हुआ",
"DeviceOnlineWithName": "{0} से संयोग हो गया है",
"DeviceOfflineWithName": "{0} से संयोग विच्छिन्न हो गया है",
"Default": "प्राथमिक",
- "Collections": "संग्रह",
+ "Collections": "संग्रहों",
"ChapterNameValue": "अध्याय",
"Channels": "चैनल",
- "CameraImageUploadedFrom": "कैमरा से एक नया चित्र अपलोड किया गया है",
- "Books": "किताब",
+ "CameraImageUploadedFrom": "{0} से एक नया कैमरावाला चित्र अपलोड किया गया है",
+ "Books": "पुस्तकों",
"AuthenticationSucceededWithUserName": "सफलता से प्रमाणीकृत",
"Artists": "कलाकारों",
"Application": "एप्लिकेशन",
@@ -123,5 +123,7 @@
"TaskRefreshPeopleDescription": "आपकी मीडिया लाइब्रेरी में अभिनेताओं और निर्देशकों के लिए मेटाडेटा अपडेट करता है।",
"TaskCleanCache": "स्वच्छ कैश निर्देशिका",
"TaskDownloadMissingSubtitlesDescription": "मेटाडेटा कॉन्फ़िगरेशन के आधार पर लापता उपशीर्षक के लिए इंटरनेट खोजता है।",
- "TaskKeyframeExtractorDescription": "अधिक सटीक एचएलएस प्लेलिस्ट बनाने के लिए वीडियो फ़ाइलों से मुख्य-फ़्रेम निकालता है। यह कार्य लंबे समय तक चल सकता है।"
+ "TaskKeyframeExtractorDescription": "अधिक सटीक एचएलएस प्लेलिस्ट बनाने के लिए वीडियो फ़ाइलों से मुख्य-फ़्रेम निकालता है। यह कार्य लंबे समय तक चल सकता है।",
+ "TaskRefreshTrickplayImages": "ट्रिकप्लै चित्रों को सृजन करे",
+ "TaskRefreshTrickplayImagesDescription": "नियत संग्रहों में चलचित्रों का ट्रीकप्लै दर्शनों को सृजन करे."
}
diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json
index 87ce07da3..78a443348 100644
--- a/Emby.Server.Implementations/Localization/Core/id.json
+++ b/Emby.Server.Implementations/Localization/Core/id.json
@@ -13,7 +13,7 @@
"HomeVideos": "Video Rumahan",
"HeaderRecordingGroups": "Grup Rekaman",
"HeaderNextUp": "Selanjutnya",
- "HeaderLiveTV": "TV Live",
+ "HeaderLiveTV": "Siaran langsung",
"HeaderFavoriteSongs": "Lagu Favorit",
"HeaderFavoriteShows": "Tayangan Favorit",
"HeaderFavoriteEpisodes": "Episode Favorit",
@@ -123,5 +123,7 @@
"TaskKeyframeExtractorDescription": "Ekstrak bingkai utama dari file video untuk membuat daftar putar HLS yang lebih tepat. Tugas ini dapat berjalan untuk waktu yang lama.",
"TaskKeyframeExtractor": "Ekstraktor Bingkai Utama",
"External": "Luar",
- "HearingImpaired": "Gangguan Pendengaran"
+ "HearingImpaired": "Gangguan Pendengaran",
+ "TaskRefreshTrickplayImages": "Hasilkan Gambar Trickplay",
+ "TaskRefreshTrickplayImagesDescription": "Buat pratinjau trickplay untuk video di perpustakaan yang diaktifkan."
}
diff --git a/Emby.Server.Implementations/Localization/Core/mr.json b/Emby.Server.Implementations/Localization/Core/mr.json
index a8fb26b91..13c58e0ab 100644
--- a/Emby.Server.Implementations/Localization/Core/mr.json
+++ b/Emby.Server.Implementations/Localization/Core/mr.json
@@ -123,5 +123,7 @@
"DeviceOnlineWithName": "{0} कनेक्ट झाले",
"DeviceOfflineWithName": "{0} डिस्कनेक्ट झाला आहे",
"AuthenticationSucceededWithUserName": "{0} यशस्वीरित्या प्रमाणीकृत",
- "HearingImpaired": "कर्णबधीर"
+ "HearingImpaired": "कर्णबधीर",
+ "TaskRefreshTrickplayImages": "ट्रिकप्ले प्रतिमा तयार करा",
+ "TaskRefreshTrickplayImagesDescription": "सक्षम लायब्ररीमधील व्हिडिओंसाठी ट्रिकप्ले पूर्वावलोकन तयार करते."
}
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index b9b93b7b6..2c8c46050 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -124,5 +124,7 @@
"TaskKeyframeExtractor": "Extrator de quadro-chave",
"TaskKeyframeExtractorDescription": "Extrai quadros-chave de arquivos de vídeo para criar listas de reprodução HLS mais precisas. Esta tarefa pode ser executada por um longo tempo.",
"External": "Externo",
- "HearingImpaired": "Deficiência Auditiva"
+ "HearingImpaired": "Deficiência Auditiva",
+ "TaskRefreshTrickplayImages": "Gerar imagens Trickplay",
+ "TaskRefreshTrickplayImagesDescription": "Cria prévias Trickplay para vídeos em bibliotecas em que o recurso está habilitado."
}
diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json
index 3ce928859..b28bfaf24 100644
--- a/Emby.Server.Implementations/Localization/Core/tr.json
+++ b/Emby.Server.Implementations/Localization/Core/tr.json
@@ -124,5 +124,7 @@
"TaskKeyframeExtractorDescription": "Daha hassas HLS çalma listeleri oluşturmak için video dosyalarından kareleri çıkarır. Bu görev uzun bir süre çalışabilir.",
"TaskKeyframeExtractor": "Kare Ayırt Edici",
"External": "Harici",
- "HearingImpaired": "Duyma engelli"
+ "HearingImpaired": "Duyma engelli",
+ "TaskRefreshTrickplayImages": "Trickplay Görselleri Oluştur",
+ "TaskRefreshTrickplayImagesDescription": "Etkin kütüphanelerdeki videolar için trickplay önizlemeleri oluşturur."
}
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index c717744b1..15c4cfdf0 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -321,9 +321,15 @@ namespace Emby.Server.Implementations.Updates
}
_completedInstallationsInternal.Add(package);
- await _eventManager.PublishAsync(isUpdate
- ? (GenericEventArgs<InstallationInfo>)new PluginUpdatedEventArgs(package)
- : new PluginInstalledEventArgs(package)).ConfigureAwait(false);
+
+ if (isUpdate)
+ {
+ await _eventManager.PublishAsync(new PluginUpdatedEventArgs(package)).ConfigureAwait(false);
+ }
+ else
+ {
+ await _eventManager.PublishAsync(new PluginInstalledEventArgs(package)).ConfigureAwait(false);
+ }
_applicationHost.NotifyPendingRestart();
}
@@ -551,8 +557,7 @@ namespace Emby.Server.Implementations.Updates
}
stream.Position = 0;
- using var reader = new ZipArchive(stream);
- reader.ExtractToDirectory(targetDir, true);
+ ZipFile.ExtractToDirectory(stream, targetDir, true);
// Ensure we create one or populate existing ones with missing data.
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status).ConfigureAwait(false);
diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj
index c26e6cf23..75912abf0 100644
--- a/Jellyfin.Data/Jellyfin.Data.csproj
+++ b/Jellyfin.Data/Jellyfin.Data.csproj
@@ -23,10 +23,6 @@
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
- <ItemGroup>
- <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
- </ItemGroup>
-
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="IDisposableAnalyzers">
diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
index ce1c54cbb..54272aeaf 100644
--- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
+++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
@@ -68,7 +68,6 @@ namespace Jellyfin.Server.Implementations.Activity
Date = entity.DateCreated,
Severity = entity.LogSeverity
})
- .AsQueryable()
.ToListAsync()
.ConfigureAwait(false));
}
@@ -80,11 +79,10 @@ namespace Jellyfin.Server.Implementations.Activity
var dbContext = await _provider.CreateDbContextAsync().ConfigureAwait(false);
await using (dbContext.ConfigureAwait(false))
{
- var entries = dbContext.ActivityLogs
- .Where(entry => entry.DateCreated <= startDate);
-
- dbContext.RemoveRange(entries);
- await dbContext.SaveChangesAsync().ConfigureAwait(false);
+ await dbContext.ActivityLogs
+ .Where(entry => entry.DateCreated <= startDate)
+ .ExecuteDeleteAsync()
+ .ConfigureAwait(false);
}
}
diff --git a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs
index b2dfe60a1..07ac27e3c 100644
--- a/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs
+++ b/Jellyfin.Server.Implementations/Security/AuthenticationManager.cs
@@ -58,19 +58,10 @@ namespace Jellyfin.Server.Implementations.Security
var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
await using (dbContext.ConfigureAwait(false))
{
- var key = await dbContext.ApiKeys
+ await dbContext.ApiKeys
.Where(apiKey => apiKey.AccessToken == accessToken)
- .FirstOrDefaultAsync()
+ .ExecuteDeleteAsync()
.ConfigureAwait(false);
-
- if (key is null)
- {
- return;
- }
-
- dbContext.Remove(key);
-
- await dbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
}
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 9b3ea4368..8ad626b41 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -21,7 +21,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
- <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Common/Net/NetworkUtils.cs b/MediaBrowser.Common/Net/NetworkUtils.cs
index 4110b000e..e482089f0 100644
--- a/MediaBrowser.Common/Net/NetworkUtils.cs
+++ b/MediaBrowser.Common/Net/NetworkUtils.cs
@@ -197,46 +197,29 @@ public static partial class NetworkUtils
/// <returns><c>True</c> if parsing was successful.</returns>
public static bool TryParseToSubnet(ReadOnlySpan<char> value, [NotNullWhen(true)] out IPNetwork? result, bool negated = false)
{
- var splitString = value.Trim().Split('/');
- if (splitString.MoveNext())
+ value = value.Trim();
+ if (value.Contains('/'))
{
- var ipBlock = splitString.Current;
- var address = IPAddress.None;
- if (negated && ipBlock.StartsWith("!") && IPAddress.TryParse(ipBlock[1..], out var tmpAddress))
+ if (negated && value.StartsWith("!") && IPNetwork.TryParse(value[1..], out result))
{
- address = tmpAddress;
+ return true;
}
- else if (!negated && IPAddress.TryParse(ipBlock, out tmpAddress))
+ else if (!negated && IPNetwork.TryParse(value, out result))
{
- address = tmpAddress;
+ return true;
}
-
- if (address != IPAddress.None)
+ }
+ else if (IPAddress.TryParse(value, out var address))
+ {
+ if (address.AddressFamily == AddressFamily.InterNetwork)
{
- if (splitString.MoveNext())
- {
- var subnetBlock = splitString.Current;
- if (int.TryParse(subnetBlock, out var netmask))
- {
- result = new IPNetwork(address, netmask);
- return true;
- }
- else if (IPAddress.TryParse(subnetBlock, out var netmaskAddress))
- {
- result = new IPNetwork(address, NetworkUtils.MaskToCidr(netmaskAddress));
- return true;
- }
- }
- else if (address.AddressFamily == AddressFamily.InterNetwork)
- {
- result = address.Equals(IPAddress.Any) ? NetworkConstants.IPv4Any : new IPNetwork(address, NetworkConstants.MinimumIPv4PrefixSize);
- return true;
- }
- else if (address.AddressFamily == AddressFamily.InterNetworkV6)
- {
- result = address.Equals(IPAddress.IPv6Any) ? NetworkConstants.IPv6Any : new IPNetwork(address, NetworkConstants.MinimumIPv6PrefixSize);
- return true;
- }
+ result = address.Equals(IPAddress.Any) ? NetworkConstants.IPv4Any : new IPNetwork(address, NetworkConstants.MinimumIPv4PrefixSize);
+ return true;
+ }
+ else if (address.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ result = address.Equals(IPAddress.IPv6Any) ? NetworkConstants.IPv6Any : new IPNetwork(address, NetworkConstants.MinimumIPv6PrefixSize);
+ return true;
}
}
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 63f9180fd..66dea1084 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -25,6 +25,9 @@ namespace MediaBrowser.Controller.Entities
public override bool SupportsPositionTicksResume => true;
[JsonIgnore]
+ public override bool SupportsPeople => true;
+
+ [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; }
[JsonIgnore]
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 83faac337..f237993fd 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -20,7 +20,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
- <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="System.Threading.Tasks.Dataflow" />
</ItemGroup>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 89ec156a9..7af46f8a0 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -34,7 +34,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.HttpOverrides" />
- <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="MimeTypes">
<PrivateAssets>all</PrivateAssets>
diff --git a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs
index 5303c8f58..ef518369c 100644
--- a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs
+++ b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs
@@ -66,6 +66,11 @@ namespace MediaBrowser.Model.Providers
/// <summary>
/// A music track.
/// </summary>
- Track = 12
+ Track = 12,
+
+ /// <summary>
+ /// A book.
+ /// </summary>
+ Book = 13
}
}
diff --git a/README.md b/README.md
index 911d9a094..15dd0ae67 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,7 @@ These instructions will help you get set up with a local development environment
### Prerequisites
-Before the project can be built, you must first install the [.NET 7.0 SDK](https://dotnet.microsoft.com/download/dotnet) on your system.
+Before the project can be built, you must first install the [.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet) on your system.
Instructions to run this project from the command line are included here, but you will also need to install an IDE if you want to debug the server while it is running. Any IDE that supports .NET 6 development will work, but two options are recent versions of [Visual Studio](https://visualstudio.microsoft.com/downloads/) (at least 2022) and [Visual Studio Code](https://code.visualstudio.com/Download).
diff --git a/debian/control b/debian/control
index 0b9dd570e..5e0460de9 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: misc
Priority: optional
Maintainer: Jellyfin Team <team@jellyfin.org>
Build-Depends: debhelper (>= 9),
- dotnet-sdk-7.0,
+ dotnet-sdk-8.0,
libc6-dev,
libcurl4-openssl-dev,
libfontconfig1-dev,
diff --git a/deployment/Dockerfile.debian.amd64 b/deployment/Dockerfile.debian.amd64
index 1e1f6e54e..d344c5964 100644
--- a/deployment/Dockerfile.debian.amd64
+++ b/deployment/Dockerfile.debian.amd64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.debian.arm64 b/deployment/Dockerfile.debian.arm64
index bbed2c534..8a5411f05 100644
--- a/deployment/Dockerfile.debian.arm64
+++ b/deployment/Dockerfile.debian.arm64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.debian.armhf b/deployment/Dockerfile.debian.armhf
index 79373519c..e95ba1696 100644
--- a/deployment/Dockerfile.debian.armhf
+++ b/deployment/Dockerfile.debian.armhf
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.docker.amd64 b/deployment/Dockerfile.docker.amd64
index 3a6ad95e8..1749ca563 100644
--- a/deployment/Dockerfile.docker.amd64
+++ b/deployment/Dockerfile.docker.amd64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
ARG SOURCE_DIR=/src
ARG ARTIFACT_DIR=/jellyfin
diff --git a/deployment/Dockerfile.docker.arm64 b/deployment/Dockerfile.docker.arm64
index ca7239304..bbddb61e4 100644
--- a/deployment/Dockerfile.docker.arm64
+++ b/deployment/Dockerfile.docker.arm64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
ARG SOURCE_DIR=/src
ARG ARTIFACT_DIR=/jellyfin
diff --git a/deployment/Dockerfile.docker.armhf b/deployment/Dockerfile.docker.armhf
index 26cce1958..3de1d6887 100644
--- a/deployment/Dockerfile.docker.armhf
+++ b/deployment/Dockerfile.docker.armhf
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
ARG SOURCE_DIR=/src
ARG ARTIFACT_DIR=/jellyfin
diff --git a/deployment/Dockerfile.linux.amd64 b/deployment/Dockerfile.linux.amd64
index 39169bd2a..386f7cefe 100644
--- a/deployment/Dockerfile.linux.amd64
+++ b/deployment/Dockerfile.linux.amd64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.linux.amd64-musl b/deployment/Dockerfile.linux.amd64-musl
index 636a34544..56c877333 100644
--- a/deployment/Dockerfile.linux.amd64-musl
+++ b/deployment/Dockerfile.linux.amd64-musl
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.linux.arm64 b/deployment/Dockerfile.linux.arm64
index ba8ce82f0..c9692c440 100644
--- a/deployment/Dockerfile.linux.arm64
+++ b/deployment/Dockerfile.linux.arm64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.linux.armhf b/deployment/Dockerfile.linux.armhf
index d771e9991..230461556 100644
--- a/deployment/Dockerfile.linux.armhf
+++ b/deployment/Dockerfile.linux.armhf
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.linux.musl-linux-arm64 b/deployment/Dockerfile.linux.musl-linux-arm64
index 846561181..240d09186 100644
--- a/deployment/Dockerfile.linux.musl-linux-arm64
+++ b/deployment/Dockerfile.linux.musl-linux-arm64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.macos.amd64 b/deployment/Dockerfile.macos.amd64
index 7ebf35442..1b054dfc4 100644
--- a/deployment/Dockerfile.macos.amd64
+++ b/deployment/Dockerfile.macos.amd64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.macos.arm64 b/deployment/Dockerfile.macos.arm64
index 5041ff967..07e18da55 100644
--- a/deployment/Dockerfile.macos.arm64
+++ b/deployment/Dockerfile.macos.arm64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.portable b/deployment/Dockerfile.portable
index 822b66ee6..36135f7a6 100644
--- a/deployment/Dockerfile.portable
+++ b/deployment/Dockerfile.portable
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/Dockerfile.windows.amd64 b/deployment/Dockerfile.windows.amd64
index 805c63f8c..08587aa7e 100644
--- a/deployment/Dockerfile.windows.amd64
+++ b/deployment/Dockerfile.windows.amd64
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim
+FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
diff --git a/deployment/build.debian.amd64 b/deployment/build.debian.amd64
index d92953ad1..7e968192b 100755
--- a/deployment/build.debian.amd64
+++ b/deployment/build.debian.amd64
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/deployment/build.debian.arm64 b/deployment/build.debian.arm64
index 618a121b6..7b7b603d6 100755
--- a/deployment/build.debian.arm64
+++ b/deployment/build.debian.arm64
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/deployment/build.debian.armhf b/deployment/build.debian.armhf
index d1631d022..3d894ba20 100755
--- a/deployment/build.debian.armhf
+++ b/deployment/build.debian.armhf
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/deployment/build.ubuntu.amd64 b/deployment/build.ubuntu.amd64
index 4254103fa..5f25cb610 100755
--- a/deployment/build.ubuntu.amd64
+++ b/deployment/build.ubuntu.amd64
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/deployment/build.ubuntu.arm64 b/deployment/build.ubuntu.arm64
index 42f111a01..334ced997 100755
--- a/deployment/build.ubuntu.arm64
+++ b/deployment/build.ubuntu.arm64
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/deployment/build.ubuntu.armhf b/deployment/build.ubuntu.armhf
index 357d63626..77e33c307 100755
--- a/deployment/build.ubuntu.armhf
+++ b/deployment/build.ubuntu.armhf
@@ -9,9 +9,9 @@ set -o xtrace
pushd ${SOURCE_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
- # Remove build-dep for dotnet-sdk-7.0, since it's installed manually
+ # Remove build-dep for dotnet-sdk-8.0, since it's installed manually
cp -a debian/control /tmp/control.orig
- sed -i '/dotnet-sdk-7.0,/d' debian/control
+ sed -i '/dotnet-sdk-8.0,/d' debian/control
fi
# Modify changelog to unstable configuration if IS_UNSTABLE
diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec
index c56a189ce..fb9fb2f7d 100644
--- a/fedora/jellyfin.spec
+++ b/fedora/jellyfin.spec
@@ -26,7 +26,7 @@ BuildRequires: systemd
BuildRequires: libcurl-devel, fontconfig-devel, freetype-devel, openssl-devel, glibc-devel, libicu-devel
# Requirements not packaged in RHEL 7 main repos, added via Makefile
# https://packages.microsoft.com/rhel/7/prod/
-BuildRequires: dotnet-runtime-7.0, dotnet-sdk-7.0
+BuildRequires: dotnet-runtime-8.0, dotnet-sdk-8.0
Requires: %{name}-server = %{version}-%{release}, %{name}-web = %{version}-%{release}
# Temporary (hopefully?) fix for https://github.com/jellyfin/jellyfin/issues/7471
diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
index 19aaa5ef8..3b7c43100 100644
--- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
+++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
@@ -71,7 +71,6 @@ namespace Jellyfin.Networking.Tests
[InlineData("127.0.0.1/8")]
[InlineData("192.168.1.2")]
[InlineData("192.168.1.2/24")]
- [InlineData("192.168.1.2/255.255.255.0")]
[InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")]
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]")]
[InlineData("fe80::7add:12ff:febb:c67b%16")]
@@ -103,12 +102,10 @@ namespace Jellyfin.Networking.Tests
[Theory]
[InlineData("192.168.5.85/24", "192.168.5.1")]
[InlineData("192.168.5.85/24", "192.168.5.254")]
- [InlineData("192.168.5.85/255.255.255.0", "192.168.5.254")]
[InlineData("10.128.240.50/30", "10.128.240.48")]
[InlineData("10.128.240.50/30", "10.128.240.49")]
[InlineData("10.128.240.50/30", "10.128.240.50")]
[InlineData("10.128.240.50/30", "10.128.240.51")]
- [InlineData("10.128.240.50/255.255.255.252", "10.128.240.51")]
[InlineData("127.0.0.1/8", "127.0.0.1")]
public void IPv4SubnetMaskMatchesValidIPAddress(string netMask, string ipAddress)
{
@@ -124,12 +121,10 @@ namespace Jellyfin.Networking.Tests
[Theory]
[InlineData("192.168.5.85/24", "192.168.4.254")]
[InlineData("192.168.5.85/24", "191.168.5.254")]
- [InlineData("192.168.5.85/255.255.255.252", "192.168.4.254")]
[InlineData("10.128.240.50/30", "10.128.240.47")]
[InlineData("10.128.240.50/30", "10.128.240.52")]
[InlineData("10.128.240.50/30", "10.128.239.50")]
[InlineData("10.128.240.50/30", "10.127.240.51")]
- [InlineData("10.128.240.50/255.255.255.252", "10.127.240.51")]
public void IPv4SubnetMaskDoesNotMatchInvalidIPAddress(string netMask, string ipAddress)
{
var ipa = IPAddress.Parse(ipAddress);