Browse Source

Merge branch 'master' into feature/EFUserData

JPVenson 6 months ago
parent
commit
427359deee
56 changed files with 184 additions and 93 deletions
  1. 1 1
      .config/dotnet-tools.json
  2. 3 3
      .devcontainer/Dev - Server Ffmpeg/devcontainer.json
  3. 3 3
      .devcontainer/devcontainer.json
  4. 4 4
      .github/workflows/ci-codeql-analysis.yml
  5. 10 0
      .github/workflows/ci-compat.yml
  6. 4 4
      .github/workflows/ci-openapi.yml
  7. 2 2
      .github/workflows/ci-tests.yml
  8. 3 3
      .vscode/launch.json
  9. 1 0
      Directory.Build.props
  10. 13 13
      Directory.Packages.props
  11. 1 1
      Emby.Naming/Emby.Naming.csproj
  12. 1 1
      Emby.Photos/Emby.Photos.csproj
  13. 1 1
      Emby.Server.Implementations/ApplicationHost.cs
  14. 1 1
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  15. 0 1
      Emby.Server.Implementations/Library/UserDataManager.cs
  16. 6 6
      Emby.Server.Implementations/Localization/Core/sv.json
  17. 88 1
      Emby.Server.Implementations/Localization/Core/uz.json
  18. 1 1
      Emby.Server.Implementations/Plugins/PluginManager.cs
  19. 1 1
      Jellyfin.Api/Controllers/ItemUpdateController.cs
  20. 1 1
      Jellyfin.Api/Jellyfin.Api.csproj
  21. 1 1
      Jellyfin.Data/Entities/User.cs
  22. 1 1
      Jellyfin.Data/Jellyfin.Data.csproj
  23. 1 1
      Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
  24. 0 8
      Jellyfin.Server/Helpers/StartupHelpers.cs
  25. 1 1
      Jellyfin.Server/Jellyfin.Server.csproj
  26. 1 1
      MediaBrowser.Common/MediaBrowser.Common.csproj
  27. 1 1
      MediaBrowser.Common/Plugins/BasePluginOfT.cs
  28. 1 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  29. 1 1
      MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
  30. 1 1
      MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
  31. 1 1
      MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
  32. 2 2
      MediaBrowser.Model/MediaBrowser.Model.csproj
  33. 0 1
      MediaBrowser.Providers/Manager/ProviderManager.cs
  34. 1 1
      MediaBrowser.Providers/MediaBrowser.Providers.csproj
  35. 1 1
      MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
  36. 2 2
      README.md
  37. 1 1
      fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj
  38. 1 1
      fuzz/Emby.Server.Implementations.Fuzz/fuzz.sh
  39. 1 1
      fuzz/Jellyfin.Api.Fuzz/Jellyfin.Api.Fuzz.csproj
  40. 1 1
      fuzz/Jellyfin.Api.Fuzz/fuzz.sh
  41. 1 1
      global.json
  42. 4 0
      jellyfin.ruleset
  43. 1 1
      src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
  44. 1 1
      src/Jellyfin.Drawing/Jellyfin.Drawing.csproj
  45. 1 1
      src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
  46. 0 1
      src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs
  47. 1 1
      src/Jellyfin.LiveTv/Jellyfin.LiveTv.csproj
  48. 1 1
      src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj
  49. 1 1
      src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj
  50. 1 1
      src/Jellyfin.Networking/Jellyfin.Networking.csproj
  51. 1 1
      src/Jellyfin.Networking/Manager/NetworkManager.cs
  52. 1 1
      tests/Directory.Build.props
  53. 1 1
      tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs
  54. 1 1
      tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs
  55. 2 2
      tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj
  56. 1 1
      tests/Jellyfin.Server.Implementations.Tests/TypedBaseItem/BaseItemKindTests.cs

+ 1 - 1
.config/dotnet-tools.json

@@ -3,7 +3,7 @@
   "isRoot": true,
   "tools": {
     "dotnet-ef": {
-      "version": "8.0.8",
+      "version": "8.0.11",
       "commands": [
         "dotnet-ef"
       ]

+ 3 - 3
.devcontainer/Dev - Server Ffmpeg/devcontainer.json

@@ -1,6 +1,6 @@
 {
     "name": "Development Jellyfin Server - FFmpeg",
-    "image":"mcr.microsoft.com/devcontainers/dotnet:8.0-jammy",
+    "image":"mcr.microsoft.com/devcontainers/dotnet:9.0-jammy",
     // restores nuget packages, installs the dotnet workloads and installs the dev https certificate
     "postStartCommand": "dotnet restore; dotnet workload update; dotnet dev-certs https --trust; sudo bash \"./.devcontainer/Dev - Server Ffmpeg/install-ffmpeg.sh\"",
     // reads the extensions list and installs them
@@ -8,8 +8,8 @@
     "features": {
         "ghcr.io/devcontainers/features/dotnet:2": {
             "version": "none",
-            "dotnetRuntimeVersions": "8.0",
-            "aspNetCoreRuntimeVersions": "8.0"
+            "dotnetRuntimeVersions": "9.0",
+            "aspNetCoreRuntimeVersions": "9.0"
         },
         "ghcr.io/devcontainers-contrib/features/apt-packages:1": {
             "preserve_apt_list": false,

+ 3 - 3
.devcontainer/devcontainer.json

@@ -1,6 +1,6 @@
 {
     "name": "Development Jellyfin Server",
-    "image":"mcr.microsoft.com/devcontainers/dotnet:8.0-jammy",
+    "image":"mcr.microsoft.com/devcontainers/dotnet:9.0-jammy",
     // restores nuget packages, installs the dotnet workloads and installs the dev https certificate
     "postStartCommand": "dotnet restore; dotnet workload update; dotnet dev-certs https --trust",
     // reads the extensions list and installs them
@@ -8,8 +8,8 @@
     "features": {
         "ghcr.io/devcontainers/features/dotnet:2": {
             "version": "none",
-            "dotnetRuntimeVersions": "8.0",
-            "aspNetCoreRuntimeVersions": "8.0"
+            "dotnetRuntimeVersions": "9.0",
+            "aspNetCoreRuntimeVersions": "9.0"
         },
         "ghcr.io/devcontainers-contrib/features/apt-packages:1": {
             "preserve_apt_list": false,

+ 4 - 4
.github/workflows/ci-codeql-analysis.yml

@@ -24,14 +24,14 @@ jobs:
     - name: Setup .NET
       uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
       with:
-        dotnet-version: '8.0.x'
+        dotnet-version: '9.0.x'
 
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
+      uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
       with:
         languages: ${{ matrix.language }}
         queries: +security-extended
     - name: Autobuild
-      uses: github/codeql-action/autobuild@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
+      uses: github/codeql-action/autobuild@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
+      uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4

+ 10 - 0
.github/workflows/ci-compat.yml

@@ -16,6 +16,11 @@ jobs:
           ref: ${{ github.event.pull_request.head.sha }}
           repository: ${{ github.event.pull_request.head.repo.full_name }}
 
+      - name: Setup .NET
+        uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
+        with:
+          dotnet-version: '9.0.x'
+
       - name: Build
         run: |
           dotnet build Jellyfin.Server -o ./out
@@ -41,6 +46,11 @@ jobs:
           repository: ${{ github.event.pull_request.head.repo.full_name }}
           fetch-depth: 0
 
+      - name: Setup .NET
+        uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
+        with:
+          dotnet-version: '9.0.x'
+
       - name: Checkout common ancestor
         env:
           HEAD_REF: ${{ github.head_ref }}

+ 4 - 4
.github/workflows/ci-openapi.yml

@@ -23,7 +23,7 @@ jobs:
       - name: Setup .NET
         uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
         with:
-          dotnet-version: '8.0.x'
+          dotnet-version: '9.0.x'
       - name: Generate openapi.json
         run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
       - name: Upload openapi.json
@@ -32,7 +32,7 @@ jobs:
           name: openapi-head
           retention-days: 14
           if-no-files-found: error
-          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
+          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json
 
   openapi-base:
     name: OpenAPI - BASE
@@ -57,7 +57,7 @@ jobs:
       - name: Setup .NET
         uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
         with:
-          dotnet-version: '8.0.x'
+          dotnet-version: '9.0.x'
       - name: Generate openapi.json
         run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
       - name: Upload openapi.json
@@ -66,7 +66,7 @@ jobs:
           name: openapi-base
           retention-days: 14
           if-no-files-found: error
-          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
+          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json
 
   openapi-diff:
     permissions:

+ 2 - 2
.github/workflows/ci-tests.yml

@@ -9,7 +9,7 @@ on:
   pull_request:
 
 env:
-  SDK_VERSION: "8.0.x"
+  SDK_VERSION: "9.0.x"
 
 jobs:
   run-tests:
@@ -34,7 +34,7 @@ jobs:
           --verbosity minimal
 
       - name: Merge code coverage results
-        uses: danielpalme/ReportGenerator-GitHub-Action@62f9e70ab348d56eee76d446b4db903a85ab0ea8 # v5.3.11
+        uses: danielpalme/ReportGenerator-GitHub-Action@810356ce07a94200154301fb73d878e327b2dd58 # v5.4.1
         with:
           reports: "**/coverage.cobertura.xml"
           targetdir: "merged/"

+ 3 - 3
.vscode/launch.json

@@ -6,7 +6,7 @@
             "type": "coreclr",
             "request": "launch",
             "preLaunchTask": "build",
-            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
+            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
             "args": [],
             "cwd": "${workspaceFolder}/Jellyfin.Server",
             "console": "internalConsole",
@@ -22,7 +22,7 @@
             "type": "coreclr",
             "request": "launch",
             "preLaunchTask": "build",
-            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
+            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
             "args": ["--nowebclient"],
             "cwd": "${workspaceFolder}/Jellyfin.Server",
             "console": "internalConsole",
@@ -34,7 +34,7 @@
             "type": "coreclr",
             "request": "launch",
             "preLaunchTask": "build",
-            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
+            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
             "args": ["--nowebclient", "--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg"],
             "cwd": "${workspaceFolder}/Jellyfin.Server",
             "console": "internalConsole",

+ 1 - 0
Directory.Build.props

@@ -8,6 +8,7 @@
 
   <PropertyGroup>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+    <WarningsNotAsErrors>NU1902;NU1903</WarningsNotAsErrors>
   </PropertyGroup>
 
   <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

+ 13 - 13
Directory.Packages.props

@@ -17,21 +17,21 @@
     <PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
     <PackageVersion Include="DotNet.Glob" Version="3.1.3" />
     <PackageVersion Include="FsCheck.Xunit" Version="2.16.6" />
-    <PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0.2" />
+    <PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0.3" />
     <PackageVersion Include="ICU4N.Transliterator" Version="60.1.0-alpha.356" />
     <PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
     <PackageVersion Include="Jellyfin.XmlTv" Version="10.8.0" />
     <PackageVersion Include="libse" Version="4.0.8" />
     <PackageVersion Include="LrcParser" Version="2024.0728.2" />
     <PackageVersion Include="MetaBrainz.MusicBrainz" Version="6.1.0" />
-    <PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.10" />
+    <PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.11" />
     <PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
-    <PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10" />
+    <PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.11" />
     <PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
     <PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
     <PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
@@ -40,8 +40,8 @@
     <PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
     <PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
     <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
-    <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.10" />
-    <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="8.0.10" />
+    <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.11" />
+    <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="8.0.11" />
     <PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
     <PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.1" />
     <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
@@ -66,9 +66,9 @@
     <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.8" />
-    <PackageVersion Include="SkiaSharp.HarfBuzz" Version="2.88.8" />
-    <PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.8" />
+    <PackageVersion Include="SkiaSharp" Version="2.88.9" />
+    <PackageVersion Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
+    <PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
     <PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
     <PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
     <PackageVersion Include="Svg.Skia" Version="2.0.0.2" />

+ 1 - 1
Emby.Naming/Emby.Naming.csproj

@@ -6,7 +6,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>

+ 1 - 1
Emby.Photos/Emby.Photos.csproj

@@ -19,7 +19,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 1 - 1
Emby.Server.Implementations/ApplicationHost.cs

@@ -611,7 +611,7 @@ namespace Emby.Server.Implementations
                 // Don't use an empty string password
                 password = string.IsNullOrWhiteSpace(password) ? null : password;
 
-                var localCert = new X509Certificate2(path, password, X509KeyStorageFlags.UserKeySet);
+                var localCert = X509CertificateLoader.LoadPkcs12FromFile(path, password, X509KeyStorageFlags.UserKeySet);
                 if (!localCert.HasPrivateKey)
                 {
                     Logger.LogError("No private key included in SSL cert {CertificateLocation}.", path);

+ 1 - 1
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -37,7 +37,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 0 - 1
Emby.Server.Implementations/Library/UserDataManager.cs

@@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Library
         {
             ArgumentNullException.ThrowIfNull(user);
             ArgumentNullException.ThrowIfNull(item);
-            ArgumentNullException.ThrowIfNull(reason);
             ArgumentNullException.ThrowIfNull(userDataDto);
 
             var userData = GetUserData(user, item) ?? throw new InvalidOperationException("Did not expect UserData to be null.");

+ 6 - 6
Emby.Server.Implementations/Localization/Core/sv.json

@@ -82,13 +82,13 @@
     "UserCreatedWithName": "Användaren {0} har skapats",
     "UserDeletedWithName": "Användaren {0} har tagits bort",
     "UserDownloadingItemWithValues": "{0} laddar ner {1}",
-    "UserLockedOutWithName": "Användare {0} har låsts ute",
-    "UserOfflineFromDevice": "{0} har avbrutit anslutningen från {1}",
+    "UserLockedOutWithName": "Användare {0} har utelåsts",
+    "UserOfflineFromDevice": "{0} har kopplat ned från {1}",
     "UserOnlineFromDevice": "{0} är uppkopplad från {1}",
     "UserPasswordChangedWithName": "Lösenordet för {0} har ändrats",
     "UserPolicyUpdatedWithName": "Användarpolicyn har uppdaterats för {0}",
-    "UserStartedPlayingItemWithValues": "{0} spelar upp {1} på {2}",
-    "UserStoppedPlayingItemWithValues": "{0} har avslutat uppspelningen av {1} på {2}",
+    "UserStartedPlayingItemWithValues": "{0} spelar {1} på {2}",
+    "UserStoppedPlayingItemWithValues": "{0} har stoppat uppspelningen av {1} på {2}",
     "ValueHasBeenAddedToLibrary": "{0} har lagts till i ditt mediebibliotek",
     "ValueSpecialEpisodeName": "Specialavsnitt - {0}",
     "VersionNumber": "Version {0}",
@@ -98,8 +98,8 @@
     "TaskRefreshChannels": "Uppdatera kanaler",
     "TaskCleanTranscodeDescription": "Raderar omkodningsfiler äldre än en dag.",
     "TaskCleanTranscode": "Rensa omkodningskatalog",
-    "TaskUpdatePluginsDescription": "Laddar ned och installerar uppdateringar till tilläggsprogram som är konfigurerade att uppdateras automatiskt.",
-    "TaskUpdatePlugins": "Uppdatera tilläggsprogram",
+    "TaskUpdatePluginsDescription": "Laddar ned och installerar uppdateringar till tillägg som är konfigurerade att uppdateras automatiskt.",
+    "TaskUpdatePlugins": "Uppdatera tillägg",
     "TaskRefreshPeopleDescription": "Uppdaterar metadata för skådespelare och regissörer i ditt mediabibliotek.",
     "TaskCleanLogsDescription": "Raderar loggfiler som är mer än {0} dagar gamla.",
     "TaskCleanLogs": "Rensa loggkatalog",

+ 88 - 1
Emby.Server.Implementations/Localization/Core/uz.json

@@ -23,5 +23,92 @@
     "HeaderLiveTV": "Jonli TV",
     "HeaderNextUp": "Keyingisi",
     "ItemAddedWithName": "{0} kutbxonaga qo'shildi",
-    "LabelIpAddressValue": "IP manzil: {0}"
+    "LabelIpAddressValue": "IP manzil: {0}",
+    "SubtitleDownloadFailureFromForItem": "{0} dan {1} uchun taglavhalarni yuklab boʻlmadi",
+    "UserPasswordChangedWithName": "Foydalanuvchi {0} paroli oʻzgartirildi",
+    "ValueHasBeenAddedToLibrary": "{0} kutubxonaga qoʻshildi",
+    "TaskCleanActivityLogDescription": "Belgilangan yoshdan kattaroq faoliyat jurnali yozuvlarini oʻchiradi.",
+    "TaskAudioNormalization": "Ovozni normallashtirish",
+    "TaskRefreshLibraryDescription": "Media kutubxonasi yangi fayllar uchun skanerlanmoqda va metama'lumotlar yangilanmoqda.",
+    "Default": "Joriy",
+    "HeaderFavoriteAlbums": "Tanlangan albomlar",
+    "HeaderFavoriteArtists": "Tanlangan artistlar",
+    "HeaderFavoriteEpisodes": "Tanlangan epizodlar",
+    "HeaderFavoriteShows": "Tanlangan shoular",
+    "HeaderFavoriteSongs": "Tanlangan qo'shiqlar",
+    "HeaderRecordingGroups": "Yozuvlar guruhi",
+    "HomeVideos": "Uy videolari",
+    "NotificationOptionVideoPlaybackStopped": "Video ijrosi toʻxtatildi",
+    "TvShows": "TV seriallar",
+    "Undefined": "Belgilanmagan",
+    "User": "Foydalanuvchi",
+    "UserCreatedWithName": "{0} foydalanuvchi yaratildi",
+    "TaskCleanCacheDescription": "Tizimga kerak bo'lmagan kesh fayllari o'chiriladi.",
+    "TaskAudioNormalizationDescription": "Ovozni normallashtirish ma'lumotlari uchun fayllarni skanerlaydi.",
+    "PluginInstalledWithName": "{0} - o'rnatildi",
+    "PluginUninstalledWithName": "{0} - o'chirildi",
+    "HearingImpaired": "Yaxshi eshitmaydiganlar uchun",
+    "Inherit": "Meroslangan",
+    "NotificationOptionApplicationUpdateAvailable": "Ilova yangilanishi mavjud",
+    "NotificationOptionApplicationUpdateInstalled": "Ilova yangilanishi oʻrnatildi",
+    "LabelRunningTimeValue": "Davomiyligi",
+    "NotificationOptionAudioPlayback": "Audio tinglash boshlandi",
+    "NotificationOptionAudioPlaybackStopped": "Audio tinglash to'xtatildi",
+    "NotificationOptionCameraImageUploaded": "Kamera tasvirlari yuklandi",
+    "NotificationOptionInstallationFailed": "O'rnatishda hatolik",
+    "NotificationOptionNewLibraryContent": "Yangi tarkib qo'shildi",
+    "NotificationOptionPluginError": "Plagin ishdan chiqdi",
+    "NotificationOptionPluginInstalled": "Plagin o'rnatildi",
+    "NotificationOptionPluginUninstalled": "Plagin o'chirildi",
+    "NotificationOptionPluginUpdateInstalled": "Plagin uchun yangilanish o'rnatildi",
+    "NotificationOptionServerRestartRequired": "Server-ni qayta yuklash lozim",
+    "NotificationOptionTaskFailed": "Rejalashtirilgan vazifa bajarilmadi",
+    "NotificationOptionUserLockedOut": "Foydalanuvchi bloklangan",
+    "NotificationOptionVideoPlayback": "Video ijrosi boshlandi",
+    "Photos": "Surat",
+    "Latest": "So'ngi",
+    "MessageApplicationUpdated": "Jellyfin Server yangilandi",
+    "MessageApplicationUpdatedTo": "Jellyfin Server {0} gacha yangilandi",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Server konfiguratsiyasi ({0}-boʻlim) yangilandi",
+    "MessageServerConfigurationUpdated": "Server konfiguratsiyasi yangilandi",
+    "MixedContent": "Aralashgan tarkib",
+    "Movies": "Kinolar",
+    "Music": "Qo'shiqlar",
+    "MusicVideos": "Musiqali videolar",
+    "NameInstallFailed": "Omadsiz ornatish {0}",
+    "NameSeasonNumber": "{0} Fasl",
+    "NameSeasonUnknown": "Fasl aniqlanmagan",
+    "Playlists": "Pleylistlar",
+    "NewVersionIsAvailable": "Yuklab olish uchun Jellyfin Server ning yangi versiyasi mavjud",
+    "Plugin": "Plagin",
+    "TaskCleanLogs": "Jurnallar katalogini tozalash",
+    "PluginUpdatedWithName": "{0} - yangilandi",
+    "ProviderValue": "Yetkazib beruvchi: {0}",
+    "ScheduledTaskFailedWithName": "{0} - omadsiz",
+    "ScheduledTaskStartedWithName": "{0} - ishga tushirildi",
+    "ServerNameNeedsToBeRestarted": "Qayta yuklash kerak {0}",
+    "Shows": "Teleko'rsatuv",
+    "Songs": "Kompozitsiyalar",
+    "StartupEmbyServerIsLoading": "Jellyfin Server yuklanmoqda. Tez orada qayta urinib koʻring.",
+    "Sync": "Sinxronizatsiya",
+    "System": "Tizim",
+    "UserDeletedWithName": "{0} foydalanuvchisi oʻchirib tashlandi",
+    "UserDownloadingItemWithValues": "{0} yuklanmoqda {1}",
+    "UserLockedOutWithName": "{0} foydalanuvchisi bloklandi",
+    "UserOfflineFromDevice": "{0} {1}dan uzildi",
+    "UserOnlineFromDevice": "{0} {1} dan ulandi",
+    "UserPolicyUpdatedWithName": "{0} foydalanuvchisining siyosatlari yangilandi",
+    "UserStartedPlayingItemWithValues": "{0} - {2} da \"{1}\" ijrosi",
+    "UserStoppedPlayingItemWithValues": "{0} - ijro etish to‘xtatildi {1} {2}",
+    "ValueSpecialEpisodeName": "Maxsus qism – {0}",
+    "VersionNumber": "Versiya {0}",
+    "TasksMaintenanceCategory": "Xizmat ko'rsatish",
+    "TasksLibraryCategory": "Media kutubxona",
+    "TasksApplicationCategory": "Ilova",
+    "TasksChannelsCategory": "Internet kanallari",
+    "TaskCleanActivityLog": "Faoliyat jurnalini tozalash",
+    "TaskCleanCache": "Kesh katalogini tozalash",
+    "TaskRefreshChapterImages": "Sahnadan tasvirini chiqarish",
+    "TaskRefreshChapterImagesDescription": "Sahnalarni o'z ichiga olgan videolar uchun eskizlarni yaratadi.",
+    "TaskRefreshLibrary": "Media kutubxonangizni skanerlash"
 }

+ 1 - 1
Emby.Server.Implementations/Plugins/PluginManager.cs

@@ -835,7 +835,7 @@ namespace Emby.Server.Implementations.Plugins
         /// <exception cref="ArgumentNullException">If the <see cref="LocalPlugin"/> is null.</exception>
         private bool TryGetPluginDlls(LocalPlugin plugin, out IReadOnlyList<string> whitelistedDlls)
         {
-            ArgumentNullException.ThrowIfNull(nameof(plugin));
+            ArgumentNullException.ThrowIfNull(plugin);
 
             IReadOnlyList<string> pluginDlls = Directory.GetFiles(plugin.Path, "*.dll", SearchOption.AllDirectories);
 

+ 1 - 1
Jellyfin.Api/Controllers/ItemUpdateController.cs

@@ -457,7 +457,7 @@ public class ItemUpdateController : BaseJellyfinApiController
             return null;
         }
 
-        return (SeriesStatus)Enum.Parse(typeof(SeriesStatus), item.Status, true);
+        return Enum.Parse<SeriesStatus>(item.Status, true);
     }
 
     private DateTime NormalizeDateTime(DateTime val)

+ 1 - 1
Jellyfin.Api/Jellyfin.Api.csproj

@@ -6,7 +6,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 

+ 1 - 1
Jellyfin.Data/Entities/User.cs

@@ -514,7 +514,7 @@ namespace Jellyfin.Data.Entities
         /// </summary>
         public void AddDefaultPreferences()
         {
-            foreach (var val in Enum.GetValues(typeof(PreferenceKind)).Cast<PreferenceKind>())
+            foreach (var val in Enum.GetValues<PreferenceKind>())
             {
                 Preferences.Add(new Preference(val, string.Empty));
             }

+ 1 - 1
Jellyfin.Data/Jellyfin.Data.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>

+ 1 - 1
Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 0 - 8
Jellyfin.Server/Helpers/StartupHelpers.cs

@@ -292,13 +292,5 @@ public static class StartupHelpers
         // Make sure we have all the code pages we can get
         // Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks
         Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
-
-        // Increase the max http request limit
-        // The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
-        ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
-
-        // Disable the "Expect: 100-Continue" header by default
-        // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
-        ServicePointManager.Expect100Continue = false;
     }
 }

+ 1 - 1
Jellyfin.Server/Jellyfin.Server.csproj

@@ -8,7 +8,7 @@
   <PropertyGroup>
     <AssemblyName>jellyfin</AssemblyName>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <ServerGarbageCollection>false</ServerGarbageCollection>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>

+ 1 - 1
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -28,7 +28,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>

+ 1 - 1
MediaBrowser.Common/Plugins/BasePluginOfT.cs

@@ -193,7 +193,7 @@ namespace MediaBrowser.Common.Plugins
             }
             catch
             {
-                var config = (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
+                var config = Activator.CreateInstance<TConfigurationType>();
                 SaveConfiguration(config);
                 return config;
             }

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -34,7 +34,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>

+ 1 - 1
MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj

@@ -11,7 +11,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 1 - 1
MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj

@@ -6,7 +6,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 1 - 1
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

@@ -1648,7 +1648,7 @@ namespace MediaBrowser.MediaEncoding.Probing
 
             using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1))
             {
-                fs.Read(packetBuffer);
+                fs.ReadExactly(packetBuffer);
             }
 
             if (packetBuffer[0] == 71)

+ 2 - 2
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -14,7 +14,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>
@@ -35,7 +35,7 @@
   <ItemGroup>
     <FrameworkReference Include="Microsoft.AspNetCore.App" />
   </ItemGroup>
-  
+
   <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
     <PackageReference Include="MimeTypes">

+ 0 - 1
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -1033,7 +1033,6 @@ namespace MediaBrowser.Providers.Manager
         /// <inheritdoc/>
         public void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority)
         {
-            ArgumentNullException.ThrowIfNull(itemId);
             if (itemId.IsEmpty())
             {
                 throw new ArgumentException("Guid can't be empty", nameof(itemId));

+ 1 - 1
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -28,7 +28,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>

+ 1 - 1
MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj

@@ -15,7 +15,7 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 2 - 2
README.md

@@ -74,7 +74,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 8.0 SDK](https://dotnet.microsoft.com/download/dotnet) on your system.
+Before the project can be built, you must first install the [.NET 9.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).
 
@@ -131,7 +131,7 @@ A second option is to build the project and then run the resulting executable fi
 
 ```bash
 dotnet build                       # Build the project
-cd Jellyfin.Server/bin/Debug/net8.0 # Change into the build output directory
+cd Jellyfin.Server/bin/Debug/net9.0 # Change into the build output directory
 ```
 
 2. Execute the build output. On Linux, Mac, etc. use `./jellyfin` and on Windows use `jellyfin.exe`.

+ 1 - 1
fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
fuzz/Emby.Server.Implementations.Fuzz/fuzz.sh

@@ -8,4 +8,4 @@ cp bin/Emby.Server.Implementations.dll .
 
 dotnet build
 mkdir -p Findings
-AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net8.0/Emby.Server.Implementations.Fuzz "$1"
+AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net9.0/Emby.Server.Implementations.Fuzz "$1"

+ 1 - 1
fuzz/Jellyfin.Api.Fuzz/Jellyfin.Api.Fuzz.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
fuzz/Jellyfin.Api.Fuzz/fuzz.sh

@@ -8,4 +8,4 @@ cp bin/Jellyfin.Api.dll .
 
 dotnet build
 mkdir -p Findings
-AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net8.0/Jellyfin.Api.Fuzz "$1"
+AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net9.0/Jellyfin.Api.Fuzz "$1"

+ 1 - 1
global.json

@@ -1,6 +1,6 @@
 {
     "sdk": {
-        "version": "8.0.0",
+        "version": "9.0.0",
         "rollForward": "latestMinor"
     }
 }

+ 4 - 0
jellyfin.ruleset

@@ -154,6 +154,8 @@
     <!-- TODO: enable when false positives are fixed -->
     <!-- disable warning CA1508: Avoid dead conditional code -->
     <Rule Id="CA1508" Action="Info" />
+    <!-- disable warning CA1515: Consider making public types internal -->
+    <Rule Id="CA1515" Action="Info" />
     <!-- disable warning CA1716: Identifiers should not match keywords -->
     <Rule Id="CA1716" Action="Info" />
     <!-- disable warning CA1720: Identifiers should not contain type names -->
@@ -168,6 +170,8 @@
     <Rule Id="CA1812" Action="Info" />
     <!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
     <Rule Id="CA1822" Action="Info" />
+    <!-- CA1859: Use concrete types when possible for improved performance -->
+    <Rule Id="CA1859" Action="Info" />
     <!-- TODO: Enable -->
     <!-- CA1861: Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array -->
     <Rule Id="CA1861" Action="Info" />

+ 1 - 1
src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj

@@ -6,7 +6,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <!-- TODO: Remove once we update SkiaSharp > 2.88.5 -->

+ 1 - 1
src/Jellyfin.Drawing/Jellyfin.Drawing.csproj

@@ -6,7 +6,7 @@
   </PropertyGroup>
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 1 - 1
src/Jellyfin.Extensions/Jellyfin.Extensions.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>

+ 0 - 1
src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs

@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
-using System.Linq;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 

+ 1 - 1
src/Jellyfin.LiveTv/Jellyfin.LiveTv.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 

+ 1 - 1
src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 

+ 1 - 1
src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 

+ 1 - 1
src/Jellyfin.Networking/Jellyfin.Networking.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>

+ 1 - 1
src/Jellyfin.Networking/Manager/NetworkManager.cs

@@ -57,7 +57,7 @@ public class NetworkManager : INetworkManager, IDisposable
     /// <summary>
     /// Dictionary containing interface addresses and their subnets.
     /// </summary>
-    private IReadOnlyList<IPData> _interfaces;
+    private List<IPData> _interfaces;
 
     /// <summary>
     /// Unfiltered user defined LAN subnets (<see cref="NetworkConfiguration.LocalNetworkSubnets"/>)

+ 1 - 1
tests/Directory.Build.props

@@ -4,7 +4,7 @@
   <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
 
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <IsPackable>false</IsPackable>
     <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)/jellyfin-tests.ruleset</CodeAnalysisRuleSet>
   </PropertyGroup>

+ 1 - 1
tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs

@@ -8,7 +8,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models
     /// The generic body model.
     /// </summary>
     /// <typeparam name="T">The value type.</typeparam>
-    public class GenericBodyArrayModel<T>
+    public sealed class GenericBodyArrayModel<T>
     {
         /// <summary>
         /// Gets or sets the value.

+ 1 - 1
tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs

@@ -8,7 +8,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models
     /// The generic body <c>IReadOnlyList</c> model.
     /// </summary>
     /// <typeparam name="T">The value type.</typeparam>
-    public class GenericBodyIReadOnlyListModel<T>
+    public sealed class GenericBodyIReadOnlyListModel<T>
     {
         /// <summary>
         /// Gets or sets the value.

+ 2 - 2
tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>
@@ -22,7 +22,7 @@
     <PackageReference Include="Xunit.SkippableFact" />
     <PackageReference Include="coverlet.collector" />
   </ItemGroup>
-  
+
   <ItemGroup>
     <ProjectReference Include="..\..\src\Jellyfin.LiveTv\Jellyfin.LiveTv.csproj" />
   </ItemGroup>

+ 1 - 1
tests/Jellyfin.Server.Implementations.Tests/TypedBaseItem/BaseItemKindTests.cs

@@ -35,7 +35,7 @@ namespace Jellyfin.Server.Implementations.Tests.TypedBaseItem
         public void EnumParse_GivenValidBaseItemType_ReturnsEnumValue(Type baseItemDescendantType)
         {
             var enumValue = Enum.Parse<BaseItemKind>(baseItemDescendantType.Name);
-            Assert.True(Enum.IsDefined(typeof(BaseItemKind), enumValue));
+            Assert.True(Enum.IsDefined(enumValue));
         }
 
         [Theory]