aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines-abi.yml2
-rw-r--r--.ci/azure-pipelines-api-client.yml2
-rw-r--r--.ci/azure-pipelines-main.yml2
-rw-r--r--.ci/azure-pipelines-test.yml2
-rw-r--r--.ci/azure-pipelines.yml2
-rw-r--r--.drone.yml30
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2010Profile.cs4
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2011Profile.cs4
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2012Profile.cs4
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2013Profile.cs4
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2014Profile.cs4
-rw-r--r--Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml4
-rw-r--r--Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml4
-rw-r--r--Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml4
-rw-r--r--Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml4
-rw-r--r--Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml4
-rw-r--r--Emby.Naming/Common/NamingOptions.cs15
-rw-r--r--Emby.Naming/Emby.Naming.csproj2
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs10
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs52
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs4
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs6
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/eo.json26
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json148
-rw-r--r--Emby.Server.Implementations/Localization/Core/kk.json220
-rw-r--r--Emby.Server.Implementations/Localization/Core/ru.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json2
-rw-r--r--Emby.Server.Implementations/Plugins/PluginManager.cs54
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs20
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs7
-rw-r--r--Jellyfin.Api/Controllers/DashboardController.cs58
-rw-r--r--Jellyfin.Api/Controllers/PackageController.cs2
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs37
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs6
-rw-r--r--Jellyfin.Api/Helpers/DynamicHlsHelper.cs2
-rw-r--r--Jellyfin.Api/Helpers/RequestHelpers.cs38
-rw-r--r--Jellyfin.Api/Jellyfin.Api.csproj4
-rw-r--r--Jellyfin.Api/Models/ConfigurationPageInfo.cs23
-rw-r--r--Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs16
-rw-r--r--Jellyfin.Data/Jellyfin.Data.csproj6
-rw-r--r--Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj4
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs3
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj4
-rw-r--r--Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs2
-rw-r--r--MediaBrowser.Common/Extensions/ShuffleExtensions.cs3
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj2
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs51
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets6
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/AssParser.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs2
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs1
-rw-r--r--MediaBrowser.XbmcMetadata/EntryPoint.cs12
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs37
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs5
-rw-r--r--MediaBrowser.sln.GhostDoc.xml35
-rw-r--r--SharedVersion.cs4
-rw-r--r--build.yaml2
-rw-r--r--debian/changelog6
-rw-r--r--debian/metapackage/jellyfin2
-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.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.macos2
-rw-r--r--deployment/Dockerfile.portable2
-rw-r--r--deployment/Dockerfile.ubuntu.amd642
-rw-r--r--deployment/Dockerfile.ubuntu.arm642
-rw-r--r--deployment/Dockerfile.ubuntu.armhf2
-rw-r--r--deployment/Dockerfile.windows.amd642
-rw-r--r--fedora/jellyfin.spec4
-rw-r--r--hooks/pre_build6
-rw-r--r--tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs59
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj4
-rw-r--r--tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs22
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj2
-rw-r--r--tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj2
-rw-r--r--tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj2
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj2
-rw-r--r--tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj2
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs6
-rw-r--r--tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs69
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj13
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunHostTests.cs12
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs45
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ForceKeepAlive.json1
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/Partial.json1
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ValidPartial.json1
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/discover.json (renamed from tests/Jellyfin.Server.Implementations.Tests/LiveTv/discover.json)0
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/lineup.json (renamed from tests/Jellyfin.Server.Implementations.Tests/LiveTv/lineup.json)0
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj3
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs10
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs17
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs9
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs8
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs4
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo6
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo1
108 files changed, 752 insertions, 630 deletions
diff --git a/.ci/azure-pipelines-abi.yml b/.ci/azure-pipelines-abi.yml
index 14df7e7c8d..8d0737b66c 100644
--- a/.ci/azure-pipelines-abi.yml
+++ b/.ci/azure-pipelines-abi.yml
@@ -7,7 +7,7 @@ parameters:
default: "ubuntu-latest"
- name: DotNetSdkVersion
type: string
- default: 5.0.100
+ default: 5.0.103
jobs:
- job: CompatibilityCheck
diff --git a/.ci/azure-pipelines-api-client.yml b/.ci/azure-pipelines-api-client.yml
index 177f78889c..0e944e6f47 100644
--- a/.ci/azure-pipelines-api-client.yml
+++ b/.ci/azure-pipelines-api-client.yml
@@ -4,7 +4,7 @@
default: "ubuntu-latest"
- name: GeneratorVersion
type: string
- default: "5.0.0-beta2"
+ default: "5.0.1"
jobs:
- job: GenerateApiClients
diff --git a/.ci/azure-pipelines-main.yml b/.ci/azure-pipelines-main.yml
index 95dd3ccac2..4bc72f9eb0 100644
--- a/.ci/azure-pipelines-main.yml
+++ b/.ci/azure-pipelines-main.yml
@@ -1,7 +1,7 @@
parameters:
LinuxImage: 'ubuntu-latest'
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
- DotNetSdkVersion: 5.0.100
+ DotNetSdkVersion: 5.0.103
jobs:
- job: Build
diff --git a/.ci/azure-pipelines-test.yml b/.ci/azure-pipelines-test.yml
index 36152c82a4..95e0d8c58d 100644
--- a/.ci/azure-pipelines-test.yml
+++ b/.ci/azure-pipelines-test.yml
@@ -10,7 +10,7 @@ parameters:
default: "tests/**/*Tests.csproj"
- name: DotNetSdkVersion
type: string
- default: 5.0.100
+ default: 5.0.103
jobs:
- job: Test
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index ec4c254358..6430503f9a 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -6,7 +6,7 @@ variables:
- name: RestoreBuildProjects
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
- name: DotNetSdkVersion
- value: 5.0.100
+ value: 5.0.103
pr:
autoCancel: true
diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index 87c8e414e9..0000000000
--- a/.drone.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-kind: pipeline
-name: build-debug
-
-steps:
-- name: submodules
- image: docker:git
- commands:
- - git submodule update --init --recursive
-
-- name: build
- image: microsoft/dotnet:2-sdk
- commands:
- - dotnet publish "Jellyfin.Server" --configuration Debug --output "../ci/ci-debug"
-
----
-kind: pipeline
-name: build-release
-
-steps:
-- name: submodules
- image: docker:git
- commands:
- - git submodule update --init --recursive
-
-- name: build
- image: microsoft/dotnet:2-sdk
- commands:
- - dotnet publish "Jellyfin.Server" --configuration Release --output "../ci/ci-release"
-
diff --git a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
index 8ab4acd1be..9f0d82b8f8 100644
--- a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
- FriendlyName = @"KDL-\d{2}[EHLNPB]X\d[01]\d.*",
+ FriendlyName = @"KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Manufacturer = "Sony",
Headers = new[]
@@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
- Value = @".*KDL-\d{2}[EHLNPB]X\d[01]\d.*",
+ Value = @".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Match = HeaderMatchType.Regex
}
}
diff --git a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
index 42d253394c..dfb91817ac 100644
--- a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
- FriendlyName = @"KDL-\d{2}([A-Z]X\d2\d|CX400).*",
+ FriendlyName = @"KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Manufacturer = "Sony",
Headers = new[]
@@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
- Value = @".*KDL-\d{2}([A-Z]X\d2\d|CX400).*",
+ Value = @".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Match = HeaderMatchType.Regex
}
}
diff --git a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
index 0598e83422..d59ee38d74 100644
--- a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
- FriendlyName = @"KDL-\d{2}[A-Z]X\d5(\d|G).*",
+ FriendlyName = @"KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Manufacturer = "Sony",
Headers = new[]
@@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
- Value = @".*KDL-\d{2}[A-Z]X\d5(\d|G).*",
+ Value = @".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Match = HeaderMatchType.Regex
}
}
diff --git a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
index 3d90a1e72d..73b0fd67eb 100644
--- a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
- FriendlyName = @"KDL-\d{2}[WR][5689]\d{2}A.*",
+ FriendlyName = @"KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Manufacturer = "Sony",
Headers = new[]
@@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
- Value = @".*KDL-\d{2}[WR][5689]\d{2}A.*",
+ Value = @".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Match = HeaderMatchType.Regex
}
}
diff --git a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
index 9188f73ef1..db8ee5750f 100644
--- a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification
{
- FriendlyName = @"(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*",
+ FriendlyName = @"(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Manufacturer = "Sony",
Headers = new[]
@@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
- Value = @".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*",
+ Value = @".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Match = HeaderMatchType.Regex
}
}
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
index f20e9fcb6f..1461db3117 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
@@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2010)</Name>
<Identification>
- <FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName>
+ <FriendlyName>KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
- <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[EHLNPB]X\d[01]\d.*" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
index e516ff512d..7c5f2b1817 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
@@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2011)</Name>
<Identification>
- <FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName>
+ <FriendlyName>KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
- <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}([A-Z]X\d2\d|CX400).*" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
index 88bd1c2f53..842a8fba33 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
@@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2012)</Name>
<Identification>
- <FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName>
+ <FriendlyName>KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
- <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[A-Z]X\d5(\d|G).*" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
index 3ca9893cdc..f1135c3fe3 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
@@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2013)</Name>
<Identification>
- <FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName>
+ <FriendlyName>KDL-[0-9]{2}[WR][5689][0-9]{2}A.*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
- <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[WR][5689]\d{2}A.*" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
index 8804a75dfa..85c7868c66 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
@@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2014)</Name>
<Identification>
- <FriendlyName>(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*</FriendlyName>
+ <FriendlyName>(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*</FriendlyName>
<Manufacturer>Sony</Manufacturer>
<Headers>
- <HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*" match="Regex" />
+ <HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*" match="Regex" />
</Headers>
</Identification>
<Manufacturer>Microsoft Corporation</Manufacturer>
diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index 035d1b2280..22a3e8bb49 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/Emby.Naming/Common/NamingOptions.cs
@@ -282,7 +282,13 @@ namespace Emby.Naming.Common
SupportsAbsoluteEpisodeNumbers = true
},
- // Case Closed (1996-2007)/Case Closed - 317.mkv
+ // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
+ // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the series name
+ new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+).*$")
+ {
+ IsNamed = true
+ },
+
// /server/anything_102.mp4
// /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
// /server/anything_1996.11.14.mp4
@@ -299,11 +305,6 @@ namespace Emby.Naming.Common
// *** End Kodi Standard Naming
- // [bar] Foo - 1 [baz]
- new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>[0-9]+).*$")
- {
- IsNamed = true
- },
new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
{
IsNamed = true
@@ -587,7 +588,7 @@ namespace Emby.Naming.Common
AudioBookNamesExpressions = new[]
{
// Detect year usually in brackets after name Batman (2020)
- @"^(?<name>.+?)\s*\(\s*(?<year>\d{4})\s*\)\s*$",
+ @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
@"^\s*(?<name>[^ ].*?)\s*$"
};
diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj
index 24c15759d4..b43203e9dd 100644
--- a/Emby.Naming/Emby.Naming.csproj
+++ b/Emby.Naming/Emby.Naming.csproj
@@ -33,7 +33,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 2d5b19fa69..8c5fa09f69 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -336,19 +336,19 @@ namespace Emby.Server.Implementations.Channels
return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).Result;
}
- private List<MediaSourceInfo> GetSavedMediaSources(BaseItem item)
+ private MediaSourceInfo[] GetSavedMediaSources(BaseItem item)
{
var path = Path.Combine(item.GetInternalMetadataPath(), "channelmediasourceinfos.json");
try
{
- var jsonString = File.ReadAllText(path, Encoding.UTF8);
- return JsonSerializer.Deserialize<List<MediaSourceInfo>>(jsonString, _jsonOptions)
- ?? new List<MediaSourceInfo>();
+ var bytes = File.ReadAllBytes(path);
+ return JsonSerializer.Deserialize<MediaSourceInfo[]>(bytes, _jsonOptions)
+ ?? Array.Empty<MediaSourceInfo>();
}
catch
{
- return new List<MediaSourceInfo>();
+ return Array.Empty<MediaSourceInfo>();
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 8a901516c0..e3ab0d6eab 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1157,7 +1157,7 @@ namespace Emby.Server.Implementations.Dto
if (episodeSeries != null)
{
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, episodeSeries, ImageType.Primary);
- if (!dto.ImageTags.ContainsKey(ImageType.Primary))
+ if (dto.ImageTags == null || !dto.ImageTags.ContainsKey(ImageType.Primary))
{
AttachPrimaryImageAspectRatio(dto, episodeSeries);
}
@@ -1207,7 +1207,7 @@ namespace Emby.Server.Implementations.Dto
if (series != null)
{
dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, series, ImageType.Primary);
- if (!dto.ImageTags.ContainsKey(ImageType.Primary))
+ if (dto.ImageTags == null || !dto.ImageTags.ContainsKey(ImageType.Primary))
{
AttachPrimaryImageAspectRatio(dto, series);
}
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index fed2addf80..7e0c2c1da2 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -5,6 +5,7 @@ using System.Buffers;
using System.IO.Pipelines;
using System.Net;
using System.Net.WebSockets;
+using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@@ -138,7 +139,7 @@ namespace Emby.Server.Implementations.HttpServer
writer.Advance(bytesRead);
// Make the data available to the PipeReader
- FlushResult flushResult = await writer.FlushAsync().ConfigureAwait(false);
+ FlushResult flushResult = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
if (flushResult.IsCompleted)
{
// The PipeReader stopped reading
@@ -181,32 +182,16 @@ namespace Emby.Server.Implementations.HttpServer
}
WebSocketMessage<object>? stub;
+ long bytesConsumed = 0;
try
{
-
- if (buffer.IsSingleSegment)
- {
- stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buffer.FirstSpan, _jsonOptions);
- }
- else
- {
- var buf = ArrayPool<byte>.Shared.Rent(Convert.ToInt32(buffer.Length));
- try
- {
- buffer.CopyTo(buf);
- stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buf, _jsonOptions);
- }
- finally
- {
- ArrayPool<byte>.Shared.Return(buf);
- }
- }
+ stub = DeserializeWebSocketMessage(buffer, out bytesConsumed);
}
catch (JsonException ex)
{
// Tell the PipeReader how much of the buffer we have consumed
reader.AdvanceTo(buffer.End);
- _logger.LogError(ex, "Error processing web socket message");
+ _logger.LogError(ex, "Error processing web socket message: {Data}", Encoding.UTF8.GetString(buffer));
return;
}
@@ -217,27 +202,34 @@ namespace Emby.Server.Implementations.HttpServer
}
// Tell the PipeReader how much of the buffer we have consumed
- reader.AdvanceTo(buffer.End);
+ reader.AdvanceTo(buffer.GetPosition(bytesConsumed));
_logger.LogDebug("WS {IP} received message: {@Message}", RemoteEndPoint, stub);
- var info = new WebSocketMessageInfo
- {
- MessageType = stub.MessageType,
- Data = stub.Data?.ToString(), // Data can be null
- Connection = this
- };
-
- if (info.MessageType == SessionMessageType.KeepAlive)
+ if (stub.MessageType == SessionMessageType.KeepAlive)
{
await SendKeepAliveResponse().ConfigureAwait(false);
}
else
{
- await OnReceive(info).ConfigureAwait(false);
+ await OnReceive(
+ new WebSocketMessageInfo
+ {
+ MessageType = stub.MessageType,
+ Data = stub.Data?.ToString(), // Data can be null
+ Connection = this
+ }).ConfigureAwait(false);
}
}
+ internal WebSocketMessage<object>? DeserializeWebSocketMessage(ReadOnlySequence<byte> bytes, out long bytesConsumed)
+ {
+ var jsonReader = new Utf8JsonReader(bytes);
+ var ret = JsonSerializer.Deserialize<WebSocketMessage<object>>(ref jsonReader, _jsonOptions);
+ bytesConsumed = jsonReader.BytesConsumed;
+ return ret;
+ }
+
private Task SendKeepAliveResponse()
{
LastKeepAliveDate = DateTime.UtcNow;
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 5ebc9b61b5..c0e757543d 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -684,7 +684,9 @@ namespace Emby.Server.Implementations.IO
return new EnumerationOptions
{
RecurseSubdirectories = recursive,
- IgnoreInaccessible = true
+ IgnoreInaccessible = true,
+ // Don't skip any files.
+ AttributesToSkip = 0
};
}
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 660ec106bd..c63eb70179 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -515,7 +515,7 @@ namespace Emby.Server.Implementations.Library
}
// TODO: @bond Fix
- var json = JsonSerializer.Serialize(mediaSource, _jsonOptions);
+ var json = JsonSerializer.SerializeToUtf8Bytes(mediaSource, _jsonOptions);
_logger.LogInformation("Live stream opened: " + json);
var clone = JsonSerializer.Deserialize<MediaSourceInfo>(json, _jsonOptions);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index c80ecd6b3c..57424f0435 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -47,11 +47,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
try
{
- var jsonString = File.ReadAllText(_dataPath, Encoding.UTF8);
- _items = JsonSerializer.Deserialize<T[]>(jsonString, _jsonOptions);
+ var bytes = File.ReadAllBytes(_dataPath);
+ _items = JsonSerializer.Deserialize<T[]>(bytes, _jsonOptions);
return;
}
- catch (Exception ex)
+ catch (JsonException ex)
{
Logger.LogError(ex, "Error deserializing {Path}", _dataPath);
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 7842be7164..63a3146aa9 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -2239,7 +2239,7 @@ namespace Emby.Server.Implementations.LiveTv
public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true)
{
- info = JsonSerializer.Deserialize<TunerHostInfo>(JsonSerializer.Serialize(info));
+ info = JsonSerializer.Deserialize<TunerHostInfo>(JsonSerializer.SerializeToUtf8Bytes(info));
var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
@@ -2283,7 +2283,7 @@ namespace Emby.Server.Implementations.LiveTv
{
// Hack to make the object a pure ListingsProviderInfo instead of an AddListingProvider
// ServerConfiguration.SaveConfiguration crashes during xml serialization for AddListingProvider
- info = JsonSerializer.Deserialize<ListingsProviderInfo>(JsonSerializer.Serialize(info));
+ info = JsonSerializer.Deserialize<ListingsProviderInfo>(JsonSerializer.SerializeToUtf8Bytes(info));
var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index cdc8c6870a..f09338330f 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public LegacyHdHomerunChannelCommands(string url)
{
// parse url for channel and program
- var regExp = new Regex(@"\/ch(\d+)-?(\d*)");
+ var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)");
var match = regExp.Match(url);
if (match.Success)
{
diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json
new file mode 100644
index 0000000000..3ff7eddae3
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/eo.json
@@ -0,0 +1,26 @@
+{
+ "NotificationOptionInstallationFailed": "Instalada fiasko",
+ "NotificationOptionAudioPlaybackStopped": "Sono de ludado haltis",
+ "NotificationOptionAudioPlayback": "Ludado de sono startis",
+ "NameSeasonUnknown": "Sezono Nekonata",
+ "NameSeasonNumber": "Sezono {0}",
+ "NameInstallFailed": "{0} instalado fiaskis",
+ "Music": "Muziko",
+ "Movies": "Filmoj",
+ "ItemRemovedWithName": "{0} forigis el la biblioteko",
+ "ItemAddedWithName": "{0} aldonis al la biblioteko",
+ "HeaderLiveTV": "Viva Televido",
+ "HeaderContinueWatching": "Daŭrigi Spektado",
+ "HeaderAlbumArtists": "Artistoj de Albumo",
+ "Folders": "Dosierujoj",
+ "DeviceOnlineWithName": "{0} estas konektita",
+ "Default": "Defaŭlte",
+ "Collections": "Kolektoj",
+ "ChapterNameValue": "Ĉapitro {0}",
+ "Channels": "Kanaloj",
+ "Books": "Libroj",
+ "Artists": "Artistoj",
+ "Application": "Aplikaĵo",
+ "AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}",
+ "Albums": "Albumoj"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index 954759b5c0..fd6148e789 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -1,121 +1,121 @@
{
- "HeaderLiveTV": "Live-TV",
- "NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
+ "HeaderLiveTV": "Live TV",
+ "NewVersionIsAvailable": "Uusi versio Jellyfin-palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon kausi",
"NameSeasonNumber": "Kausi {0}",
"NameInstallFailed": "{0} asennus epäonnistui",
"MusicVideos": "Musiikkivideot",
"Music": "Musiikki",
"Movies": "Elokuvat",
- "MixedContent": "Sekoitettu sisältö",
+ "MixedContent": "Sekalainen sisältö",
"MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty",
- "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
- "MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
- "MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
- "Latest": "Uusimmat",
- "LabelRunningTimeValue": "Toiston kesto: {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusten osio {0} on päivitetty",
+ "MessageApplicationUpdatedTo": "Jellyfin-palvelin on päivitetty versioon {0}",
+ "MessageApplicationUpdated": "Jellyfin-palvelin on päivitetty",
+ "Latest": "Viimeisimmät",
+ "LabelRunningTimeValue": "Kesto: {0}",
"LabelIpAddressValue": "IP-osoite: {0}",
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
"ItemAddedWithName": "{0} lisättiin kirjastoon",
- "Inherit": "Periytyä",
+ "Inherit": "Peri",
"HomeVideos": "Kotivideot",
"HeaderRecordingGroups": "Tallennusryhmät",
"HeaderNextUp": "Seuraavaksi",
"HeaderFavoriteSongs": "Suosikkikappaleet",
"HeaderFavoriteShows": "Suosikkisarjat",
"HeaderFavoriteEpisodes": "Suosikkijaksot",
- "HeaderFavoriteArtists": "Suosikkiartistit",
+ "HeaderFavoriteArtists": "Suosikkiesittäjät",
"HeaderFavoriteAlbums": "Suosikkialbumit",
- "HeaderContinueWatching": "Jatka katsomista",
- "HeaderAlbumArtists": "Albumin artistit",
+ "HeaderContinueWatching": "Jatka katselua",
+ "HeaderAlbumArtists": "Albumin esittäjät",
"Genres": "Tyylilajit",
"Folders": "Kansiot",
"Favorites": "Suosikit",
- "FailedLoginAttemptWithUserName": "Kirjautuminen epäonnistui kohteesta {0}",
+ "FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys lähteestä \"{0}\"",
"DeviceOnlineWithName": "{0} on yhdistetty",
- "DeviceOfflineWithName": "{0} yhteys on katkaistu",
+ "DeviceOfflineWithName": "{0} on katkaissut yhteyden",
"Collections": "Kokoelmat",
- "ChapterNameValue": "Jakso: {0}",
+ "ChapterNameValue": "Kappale {0}",
"Channels": "Kanavat",
- "CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}",
+ "CameraImageUploadedFrom": "Uusi kameran kuva on sirretty lähteestä {0}",
"Books": "Kirjat",
- "AuthenticationSucceededWithUserName": "{0} todennus onnistui",
- "Artists": "Artistit",
+ "AuthenticationSucceededWithUserName": "{0} on todennettu",
+ "Artists": "Esittäjät",
"Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
"Albums": "Albumit",
"User": "Käyttäjä",
"System": "Järjestelmä",
"ScheduledTaskFailedWithName": "{0} epäonnistui",
- "PluginUpdatedWithName": "{0} päivitetty",
- "PluginInstalledWithName": "{0} asennettu",
- "Photos": "Kuvat",
- "ScheduledTaskStartedWithName": "{0} aloitettu",
- "PluginUninstalledWithName": "{0} poistettu",
+ "PluginUpdatedWithName": "{0} päivitettiin",
+ "PluginInstalledWithName": "{0} asennettiin",
+ "Photos": "Valokuvat",
+ "ScheduledTaskStartedWithName": "\"{0}\" käynnistetty",
+ "PluginUninstalledWithName": "{0} poistettiin",
"Playlists": "Soittolistat",
"VersionNumber": "Versio {0}",
- "ValueSpecialEpisodeName": "Erikois - {0}",
- "ValueHasBeenAddedToLibrary": "{0} lisättiin mediakirjastoon",
- "UserStoppedPlayingItemWithValues": "{0} toistaminen valmistui {1} laitteella {2}",
- "UserStartedPlayingItemWithValues": "{0} toistaa {1} laitteella {2}",
- "UserPolicyUpdatedWithName": "Käyttöoikeudet päivitetty käyttäjälle {0}",
- "UserPasswordChangedWithName": "Salasana vaihdettu käyttäjälle {0}",
- "UserOnlineFromDevice": "{0} on paikalla osoitteesta {1}",
- "UserOfflineFromDevice": "{0} yhteys katkaistu kohteesta {1}",
- "UserLockedOutWithName": "Käyttäjä {0} lukittu",
- "UserDownloadingItemWithValues": "{0} lataa {1}",
- "UserDeletedWithName": "Käyttäjä {0} poistettu",
- "UserCreatedWithName": "Käyttäjä {0} luotu",
- "TvShows": "TV-ohjelmat",
- "Sync": "Synkronoi",
- "SubtitleDownloadFailureFromForItem": "Tekstitystä ei voitu ladata osoitteesta {0} kohteelle {1}",
- "StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Yritä hetken kuluttua uudelleen.",
+ "ValueSpecialEpisodeName": "Erikoisjakso - {0}",
+ "ValueHasBeenAddedToLibrary": "\"{0}\" on lisätty mediakirjastoon",
+ "UserStoppedPlayingItemWithValues": "{0} lopetti kohteen \"{1}\" toiston sijainnissa \"{2}\"",
+ "UserStartedPlayingItemWithValues": "{0} toistaa kohdetta \"{1}\" sijainnissa \"{2}\"",
+ "UserPolicyUpdatedWithName": "Käyttäjän {0} käyttöoikeudet on päivitetty",
+ "UserPasswordChangedWithName": "Käyttäjän {0} salasana on vaihdettu",
+ "UserOnlineFromDevice": "{0} on yhdistänyt sijainnista \"{1}\"",
+ "UserOfflineFromDevice": "{0} on katkaissut yhteyden sijainnista \"{1}\"",
+ "UserLockedOutWithName": "Käyttäjä {0} on lukittu",
+ "UserDownloadingItemWithValues": "{0} lataa kohdetta \"{1}\"",
+ "UserDeletedWithName": "Käyttäjä {0} on poistettu",
+ "UserCreatedWithName": "Käyttäjä {0} on luotu",
+ "TvShows": "Sarjat",
+ "Sync": "Synkronointi",
+ "SubtitleDownloadFailureFromForItem": "Tekstityksen lataus lähteestä \"{0}\" kohteelle \"{1}\" epäonnistui",
+ "StartupEmbyServerIsLoading": "Jellyfin-palvelin latautuu. Yritä hetken kuluttua uudelleen.",
"Songs": "Kappaleet",
- "Shows": "Ohjelmat",
- "ServerNameNeedsToBeRestarted": "{0} on käynnistettävä uudelleen",
- "ProviderValue": "Tarjoaja: {0}",
- "Plugin": "Liitännäinen",
- "NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
- "NotificationOptionVideoPlayback": "Videota toistetaan",
- "NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
- "NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
- "NotificationOptionServerRestartRequired": "Palvelin on käynnistettävä uudelleen",
- "NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty",
- "NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
- "NotificationOptionPluginInstalled": "Liitännäinen asennettu",
- "NotificationOptionPluginError": "Ongelma liitännäisessä",
- "NotificationOptionNewLibraryContent": "Uutta sisältöä lisätty",
+ "Shows": "Sarjat",
+ "ServerNameNeedsToBeRestarted": "\"{0}\" on käynnistettävä uudelleen",
+ "ProviderValue": "Lähde: {0}",
+ "Plugin": "Laajennus",
+ "NotificationOptionVideoPlaybackStopped": "Videon toisto lopetettu",
+ "NotificationOptionVideoPlayback": "Videon toisto aloitettu",
+ "NotificationOptionUserLockedOut": "Käyttäjä on lukittu",
+ "NotificationOptionTaskFailed": "Ajoitettu tehtävä epäonnistui",
+ "NotificationOptionServerRestartRequired": "Tarvitaan palvelimen uudelleenkäynnistys",
+ "NotificationOptionPluginUpdateInstalled": "Laajennus on päivitetty",
+ "NotificationOptionPluginUninstalled": "Laajennus on poistettu",
+ "NotificationOptionPluginInstalled": "Laajennus on asennettu",
+ "NotificationOptionPluginError": "Laajennuksen virhe",
+ "NotificationOptionNewLibraryContent": "Sisältöä on lisätty",
"NotificationOptionInstallationFailed": "Asennus epäonnistui",
- "NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
+ "NotificationOptionCameraImageUploaded": "Kameran kuva on tallennettu",
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
- "NotificationOptionAudioPlayback": "Toistetaan ääntä",
- "NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettu",
- "NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla",
+ "NotificationOptionAudioPlayback": "Äänen toisto aloitettu",
+ "NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettiin",
+ "NotificationOptionApplicationUpdateAvailable": "Sovelluspäivitys on saatavilla",
"TasksMaintenanceCategory": "Ylläpito",
- "TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
+ "TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä määritettyjen metatietoasetusten mukaisesti.",
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
"TaskRefreshChannelsDescription": "Päivittää internet-kanavien tiedot.",
"TaskRefreshChannels": "Päivitä kanavat",
- "TaskCleanTranscodeDescription": "Poistaa transkoodatut tiedostot jotka ovat yli päivän vanhoja.",
- "TaskCleanTranscode": "Puhdista transkoodaushakemisto",
- "TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset liitännäisille jotka on asetettu päivittymään automaattisesti.",
- "TaskUpdatePlugins": "Päivitä liitännäiset",
- "TaskRefreshPeopleDescription": "Päivittää näyttelijöiden ja ohjaajien mediatiedot kirjastossasi.",
+ "TaskCleanTranscodeDescription": "Poistaa päivää vanhemmat transkoodaustiedostot.",
+ "TaskCleanTranscode": "Puhdista transkoodauskansio",
+ "TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset laajennuksille, jotka on määritetty päivittymään automaattisesti.",
+ "TaskUpdatePlugins": "Päivitä laajennukset",
+ "TaskRefreshPeopleDescription": "Päivittää mediakirjaston näyttelijöiden ja ohjaajien metatiedot.",
"TaskRefreshPeople": "Päivitä henkilöt",
- "TaskCleanLogsDescription": "Poistaa lokitiedostot jotka ovat yli {0} päivää vanhoja.",
- "TaskCleanLogs": "Puhdista lokihakemisto",
- "TaskRefreshLibraryDescription": "Skannaa mediakirjastosi uudet tiedostot ja päivittää metatiedot.",
- "TaskRefreshLibrary": "Skannaa mediakirjasto",
- "TaskRefreshChapterImagesDescription": "Luo pienoiskuvat videoille joissa on jaksoja.",
- "TaskRefreshChapterImages": "Pura jakson kuvat",
- "TaskCleanCacheDescription": "Poistaa järjestelmälle tarpeettomat väliaikaistiedostot.",
- "TaskCleanCache": "Tyhjennä välimuisti-hakemisto",
- "TasksChannelsCategory": "Internet kanavat",
+ "TaskCleanLogsDescription": "Poistaa {0} päivää vanhemmat lokitiedostot.",
+ "TaskCleanLogs": "Siivoa lokikansio",
+ "TaskRefreshLibraryDescription": "Tarkastaa mediakirjastosi sisällön uusien tiedostojen varalta ja päivittää metatiedot.",
+ "TaskRefreshLibrary": "Päivitä mediakirjasto",
+ "TaskRefreshChapterImagesDescription": "Luo esikatselukuvat videoille, jotka sisältävät kappalejaon.",
+ "TaskRefreshChapterImages": "Pura kappalejaon kuvat",
+ "TaskCleanCacheDescription": "Poistaa tarpeettomiksi jääneet väliaikaistiedostot.",
+ "TaskCleanCache": "Tyhjennä välimuistikansio",
+ "TasksChannelsCategory": "Internet-kanavat",
"TasksApplicationCategory": "Sovellus",
"TasksLibraryCategory": "Kirjasto",
"Forced": "Pakotettu",
"Default": "Oletus",
- "TaskCleanActivityLogDescription": "Poistaa määritettyä vanhemmat tapahtumat aktiviteettilokista.",
- "TaskCleanActivityLog": "Tyhjennä aktiviteettiloki",
+ "TaskCleanActivityLogDescription": "Poistaa määritettyä ikää vanhemmat tapahtumat toimintahistoriasta.",
+ "TaskCleanActivityLog": "Tyhjennä toimintahistoria",
"Undefined": "Määrittelemätön"
}
diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json
index befe4e14f6..a321e35d03 100644
--- a/Emby.Server.Implementations/Localization/Core/kk.json
+++ b/Emby.Server.Implementations/Localization/Core/kk.json
@@ -1,122 +1,122 @@
{
- "Albums": "Álbomdar",
- "AppDeviceValues": "Qoldanba: {0}, Qurylǵy: {1}",
+ "Albums": "Älbomdar",
+ "AppDeviceValues": "Qoldanba: {0}, Qūrylğy: {1}",
"Application": "Qoldanba",
- "Artists": "Oryndaýshylar",
- "AuthenticationSucceededWithUserName": "{0} túpnusqalyq rastalýy sátti aıaqtaldy",
- "Books": "Kitaptar",
- "CameraImageUploadedFrom": "{0} kamerasynan jańa sýret júktep salyndy",
+ "Artists": "Oryndauşylar",
+ "AuthenticationSucceededWithUserName": "{0} tüpnūsqalyq rastaluy sättı aiaqtaldy",
+ "Books": "Kıtaptar",
+ "CameraImageUploadedFrom": "{0} kamerasynan jaŋa suret jüktep salyndy",
"Channels": "Arnalar",
"ChapterNameValue": "{0}-sahna",
- "Collections": "Jıyntyqtar",
- "DeviceOfflineWithName": "{0} ajyratylǵan",
- "DeviceOnlineWithName": "{0} qosylǵan",
- "FailedLoginAttemptWithUserName": "{0} tarapynan kirý áreketi sátsiz aıaqtaldy",
- "Favorites": "Tańdaýlylar",
+ "Collections": "Jiyntyqtar",
+ "DeviceOfflineWithName": "{0} ajyratylğan",
+ "DeviceOnlineWithName": "{0} qosylğan",
+ "FailedLoginAttemptWithUserName": "{0} tarapynan kıru äreketı sätsız aiaqtaldy",
+ "Favorites": "Taŋdaulylar",
"Folders": "Qaltalar",
"Genres": "Janrlar",
- "HeaderAlbumArtists": "Álbom oryndaýshylary",
- "HeaderContinueWatching": "Qaraýdy jalǵastyrý",
- "HeaderFavoriteAlbums": "Tańdaýly álbomdar",
- "HeaderFavoriteArtists": "Tańdaýly oryndaýshylar",
- "HeaderFavoriteEpisodes": "Tańdaýly bólimder",
- "HeaderFavoriteShows": "Tańdaýly kórsetimder",
- "HeaderFavoriteSongs": "Tańdaýly áýender",
- "HeaderLiveTV": "Efır",
- "HeaderNextUp": "Kezekti",
+ "HeaderAlbumArtists": "Älbom oryndauşylary",
+ "HeaderContinueWatching": "Qaraudy jalğastyru",
+ "HeaderFavoriteAlbums": "Taŋdauly älbomdar",
+ "HeaderFavoriteArtists": "Taŋdauly oryndauşylar",
+ "HeaderFavoriteEpisodes": "Taŋdauly telebölımder",
+ "HeaderFavoriteShows": "Taŋdauly körsetımder",
+ "HeaderFavoriteSongs": "Taŋdauly äuender",
+ "HeaderLiveTV": "Efir",
+ "HeaderNextUp": "Kezektı",
"HeaderRecordingGroups": "Jazba toptary",
- "HomeVideos": "Úılik beıneler",
- "Inherit": "Muraǵa ıelený",
- "ItemAddedWithName": "{0} tasyǵyshhanaǵa ústeldi",
- "ItemRemovedWithName": "{0} tasyǵyshhanadan alastaldy",
- "LabelIpAddressValue": "IP-mekenjaıy: {0}",
- "LabelRunningTimeValue": "Oınatý ýaqyty: {0}",
- "Latest": "Eń keıingi",
- "MessageApplicationUpdated": "Jellyfin Serveri jańartyldy",
- "MessageApplicationUpdatedTo": "Jellyfin Serveri {0} nusqasyna jańartyldy",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server konfıgýrasýasynyń {0} bólimi jańartyldy",
- "MessageServerConfigurationUpdated": "Server konfıgýrasıasy jańartyldy",
- "MixedContent": "Aralas mazmun",
- "Movies": "Fılmder",
- "Music": "Mýzyka",
- "MusicVideos": "Mýzykalyq beıneler",
- "NameInstallFailed": "{0} ornatylýy sátsiz",
- "NameSeasonNumber": "{0}-maýsym",
- "NameSeasonUnknown": "Belgisiz maýsym",
- "NewVersionIsAvailable": "Jańa Jellyfin Server nusqasy júktep alýǵa qoljetimdi.",
- "NotificationOptionApplicationUpdateAvailable": "Qoldanba jańartýy qoljetimdi",
- "NotificationOptionApplicationUpdateInstalled": "Qoldanba jańartýy ornatyldy",
- "NotificationOptionAudioPlayback": "Dybys oınatýy bastaldy",
- "NotificationOptionAudioPlaybackStopped": "Dybys oınatýy toqtatyldy",
- "NotificationOptionCameraImageUploaded": "Kameradan fotosýret júktep salynǵan",
- "NotificationOptionInstallationFailed": "Ornatý sátsizdigi",
- "NotificationOptionNewLibraryContent": "Jańa mazmun ústelgen",
- "NotificationOptionPluginError": "Plagın sátsizdigi",
- "NotificationOptionPluginInstalled": "Plagın ornatyldy",
- "NotificationOptionPluginUninstalled": "Plagın ornatýy boldyrylmady",
- "NotificationOptionPluginUpdateInstalled": "Plagın jańartýy ornatyldy",
- "NotificationOptionServerRestartRequired": "Serverdi qaıta iske qosý qajet",
- "NotificationOptionTaskFailed": "Josparlaǵan tapsyrma sátsizdigi",
- "NotificationOptionUserLockedOut": "Paıdalanýshy qursaýly",
- "NotificationOptionVideoPlayback": "Beıne oınatýy bastaldy",
- "NotificationOptionVideoPlaybackStopped": "Beıne oınatýy toqtatyldy",
- "Photos": "Fotosýretter",
- "Playlists": "Oınatý tizimderi",
- "Plugin": "Plagın",
+ "HomeVideos": "Üilık beineler",
+ "Inherit": "İelenu",
+ "ItemAddedWithName": "{0} tasyğyşhanağa üstelindı",
+ "ItemRemovedWithName": "{0} tasyğyşhanadan alastaldy",
+ "LabelIpAddressValue": "IP-mekenjaiy: {0}",
+ "LabelRunningTimeValue": "Oinatu uaqyty: {0}",
+ "Latest": "Eŋ keiıngı",
+ "MessageApplicationUpdated": "Jellyfin Serverı jaŋartyldy",
+ "MessageApplicationUpdatedTo": "Jellyfin Serverı {0} nūsqasyna jaŋartyldy",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Server teŋşelımderınıŋ {0} bölımı jaŋartyldy",
+ "MessageServerConfigurationUpdated": "Server teŋşelımderı jaŋartyldy",
+ "MixedContent": "Aralas mazmūn",
+ "Movies": "Filmder",
+ "Music": "Muzyka",
+ "MusicVideos": "Muzykalyq beineler",
+ "NameInstallFailed": "{0} ornatyluy sätsız",
+ "NameSeasonNumber": "{0}-mausym",
+ "NameSeasonUnknown": "Belgısız mausym",
+ "NewVersionIsAvailable": "Jaŋa Jellyfin Server nūsqasy jüktep aluğa qoljetımdı.",
+ "NotificationOptionApplicationUpdateAvailable": "Qoldanba jaŋartuy qoljetımdı",
+ "NotificationOptionApplicationUpdateInstalled": "Qoldanba jaŋartuy ornatyldy",
+ "NotificationOptionAudioPlayback": "Dybys oinatuy bastaldy",
+ "NotificationOptionAudioPlaybackStopped": "Dybys oinatuy toqtatyldy",
+ "NotificationOptionCameraImageUploaded": "Kameradan fotosuret jüktep salynğan",
+ "NotificationOptionInstallationFailed": "Ornatu sätsızdıgı",
+ "NotificationOptionNewLibraryContent": "Jaŋa mazmūn üstelıngen",
+ "NotificationOptionPluginError": "Plagin sätsızdıgı",
+ "NotificationOptionPluginInstalled": "Plagin ornatyldy",
+ "NotificationOptionPluginUninstalled": "Plagin ornatuy boldyrylmady",
+ "NotificationOptionPluginUpdateInstalled": "Plagin jaŋartuy ornatyldy",
+ "NotificationOptionServerRestartRequired": "Serverdı qaita ıske qosu qajet",
+ "NotificationOptionTaskFailed": "Josparlağan tapsyrma sätsızdıgı",
+ "NotificationOptionUserLockedOut": "Paidalanuşy qūrsauly",
+ "NotificationOptionVideoPlayback": "Beine oinatuy bastaldy",
+ "NotificationOptionVideoPlaybackStopped": "Beine oinatuy toqtatyldy",
+ "Photos": "Fotosuretter",
+ "Playlists": "Oinatu tızımderı",
+ "Plugin": "Plagin",
"PluginInstalledWithName": "{0} ornatyldy",
- "PluginUninstalledWithName": "{0} joıyldy",
- "PluginUpdatedWithName": "{0} jańartyldy",
- "ProviderValue": "Jetkizýshi: {0}",
- "ScheduledTaskFailedWithName": "{0} sátsiz",
- "ScheduledTaskStartedWithName": "{0} iske qosyldy",
- "ServerNameNeedsToBeRestarted": "{0} qaıta iske qosý qajet",
- "Shows": "Kórsetimder",
- "Songs": "Áýender",
- "StartupEmbyServerIsLoading": "Jellyfin Server júktelýde. Áreketti kóp uzamaı qaıtalańyz.",
+ "PluginUninstalledWithName": "{0} joiyldy",
+ "PluginUpdatedWithName": "{0} jaŋartyldy",
+ "ProviderValue": "Jetkızuşı: {0}",
+ "ScheduledTaskFailedWithName": "{0} sätsız",
+ "ScheduledTaskStartedWithName": "{0} ıske qosyldy",
+ "ServerNameNeedsToBeRestarted": "{0} qaita ıske qosu qajet",
+ "Shows": "Körsetımder",
+ "Songs": "Äuender",
+ "StartupEmbyServerIsLoading": "Jellyfin Server jüktelude. Ärekettı köp ūzamai qaitalaŋyz.",
"SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
- "SubtitleDownloadFailureFromForItem": "{1} úshin sýbtıtrlerdi {0} kózinen júktep alý sátsiz",
- "Sync": "Úndestirý",
- "System": "Júıe",
- "TvShows": "TD-kórsetimder",
- "User": "Paıdalanýshy",
- "UserCreatedWithName": "Paıdalanýshy {0} jasalǵan",
- "UserDeletedWithName": "Paıdalanýshy {0} joıylǵan",
- "UserDownloadingItemWithValues": "{0} mynany júktep alýda: {1}",
- "UserLockedOutWithName": "Paıdalanýshy {0} qursaýly",
- "UserOfflineFromDevice": "{0} - {1} tarapynan ajyratylǵan",
- "UserOnlineFromDevice": "{0} - {1} arqyly qosylǵan",
- "UserPasswordChangedWithName": "Paıdalanýshy {0} úshin paról ózgertildi",
- "UserPolicyUpdatedWithName": "Paıdalanýshy {0} úshin saıasattary jańartyldy",
- "UserStartedPlayingItemWithValues": "{0} - {1} oınatýyn {2} bastady",
- "UserStoppedPlayingItemWithValues": "{0} - {1} oınatýyn {2} toqtatty",
- "ValueHasBeenAddedToLibrary": "{0} (tasyǵyshhanaǵa ústelindi)",
- "ValueSpecialEpisodeName": "Arnaıy - {0}",
- "VersionNumber": "Nusqasy {0}",
- "Default": "Ádepki",
- "TaskDownloadMissingSubtitles": "Joq sýbtıtrlerdi júktep alý",
- "TaskRefreshChannels": "Arnalardy jańǵyrtý",
- "TaskCleanTranscode": "Qaıta kodtaý katalogyn tazalaý",
- "TaskUpdatePlugins": "Plagınderdi jańartý",
- "TaskRefreshPeople": "Adamdardy jańartý",
- "TaskCleanLogs": "Jurnal katalogyn tazalaý",
- "TaskRefreshLibrary": "Tasyǵyshhanany skanerleý",
- "TaskRefreshChapterImages": "Sahna keskinderin shyǵaryp alý",
- "TaskCleanCache": "Kesh katalogyn tazalaý",
- "TaskCleanActivityLog": "Áreket jurnalyn tazalaý",
+ "SubtitleDownloadFailureFromForItem": "{1} üşın subtitrlerdı {0} közınen jüktep alu sätsız",
+ "Sync": "Ündestıru",
+ "System": "Jüie",
+ "TvShows": "TD-körsetımder",
+ "User": "Paidalanuşy",
+ "UserCreatedWithName": "Paidalanuşy {0} jasalğan",
+ "UserDeletedWithName": "Paidalanuşy {0} joiylğan",
+ "UserDownloadingItemWithValues": "{0} — {1} jüktep aluda",
+ "UserLockedOutWithName": "Paidalanuşy {0} qūrsaulanğan",
+ "UserOfflineFromDevice": "{0} — {1} tarapynan ajyratyldy",
+ "UserOnlineFromDevice": "{0} — {1} tarapynan qosyldy",
+ "UserPasswordChangedWithName": "Paidalanuşy {0} üşın paröl özgertıldı",
+ "UserPolicyUpdatedWithName": "Paidalanuşy {0} üşın saiasattary jaŋartyldy",
+ "UserStartedPlayingItemWithValues": "{0} — {2} tarapynan {1} oinatuda",
+ "UserStoppedPlayingItemWithValues": "{0} — {2} tarapynan {1} oinatuyn toqtatty",
+ "ValueHasBeenAddedToLibrary": "{0} tasyğyşhanağa üstelındı",
+ "ValueSpecialEpisodeName": "Arnaiy - {0}",
+ "VersionNumber": "Nūsqasy {0}",
+ "Default": "Ädepkı",
+ "TaskDownloadMissingSubtitles": "Joq subtitrlerdı jüktep alu",
+ "TaskRefreshChannels": "Arnalardy jaŋğyrtu",
+ "TaskCleanTranscode": "Qaita kodtau katalogyn tazalau",
+ "TaskUpdatePlugins": "Plaginderdı jaŋartu",
+ "TaskRefreshPeople": "Adamdardy jaŋğyrtu",
+ "TaskCleanLogs": "Jūrnal katalogyn tazalau",
+ "TaskRefreshLibrary": "Tasyğyşhanany skanerleu",
+ "TaskRefreshChapterImages": "Sahna suretterın şyğaryp alu",
+ "TaskCleanCache": "Keş katalogyn tazalau",
+ "TaskCleanActivityLog": "Äreket jūrnalyn tazalau",
"TasksChannelsCategory": "Internet-arnalar",
"TasksApplicationCategory": "Qoldanba",
- "TasksLibraryCategory": "Tasyǵyshhana",
- "TasksMaintenanceCategory": "Qyzmet kórsetý",
- "Undefined": "Anyqtalmady",
- "Forced": "Májbúrli",
- "TaskDownloadMissingSubtitlesDescription": "Metaderekter teńshelimi negіzіnde joq sýbtıtrlerdі Internetten іzdeıdі.",
- "TaskRefreshChannelsDescription": "Internet-arnalar málimetterin jańǵyrtady.",
- "TaskCleanTranscodeDescription": "Bіr kúnnen asqan qaıta kodtaý faıldaryn joıady.",
- "TaskUpdatePluginsDescription": "Avtomatty túrde jańartýǵa teńshelgen plagınder úshin jańartýlardy júktep alady jáne ornatady.",
- "TaskRefreshPeopleDescription": "Tasyǵyshhanadaǵy aktórler men rejısórler metaderekterіn jańartady.",
- "TaskCleanLogsDescription": "{0} kúnnen asqan jurnal faıldaryn joıady.",
- "TaskRefreshLibraryDescription": "Tasyǵyshhanadaǵy jańa faıldardy skanerleıdі jáne metaderekterdі jańartady.",
- "TaskRefreshChapterImagesDescription": "Sahnalarǵa bólіngen beıneler úshіn nobaılar jasaıdy.",
- "TaskCleanCacheDescription": "Júıede qajet emes keshtelgen faıldardy joıady.",
- "TaskCleanActivityLogDescription": "Áreketter jurnalyndaǵy teńshelgen jasynan asqan jazbalaly joıady."
+ "TasksLibraryCategory": "Tasyğyşhana",
+ "TasksMaintenanceCategory": "Qyzmet körsetu",
+ "Undefined": "Anyqtalmağan",
+ "Forced": "Mäjbürlı",
+ "TaskDownloadMissingSubtitlesDescription": "Metaderekter teŋşelımderı negızınde joq subtitrlerdı Internetten ızdeidı.",
+ "TaskRefreshChannelsDescription": "Internet-arnalar mälımetterın jaŋğyrtady.",
+ "TaskCleanTranscodeDescription": "Bіr künnen asqan qaita kodtau faildaryn joiady.",
+ "TaskUpdatePluginsDescription": "Avtomatty türde jaŋartuğa teŋşelgen plaginder üşın jaŋartulardy jüktep alady jäne ornatady.",
+ "TaskRefreshPeopleDescription": "Tasyğyşhanadağy aktörler men rejisörler metaderekterın jaŋartady.",
+ "TaskCleanLogsDescription": "{0} künnen asqan jūrnal faildaryn joiady.",
+ "TaskRefreshLibraryDescription": "Tasyğyşhanadağy jaŋa faildardy skanerleidі jäne metaderekterdı jaŋğyrtady.",
+ "TaskRefreshChapterImagesDescription": "Sahnalary bar beineler üşіn nobailar jasaidy.",
+ "TaskCleanCacheDescription": "Jüiede qajet emes keştelgen faildardy joiady.",
+ "TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teŋşelgen jasynan asqan jazbalary joiady."
}
diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json
index 03d30247a7..46b47cf4a8 100644
--- a/Emby.Server.Implementations/Localization/Core/ru.json
+++ b/Emby.Server.Implementations/Localization/Core/ru.json
@@ -89,8 +89,8 @@
"UserPolicyUpdatedWithName": "Политики пользователя {0} были обновлены",
"UserStartedPlayingItemWithValues": "{0} - воспроизведение «{1}» на {2}",
"UserStoppedPlayingItemWithValues": "{0} - воспроизведение остановлено «{1}» на {2}",
- "ValueHasBeenAddedToLibrary": "{0} (добавлено в медиатеку)",
- "ValueSpecialEpisodeName": "Специальный эпизод - {0}",
+ "ValueHasBeenAddedToLibrary": "{0} добавлено в медиатеку",
+ "ValueSpecialEpisodeName": "Спецэпизод - {0}",
"VersionNumber": "Версия {0}",
"TaskDownloadMissingSubtitles": "Загрузка отсутствующих субтитров",
"TaskRefreshChannels": "Обновление каналов",
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index 552710d703..345d41e9ee 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -117,5 +117,5 @@
"TaskCleanActivityLogDescription": "Radera aktivitets logg inlägg som är äldre än definerad ålder.",
"TaskCleanActivityLog": "Rensa Aktivitets Logg",
"Undefined": "odefinierad",
- "Forced": "Tvinga"
+ "Forced": "Tvingad"
}
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 9f597f3ef3..c26ccfd886 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -112,8 +112,6 @@ namespace Emby.Server.Implementations.Plugins
{
assembly = Assembly.LoadFrom(file);
- // This force loads all reference dll's that the plugin uses in the try..catch block.
- // Removing this will cause JF to bomb out if referenced dll's cause issues.
assembly.GetExportedTypes();
}
catch (FileLoadException ex)
@@ -122,6 +120,20 @@ namespace Emby.Server.Implementations.Plugins
ChangePluginState(plugin, PluginStatus.Malfunctioned);
continue;
}
+ catch (TypeLoadException ex) // Undocumented exception
+ {
+ _logger.LogError(ex, "Failed to load assembly {Path}. This error occurs when a plugin references an incompatible version of one of the shared libraries. Disabling plugin.", file);
+ ChangePluginState(plugin, PluginStatus.NotSupported);
+ continue;
+ }
+#pragma warning disable CA1031 // Do not catch general exception types
+ catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
+ {
+ _logger.LogError(ex, "Failed to load assembly {Path}. Unknown exception was thrown. Disabling plugin.", file);
+ ChangePluginState(plugin, PluginStatus.Malfunctioned);
+ continue;
+ }
_logger.LogInformation("Loaded assembly {Assembly} from {Path}", assembly.FullName, file);
yield return assembly;
@@ -336,7 +348,7 @@ namespace Emby.Server.Implementations.Plugins
try
{
var data = JsonSerializer.Serialize(manifest, _jsonOptions);
- File.WriteAllText(Path.Combine(path, "meta.json"), data, Encoding.UTF8);
+ File.WriteAllText(Path.Combine(path, "meta.json"), data);
return true;
}
#pragma warning disable CA1031 // Do not catch general exception types
@@ -507,39 +519,43 @@ namespace Emby.Server.Implementations.Plugins
return _plugins.Remove(plugin);
}
- private LocalPlugin LoadManifest(string dir)
+ internal LocalPlugin LoadManifest(string dir)
{
Version? version;
PluginManifest? manifest = null;
var metafile = Path.Combine(dir, "meta.json");
if (File.Exists(metafile))
{
+ // Only path where this stays null is when File.ReadAllBytes throws an IOException
+ byte[] data = null!;
try
{
- var data = File.ReadAllText(metafile, Encoding.UTF8);
+ data = File.ReadAllBytes(metafile);
manifest = JsonSerializer.Deserialize<PluginManifest>(data, _jsonOptions);
}
-#pragma warning disable CA1031 // Do not catch general exception types
- catch (Exception ex)
-#pragma warning restore CA1031 // Do not catch general exception types
+ catch (IOException ex)
{
- _logger.LogError(ex, "Error deserializing {Path}.", dir);
+ _logger.LogError(ex, "Error reading file {Path}.", dir);
}
- }
-
- if (manifest != null)
- {
- if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
+ catch (JsonException ex)
{
- targetAbi = _minimumVersion;
+ _logger.LogError(ex, "Error deserializing {Json}.", Encoding.UTF8.GetString(data!));
}
- if (!Version.TryParse(manifest.Version, out version))
+ if (manifest != null)
{
- manifest.Version = _minimumVersion.ToString();
- }
+ if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
+ {
+ targetAbi = _minimumVersion;
+ }
- return new LocalPlugin(dir, _appVersion >= targetAbi, manifest);
+ if (!Version.TryParse(manifest.Version, out version))
+ {
+ manifest.Version = _minimumVersion.ToString();
+ }
+
+ return new LocalPlugin(dir, _appVersion >= targetAbi, manifest);
+ }
}
// No metafile, so lets see if the folder is versioned.
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index d3cf3bf3f4..b302303f88 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -143,21 +143,21 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
if (File.Exists(path))
{
- try
+ var bytes = File.ReadAllBytes(path);
+ if (bytes.Length > 0)
{
- var jsonString = File.ReadAllText(path, Encoding.UTF8);
- if (!string.IsNullOrWhiteSpace(jsonString))
+ try
{
- _lastExecutionResult = JsonSerializer.Deserialize<TaskResult>(jsonString, _jsonOptions);
+ _lastExecutionResult = JsonSerializer.Deserialize<TaskResult>(bytes, _jsonOptions);
}
- else
+ catch (JsonException ex)
{
- _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path);
+ _logger.LogError(ex, "Error deserializing {File}", path);
}
}
- catch (Exception ex)
+ else
{
- _logger.LogError(ex, "Error deserializing {File}", path);
+ _logger.LogDebug("Scheduled Task history file {Path} is empty. Skipping deserialization.", path);
}
}
@@ -541,8 +541,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
TaskTriggerInfo[] list = null;
if (File.Exists(path))
{
- var jsonString = File.ReadAllText(path, Encoding.UTF8);
- list = JsonSerializer.Deserialize<TaskTriggerInfo[]>(jsonString, _jsonOptions);
+ var bytes = File.ReadAllBytes(path);
+ list = JsonSerializer.Deserialize<TaskTriggerInfo[]>(bytes, _jsonOptions);
}
// Return defaults if file doesn't exist.
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 4e026a0e6a..10e28c33a5 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -1456,7 +1456,12 @@ namespace Emby.Server.Implementations.Session
throw new SecurityException("Unknown quick connect token");
}
- request.UserId = result.Items[0].UserId;
+ var info = result.Items[0];
+ request.UserId = info.UserId;
+
+ // There's no need to keep the quick connect token in the database, as AuthenticateNewSessionInternal() issues a long lived token.
+ _authRepo.Delete(info);
+
return AuthenticateNewSessionInternal(request, false);
}
diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs
index b77d79209a..ff7895373b 100644
--- a/Jellyfin.Api/Controllers/DashboardController.cs
+++ b/Jellyfin.Api/Controllers/DashboardController.cs
@@ -51,7 +51,6 @@ namespace Jellyfin.Api.Controllers
/// Gets the configuration pages.
/// </summary>
/// <param name="enableInMainMenu">Whether to enable in the main menu.</param>
- /// <param name="pageType">The <see cref="ConfigurationPageInfo"/>.</param>
/// <response code="200">ConfigurationPages returned.</response>
/// <response code="404">Server still loading.</response>
/// <returns>An <see cref="IEnumerable{ConfigurationPageInfo}"/> with infos about the plugins.</returns>
@@ -59,40 +58,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<IEnumerable<ConfigurationPageInfo?>> GetConfigurationPages(
- [FromQuery] bool? enableInMainMenu,
- [FromQuery] ConfigurationPageType? pageType)
+ [FromQuery] bool? enableInMainMenu)
{
- const string unavailableMessage = "The server is still loading. Please try again momentarily.";
-
- var pages = _appHost.GetExports<IPluginConfigurationPage>().ToList();
-
- if (pages == null)
- {
- return NotFound(unavailableMessage);
- }
-
- // Don't allow a failing plugin to fail them all
- var configPages = pages.Select(p =>
- {
- try
- {
- return new ConfigurationPageInfo(p);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting plugin information from {Plugin}", p.GetType().Name);
- return null;
- }
- })
- .Where(i => i != null)
- .ToList();
-
- configPages.AddRange(_pluginManager.Plugins.SelectMany(GetConfigPages));
-
- if (pageType.HasValue)
- {
- configPages = configPages.Where(p => p!.ConfigurationPageType == pageType).ToList();
- }
+ var configPages = _pluginManager.Plugins.SelectMany(GetConfigPages).ToList();
if (enableInMainMenu.HasValue)
{
@@ -121,24 +89,14 @@ namespace Jellyfin.Api.Controllers
var isJs = false;
var isTemplate = false;
- var page = _appHost.GetExports<IPluginConfigurationPage>().FirstOrDefault(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));
- if (page != null)
- {
- plugin = page.Plugin;
- stream = page.GetHtmlStream();
- }
-
- if (plugin == null)
+ var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase));
+ if (altPage != null)
{
- var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase));
- if (altPage != null)
- {
- plugin = altPage.Item2;
- stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath);
+ plugin = altPage.Item2;
+ stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath);
- isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase);
- isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal);
- }
+ isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase);
+ isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal);
}
if (plugin != null && stream != null)
diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs
index 9ab8e0bdcf..c589f54ac4 100644
--- a/Jellyfin.Api/Controllers/PackageController.cs
+++ b/Jellyfin.Api/Controllers/PackageController.cs
@@ -158,7 +158,7 @@ namespace Jellyfin.Api.Controllers
[HttpPost("Repositories")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult SetRepositories([FromBody] List<RepositoryInfo> repositoryInfos)
+ public ActionResult SetRepositories([FromBody, Required] List<RepositoryInfo> repositoryInfos)
{
_serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos;
_serverConfigurationManager.SaveConfiguration();
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index 34c9f32fa4..bacd95baca 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -278,7 +278,7 @@ namespace Jellyfin.Api.Controllers
var directPlayProfiles = new DirectPlayProfile[len];
for (int i = 0; i < len; i++)
{
- var parts = RequestHelpers.Split(containers[i], '|', true);
+ var parts = containers[i].Split('|', StringSplitOptions.RemoveEmptyEntries);
var audioCodecs = parts.Length == 1 ? null : string.Join(',', parts.Skip(1));
@@ -312,25 +312,52 @@ namespace Jellyfin.Api.Controllers
if (maxAudioSampleRate.HasValue)
{
// codec profile
- conditions.Add(new ProfileCondition { Condition = ProfileConditionType.LessThanEqual, IsRequired = false, Property = ProfileConditionValue.AudioSampleRate, Value = maxAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture) });
+ conditions.Add(
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ IsRequired = false,
+ Property = ProfileConditionValue.AudioSampleRate,
+ Value = maxAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture)
+ });
}
if (maxAudioBitDepth.HasValue)
{
// codec profile
- conditions.Add(new ProfileCondition { Condition = ProfileConditionType.LessThanEqual, IsRequired = false, Property = ProfileConditionValue.AudioBitDepth, Value = maxAudioBitDepth.Value.ToString(CultureInfo.InvariantCulture) });
+ conditions.Add(
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ IsRequired = false,
+ Property = ProfileConditionValue.AudioBitDepth,
+ Value = maxAudioBitDepth.Value.ToString(CultureInfo.InvariantCulture)
+ });
}
if (maxAudioChannels.HasValue)
{
// codec profile
- conditions.Add(new ProfileCondition { Condition = ProfileConditionType.LessThanEqual, IsRequired = false, Property = ProfileConditionValue.AudioChannels, Value = maxAudioChannels.Value.ToString(CultureInfo.InvariantCulture) });
+ conditions.Add(
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ IsRequired = false,
+ Property = ProfileConditionValue.AudioChannels,
+ Value = maxAudioChannels.Value.ToString(CultureInfo.InvariantCulture)
+ });
}
if (conditions.Count > 0)
{
// codec profile
- codecProfiles.Add(new CodecProfile { Type = CodecType.Audio, Container = string.Join(',', containers), Conditions = conditions.ToArray() });
+ codecProfiles.Add(
+ new CodecProfile
+ {
+ Type = CodecType.Audio,
+ Container = string.Join(',', containers),
+ Conditions = conditions.ToArray()
+ });
}
deviceProfile.CodecProfiles = codecProfiles.ToArray();
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index 0f0bee4bcf..43ee309b76 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -509,14 +509,14 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Redeems a forgot password pin.
/// </summary>
- /// <param name="pin">The pin.</param>
+ /// <param name="forgotPasswordPinRequest">The forgot password pin request containing the entered pin.</param>
/// <response code="200">Pin reset process started.</response>
/// <returns>A <see cref="Task"/> containing a <see cref="PinRedeemResult"/>.</returns>
[HttpPost("ForgotPassword/Pin")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task<ActionResult<PinRedeemResult>> ForgotPasswordPin([FromBody] string? pin)
+ public async Task<ActionResult<PinRedeemResult>> ForgotPasswordPin([FromBody, Required] ForgotPasswordPinDto forgotPasswordPinRequest)
{
- var result = await _userManager.RedeemPasswordResetPin(pin).ConfigureAwait(false);
+ var result = await _userManager.RedeemPasswordResetPin(forgotPasswordPinRequest.Pin).ConfigureAwait(false);
return result;
}
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index a4da54cfdf..92ff42b49f 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -427,7 +427,7 @@ namespace Jellyfin.Api.Helpers
if (framerate.HasValue)
{
builder.Append(",FRAME-RATE=")
- .Append(framerate.Value);
+ .Append(framerate.Value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs
index 056ad83daf..db0ccc6577 100644
--- a/Jellyfin.Api/Helpers/RequestHelpers.cs
+++ b/Jellyfin.Api/Helpers/RequestHelpers.cs
@@ -25,44 +25,30 @@ namespace Jellyfin.Api.Helpers
/// <param name="sortBy">Sort By. Comma delimited string.</param>
/// <param name="requestedSortOrder">Sort Order. Comma delimited string.</param>
/// <returns>Order By.</returns>
- public static ValueTuple<string, SortOrder>[] GetOrderBy(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder)
+ public static (string, SortOrder)[] GetOrderBy(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder)
{
if (sortBy.Count == 0)
{
return Array.Empty<ValueTuple<string, SortOrder>>();
}
- var result = new ValueTuple<string, SortOrder>[sortBy.Count];
- for (var i = 0; i < sortBy.Count; i++)
+ var result = new (string, SortOrder)[sortBy.Count];
+ var i = 0;
+ // Add elements which have a SortOrder specified
+ for (; i < requestedSortOrder.Count; i++)
{
- var sortOrderIndex = requestedSortOrder.Count > i ? i : 0;
-
- var sortOrder = requestedSortOrder.Count > sortOrderIndex
- ? requestedSortOrder[sortOrderIndex]
- : SortOrder.Ascending;
- result[i] = new ValueTuple<string, SortOrder>(sortBy[i], sortOrder);
+ result[i] = (sortBy[i], requestedSortOrder[i]);
}
- return result;
- }
-
- /// <summary>
- /// Splits a string at a separating character into an array of substrings.
- /// </summary>
- /// <param name="value">The string to split.</param>
- /// <param name="separator">The char that separates the substrings.</param>
- /// <param name="removeEmpty">Option to remove empty substrings from the array.</param>
- /// <returns>An array of the substrings.</returns>
- internal static string[] Split(string? value, char separator, bool removeEmpty)
- {
- if (string.IsNullOrWhiteSpace(value))
+ // Add remaining elements with the first specified SortOrder
+ // or the default one if no SortOrders are specified
+ var order = requestedSortOrder.Count > 0 ? requestedSortOrder[0] : SortOrder.Ascending;
+ for (; i < sortBy.Count; i++)
{
- return Array.Empty<string>();
+ result[i] = (sortBy[i], order);
}
- return removeEmpty
- ? value.Split(separator, StringSplitOptions.RemoveEmptyEntries)
- : value.Split(separator);
+ return result;
}
/// <summary>
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index 8437369b2f..c2f4ab522a 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -15,10 +15,10 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.2" />
+ <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
- <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" />
+ <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.0.2" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Api/Models/ConfigurationPageInfo.cs b/Jellyfin.Api/Models/ConfigurationPageInfo.cs
index f56ef59765..a7bbe42fe5 100644
--- a/Jellyfin.Api/Models/ConfigurationPageInfo.cs
+++ b/Jellyfin.Api/Models/ConfigurationPageInfo.cs
@@ -13,23 +13,6 @@ namespace Jellyfin.Api.Models
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationPageInfo"/> class.
/// </summary>
- /// <param name="page">Instance of <see cref="IPluginConfigurationPage"/> interface.</param>
- public ConfigurationPageInfo(IPluginConfigurationPage page)
- {
- Name = page.Name;
-
- ConfigurationPageType = page.ConfigurationPageType;
-
- if (page.Plugin != null)
- {
- DisplayName = page.Plugin.Name;
- PluginId = page.Plugin.Id;
- }
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ConfigurationPageInfo"/> class.
- /// </summary>
/// <param name="plugin">Instance of <see cref="IPlugin"/> interface.</param>
/// <param name="page">Instance of <see cref="PluginPageInfo"/> interface.</param>
public ConfigurationPageInfo(IPlugin? plugin, PluginPageInfo page)
@@ -69,12 +52,6 @@ namespace Jellyfin.Api.Models
public string? DisplayName { get; set; }
/// <summary>
- /// Gets or sets the type of the configuration page.
- /// </summary>
- /// <value>The type of the configuration page.</value>
- public ConfigurationPageType ConfigurationPageType { get; set; }
-
- /// <summary>
/// Gets or sets the plugin id.
/// </summary>
/// <value>The plugin id.</value>
diff --git a/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs b/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs
new file mode 100644
index 0000000000..62780e23c5
--- /dev/null
+++ b/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Jellyfin.Api.Models.UserDtos
+{
+ /// <summary>
+ /// Forgot Password Pin enter request body DTO.
+ /// </summary>
+ public class ForgotPasswordPinDto
+ {
+ /// <summary>
+ /// Gets or sets the entered pin to have the password reset.
+ /// </summary>
+ [Required]
+ public string? Pin { get; set; }
+ }
+}
diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj
index b95879de46..a8ac45645f 100644
--- a/Jellyfin.Data/Jellyfin.Data.csproj
+++ b/Jellyfin.Data/Jellyfin.Data.csproj
@@ -19,7 +19,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@@ -41,8 +41,8 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.2" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
index 05052e5c06..4f24da0ee4 100644
--- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
+++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
@@ -26,11 +26,11 @@
<ItemGroup>
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
- <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 77fb64674d..da4cc267b3 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -308,6 +308,9 @@ namespace Jellyfin.Server.Extensions
?? null;
});
+ // Allow parameters to properly be nullable.
+ c.UseAllOfToExtendReferenceSchemas();
+
// TODO - remove when all types are supported in System.Text.Json
c.AddSwaggerTypeMappings();
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 3ebcc3279d..bf4f806693 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -40,8 +40,8 @@
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
- <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
- <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.2" />
+ <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.3" />
+ <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="prometheus-net.AspNetCore" Version="4.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
index f4040748d7..07829c6969 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
@@ -90,7 +90,7 @@ namespace Jellyfin.Server.Migrations.Routines
var results = connection.Query("SELECT * FROM userdisplaypreferences");
foreach (var result in results)
{
- var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions);
+ var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToBlob(), _jsonOptions);
if (dto == null)
{
continue;
diff --git a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
index 459bec1105..6f0ea9bd58 100644
--- a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
+++ b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
@@ -33,8 +33,7 @@ namespace MediaBrowser.Common.Extensions
int n = list.Count;
while (n > 1)
{
- n--;
- int k = rng.Next(n + 1);
+ int k = rng.Next(n--);
T value = list[k];
list[k] = list[n];
list[n] = value;
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 320e60dc66..e469436a93 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index c3b6af76ea..65fd1654c3 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -123,7 +123,7 @@ namespace MediaBrowser.Controller.Entities
{
LibraryOptions[path] = options;
- var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.Serialize(options, _jsonOptions), _jsonOptions);
+ var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
foreach (var mediaPath in clone.PathInfos)
{
if (!string.IsNullOrEmpty(mediaPath.Path))
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5f75df54eb..6b1c096acb 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
diff --git a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs
deleted file mode 100644
index 93eab42cc7..0000000000
--- a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.IO;
-using MediaBrowser.Common.Plugins;
-
-namespace MediaBrowser.Controller.Plugins
-{
- /// <summary>
- /// Interface IConfigurationPage.
- /// </summary>
- public interface IPluginConfigurationPage
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; }
-
- /// <summary>
- /// Gets the type of the configuration page.
- /// </summary>
- /// <value>The type of the configuration page.</value>
- ConfigurationPageType ConfigurationPageType { get; }
-
- /// <summary>
- /// Gets the plugin.
- /// </summary>
- /// <value>The plugin.</value>
- IPlugin Plugin { get; }
-
- /// <summary>
- /// Gets the HTML stream.
- /// </summary>
- /// <returns>Stream.</returns>
- Stream GetHtmlStream();
- }
-
- /// <summary>
- /// Enum ConfigurationPageType.
- /// </summary>
- public enum ConfigurationPageType
- {
- /// <summary>
- /// The plugin configuration.
- /// </summary>
- PluginConfiguration,
-
- /// <summary>
- /// The none.
- /// </summary>
- None
- }
-}
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets
deleted file mode 100644
index f793e09bcb..0000000000
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
-<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Target Name="EmitMSBuildWarning" BeforeTargets="Build">
- <Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
- </Target>
-</Project> \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
index e0b7914fbe..bb48bed270 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
+ subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w0-9]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
trackEvents.Add(subEvent);
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
index 4a87f87dc1..ccef7eeeae 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
@@ -79,7 +79,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = string.Join(ParserValues.NewLine, multiline);
subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
+ subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\[0-9]?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase);
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index e5166672f9..c534286510 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index 6ca462474a..4c1f697632 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -54,7 +54,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
result.HasMetadata = true;
result.Item = new Season
{
- Name = info.Name,
IndexNumber = seasonNumber,
Overview = seasonResult?.Overview
};
diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs
index 981b7b9d2f..d02aea5566 100644
--- a/MediaBrowser.XbmcMetadata/EntryPoint.cs
+++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs
@@ -60,17 +60,7 @@ namespace MediaBrowser.XbmcMetadata
private void SaveMetadataForItem(BaseItem item, ItemUpdateType updateReason)
{
- if (!item.IsFileProtocol)
- {
- return;
- }
-
- if (!item.SupportsLocalMetadata)
- {
- return;
- }
-
- if (!item.IsSaveLocalMetadataEnabled())
+ if (!item.IsFileProtocol || !item.SupportsLocalMetadata)
{
return;
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index f2d0bdc545..67700f5fbe 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -721,20 +721,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
- case "musicBrainzArtistID":
- {
- if (reader.IsEmptyElement)
- {
- reader.Read();
- break;
- }
-
- var id = reader.ReadElementContentAsString();
- item.SetProviderId(MetadataProvider.MusicBrainzArtist.ToString(), id);
-
- break;
- }
-
default:
string readerName = reader.Name;
if (_validProviderIds.TryGetValue(readerName, out string? providerIdValue))
@@ -1030,6 +1016,29 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
+ case "type":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ type = val switch
+ {
+ PersonType.Composer => PersonType.Composer,
+ PersonType.Conductor => PersonType.Conductor,
+ PersonType.Director => PersonType.Director,
+ PersonType.Lyricist => PersonType.Lyricist,
+ PersonType.Producer => PersonType.Producer,
+ PersonType.Writer => PersonType.Writer,
+ PersonType.GuestStar => PersonType.GuestStar,
+ // unknown type --> actor
+ _ => PersonType.Actor
+ };
+ }
+
+ break;
+ }
+
case "order":
case "sortorder":
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index e1be79a060..9f22e618ef 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -203,10 +203,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path));
Directory.CreateDirectory(directory);
- // On Windows, savint the file will fail if the file is hidden or readonly
+ // On Windows, saving the file will fail if the file is hidden or readonly
FileSystem.SetAttributes(path, false, false);
- using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+ // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 .
+ using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
{
stream.CopyTo(filestream);
}
diff --git a/MediaBrowser.sln.GhostDoc.xml b/MediaBrowser.sln.GhostDoc.xml
deleted file mode 100644
index eafee0bf55..0000000000
--- a/MediaBrowser.sln.GhostDoc.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<GhostDoc>
- <SpellChecker>
- <IncludeExtensions>
- </IncludeExtensions>
- <IgnoreExtensions>
- </IgnoreExtensions>
- <IgnoreFiles>
- </IgnoreFiles>
- </SpellChecker>
- <HelpConfigurations selected="HelpFile">
- <HelpConfiguration name="HelpFile">
- <OutputPath>D:\Development\MediaBrowser\Help</OutputPath>
- <ImageFolderPath />
- <HtmlFormats>
- <HtmlHelp>true</HtmlHelp>
- <MSHelpViewer>false</MSHelpViewer>
- <MSHelp2>false</MSHelp2>
- <Website>false</Website>
- </HtmlFormats>
- <IncludeScopes>
- <Public>true</Public>
- <Internal>false</Internal>
- <Protected>false</Protected>
- <Private>false</Private>
- <Inherited>true</Inherited>
- <EnableTags>false</EnableTags>
- <TagList />
- </IncludeScopes>
- <ResolveCrefLinks>true</ResolveCrefLinks>
- <HeaderText />
- <FooterText />
- <SelectedProjects />
- </HelpConfiguration>
- </HelpConfigurations>
-</GhostDoc>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index d17074fc0d..5e2f151a22 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("10.7.0")]
-[assembly: AssemblyFileVersion("10.7.0")]
+[assembly: AssemblyVersion("10.8.0")]
+[assembly: AssemblyFileVersion("10.8.0")]
diff --git a/build.yaml b/build.yaml
index 7c32d955c1..18434ee003 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1,7 +1,7 @@
---
# We just wrap `build` so this is really it
name: "jellyfin"
-version: "10.7.0"
+version: "10.8.0"
packages:
- debian.amd64
- debian.arm64
diff --git a/debian/changelog b/debian/changelog
index 184143fe9a..430594cac2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+jellyfin-server (10.8.0-1) unstable; urgency=medium
+
+ * Forthcoming stable release
+
+ -- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 04 Dec 2020 21:55:12 -0500
+
jellyfin-server (10.7.0-1) unstable; urgency=medium
* Forthcoming stable release
diff --git a/debian/metapackage/jellyfin b/debian/metapackage/jellyfin
index 026fcb8217..a9a0ae5b01 100644
--- a/debian/metapackage/jellyfin
+++ b/debian/metapackage/jellyfin
@@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
Standards-Version: 3.9.2
Package: jellyfin
-Version: 10.7.0
+Version: 10.8.0
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
Depends: jellyfin-server, jellyfin-web
Description: Provides the Jellyfin Free Software Media System
diff --git a/deployment/Dockerfile.debian.amd64 b/deployment/Dockerfile.debian.amd64
index f5cf232d65..4280726135 100644
--- a/deployment/Dockerfile.debian.amd64
+++ b/deployment/Dockerfile.debian.amd64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.debian.arm64 b/deployment/Dockerfile.debian.arm64
index d9414a6104..b540efc09a 100644
--- a/deployment/Dockerfile.debian.arm64
+++ b/deployment/Dockerfile.debian.arm64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.debian.armhf b/deployment/Dockerfile.debian.armhf
index 7f2275aaa3..426ce02fcd 100644
--- a/deployment/Dockerfile.debian.armhf
+++ b/deployment/Dockerfile.debian.armhf
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.linux.amd64 b/deployment/Dockerfile.linux.amd64
index 54d75dcbe9..3b91515f36 100644
--- a/deployment/Dockerfile.linux.amd64
+++ b/deployment/Dockerfile.linux.amd64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.linux.amd64-musl b/deployment/Dockerfile.linux.amd64-musl
index e4c7242191..2ca9072bae 100644
--- a/deployment/Dockerfile.linux.amd64-musl
+++ b/deployment/Dockerfile.linux.amd64-musl
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.linux.arm64 b/deployment/Dockerfile.linux.arm64
index 6338025981..03efd306d7 100644
--- a/deployment/Dockerfile.linux.arm64
+++ b/deployment/Dockerfile.linux.arm64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.linux.armhf b/deployment/Dockerfile.linux.armhf
index ec0b015cc8..585572204b 100644
--- a/deployment/Dockerfile.linux.armhf
+++ b/deployment/Dockerfile.linux.armhf
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.macos b/deployment/Dockerfile.macos
index 25f15be183..b37afdcfbc 100644
--- a/deployment/Dockerfile.macos
+++ b/deployment/Dockerfile.macos
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.portable b/deployment/Dockerfile.portable
index cd71ce9d49..686b20197c 100644
--- a/deployment/Dockerfile.portable
+++ b/deployment/Dockerfile.portable
@@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.ubuntu.amd64 b/deployment/Dockerfile.ubuntu.amd64
index ea539b3609..3513bf8ecb 100644
--- a/deployment/Dockerfile.ubuntu.amd64
+++ b/deployment/Dockerfile.ubuntu.amd64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.ubuntu.arm64 b/deployment/Dockerfile.ubuntu.arm64
index f2f5368f7a..5acdf0d178 100644
--- a/deployment/Dockerfile.ubuntu.arm64
+++ b/deployment/Dockerfile.ubuntu.arm64
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.ubuntu.armhf b/deployment/Dockerfile.ubuntu.armhf
index ba597801b5..42f757d058 100644
--- a/deployment/Dockerfile.ubuntu.armhf
+++ b/deployment/Dockerfile.ubuntu.armhf
@@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/deployment/Dockerfile.windows.amd64 b/deployment/Dockerfile.windows.amd64
index c731268416..6ed1193fb0 100644
--- a/deployment/Dockerfile.windows.amd64
+++ b/deployment/Dockerfile.windows.amd64
@@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
-RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec
index 71583c24ef..928fe590f0 100644
--- a/fedora/jellyfin.spec
+++ b/fedora/jellyfin.spec
@@ -7,7 +7,7 @@
%endif
Name: jellyfin
-Version: 10.7.0
+Version: 10.8.0
Release: 1%{?dist}
Summary: The Free Software Media System
License: GPLv3
@@ -137,6 +137,8 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
+* Fri Dec 04 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
+- Forthcoming stable release
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
diff --git a/hooks/pre_build b/hooks/pre_build
deleted file mode 100644
index 2fd6136c53..0000000000
--- a/hooks/pre_build
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-git submodule update --init --recursive
-
-# Register qemu-*-static for all supported processors except the
-# current one, but also remove all registered binfmt_misc before
-docker run --rm --privileged multiarch/qemu-user-static:register --reset
diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
new file mode 100644
index 0000000000..606041c7f4
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using Jellyfin.Api.Helpers;
+using Jellyfin.Data.Enums;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Helpers
+{
+ public class RequestHelpersTests
+ {
+ [Theory]
+ [MemberData(nameof(GetOrderBy_Success_TestData))]
+ public void GetOrderBy_Success(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder, (string, SortOrder)[] expected)
+ {
+ Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder));
+ }
+
+ public static IEnumerable<object[]> GetOrderBy_Success_TestData()
+ {
+ yield return new object[]
+ {
+ Array.Empty<string>(),
+ Array.Empty<SortOrder>(),
+ Array.Empty<(string, SortOrder)>()
+ };
+ yield return new object[]
+ {
+ new string[]
+ {
+ "IsFavoriteOrLiked",
+ "Random"
+ },
+ Array.Empty<SortOrder>(),
+ new (string, SortOrder)[]
+ {
+ ("IsFavoriteOrLiked", SortOrder.Ascending),
+ ("Random", SortOrder.Ascending),
+ }
+ };
+ yield return new object[]
+ {
+ new string[]
+ {
+ "SortName",
+ "ProductionYear"
+ },
+ new SortOrder[]
+ {
+ SortOrder.Descending
+ },
+ new (string, SortOrder)[]
+ {
+ ("SortName", SortOrder.Descending),
+ ("ProductionYear", SortOrder.Descending),
+ }
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 98a2cda607..eca3df79b3 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -16,12 +16,12 @@
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" />
- <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.2" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
<PackageReference Include="Moq" Version="4.16.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs b/tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs
new file mode 100644
index 0000000000..cbdbcf112c
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs
@@ -0,0 +1,22 @@
+using System;
+using MediaBrowser.Common.Extensions;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Extensions
+{
+ public static class ShuffleExtensionsTests
+ {
+ private static readonly Random _rng = new Random();
+
+ [Fact]
+ public static void Shuffle_Valid_Correct()
+ {
+ byte[] original = new byte[1 << 6];
+ _rng.NextBytes(original);
+ byte[] shuffled = (byte[])original.Clone();
+ shuffled.Shuffle();
+
+ Assert.NotEqual(original, shuffled);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 7ff4d0e87c..57edbf902c 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index af412eed3b..c766c54458 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
index 21389b926d..52a9e11932 100644
--- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
+++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
@@ -11,7 +11,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index 9a1cfcfa41..24f6fb3561 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -22,7 +22,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index 31e41b12f9..a4d5c0d6fd 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
index 5e023bdb06..921c2b1f57 100644
--- a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
@@ -66,12 +66,16 @@ namespace Jellyfin.Naming.Tests.TV
[InlineData("Season 2/2. Infestation.avi", 2)]
[InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH/The Wonder Years s04e07 Christmas Party NTSC PDTV.avi", 7)]
[InlineData("Running Man/Running Man S2017E368.mkv", 368)]
+ [InlineData("Season 2/[HorribleSubs] Hunter X Hunter - 136 [720p].mkv", 136)] // triple digit episode number
+ [InlineData("Log Horizon 2/[HorribleSubs] Log Horizon 2 - 03 [720p].mkv", 3)] // digit in series name
+ [InlineData("Season 1/seriesname 05.mkv", 5)] // no hyphen between series name and episode number
+ [InlineData("[BBT-RMX] Ranma ½ - 154 [50AC421A].mkv", 154)] // hyphens in the pre-name info, triple digit episode number
+ // TODO: [InlineData("Case Closed (1996-2007)/Case Closed - 317.mkv", 317)] // triple digit episode number
// TODO: [InlineData("Season 2/16 12 Some Title.avi", 16)]
// TODO: [InlineData("/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv/The.Legend.of.Condor.Heroes.2017.E07.V2.web-dl.1080p.h264.aac-hdctv.mkv", 7)]
// TODO: [InlineData("Season 4/Uchuu.Senkan.Yamato.2199.E03.avi", 3)]
// TODO: [InlineData("Season 2/7 12 Angry Men.avi", 7)]
// TODO: [InlineData("Season 02/02x03x04x15 - Ep Name.mp4", 2)]
- // TODO: [InlineData("Season 2/[HorribleSubs] Hunter X Hunter - 136 [720p].mkv", 136)]
public void GetEpisodeNumberFromFileTest(string path, int? expected)
{
var result = new EpisodePathParser(_namingOptions)
diff --git a/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
index bb2bae8e8f..d77645cd9e 100644
--- a/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
+++ b/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
<PackageReference Include="Moq" Version="4.16.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs
new file mode 100644
index 0000000000..1ce2096ea6
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Buffers;
+using System.IO;
+using System.Text.Json;
+using Emby.Server.Implementations.HttpServer;
+using Microsoft.Extensions.Logging.Abstractions;
+using Xunit;
+
+namespace Jellyfin.Server.Implementations.Tests.HttpServer
+{
+ public class WebSocketConnectionTests
+ {
+ [Fact]
+ public void DeserializeWebSocketMessage_SingleSegment_Success()
+ {
+ var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
+ var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json");
+ con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed);
+ Assert.Equal(109, bytesConsumed);
+ }
+
+ [Fact]
+ public void DeserializeWebSocketMessage_MultipleSegments_Success()
+ {
+ const int SplitPos = 64;
+ var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
+ var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json");
+ var seg1 = new BufferSegment(new Memory<byte>(bytes, 0, SplitPos));
+ var seg2 = seg1.Append(new Memory<byte>(bytes, SplitPos, bytes.Length - SplitPos));
+ con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(seg1, 0, seg2, seg2.Memory.Length - 1), out var bytesConsumed);
+ Assert.Equal(109, bytesConsumed);
+ }
+
+ [Fact]
+ public void DeserializeWebSocketMessage_ValidPartial_Success()
+ {
+ var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
+ var bytes = File.ReadAllBytes("Test Data/HttpServer/ValidPartial.json");
+ con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed);
+ Assert.Equal(109, bytesConsumed);
+ }
+
+ [Fact]
+ public void DeserializeWebSocketMessage_Partial_ThrowJsonException()
+ {
+ var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!);
+ var bytes = File.ReadAllBytes("Test Data/HttpServer/Partial.json");
+ Assert.Throws<JsonException>(() => con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed));
+ }
+
+ internal class BufferSegment : ReadOnlySequenceSegment<byte>
+ {
+ public BufferSegment(Memory<byte> memory)
+ {
+ Memory = memory;
+ }
+
+ public BufferSegment Append(Memory<byte> memory)
+ {
+ var segment = new BufferSegment(memory)
+ {
+ RunningIndex = RunningIndex + Memory.Length
+ };
+ Next = segment;
+ return segment;
+ }
+ }
+ }
+}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index 7f909847ec..174f29b09a 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -14,13 +14,19 @@
</PropertyGroup>
<ItemGroup>
+ <None Include="Test Data\**\*.*">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ </ItemGroup>
+
+ <ItemGroup>
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Moq" Version="4.16.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
@@ -35,11 +41,6 @@
<ProjectReference Include="..\..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" />
</ItemGroup>
- <ItemGroup>
- <EmbeddedResource Include="LiveTv\discover.json" />
- <EmbeddedResource Include="LiveTv\lineup.json" />
- </ItemGroup>
-
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunHostTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunHostTests.cs
index 75939526dc..8847239d90 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunHostTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunHostTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -21,24 +22,15 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
public HdHomerunHostTests()
{
- const string BaseResourcePath = "Jellyfin.Server.Implementations.Tests.LiveTv.";
-
var messageHandler = new Mock<HttpMessageHandler>();
messageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(
(m, _) =>
{
- var resource = BaseResourcePath + m.RequestUri?.Segments[^1];
- var stream = typeof(HdHomerunHostTests).Assembly.GetManifestResourceStream(resource);
- if (stream == null)
- {
- throw new NullReferenceException("Resource doesn't exist: " + resource);
- }
-
return Task.FromResult(new HttpResponseMessage()
{
- Content = new StreamContent(stream)
+ Content = new StreamContent(File.OpenRead("Test Data/LiveTv/" + m.RequestUri?.Segments[^1]))
});
});
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs
new file mode 100644
index 0000000000..bc6a447410
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs
@@ -0,0 +1,45 @@
+using System;
+using System.IO;
+using Emby.Server.Implementations.Plugins;
+using MediaBrowser.Common.Plugins;
+using Microsoft.Extensions.Logging.Abstractions;
+using Xunit;
+
+namespace Jellyfin.Server.Implementations.Tests.Plugins
+{
+ public class PluginManagerTests
+ {
+ private static readonly string _testPathRoot = Path.Combine(Path.GetTempPath(), "jellyfin-test-data");
+
+ [Fact]
+ public void SaveManifest_RoundTrip_Success()
+ {
+ var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, null!, new Version(1, 0));
+ var manifest = new PluginManifest()
+ {
+ Version = "1.0"
+ };
+
+ var tempPath = Path.Combine(_testPathRoot, "manifest-" + Path.GetRandomFileName());
+ Directory.CreateDirectory(tempPath);
+
+ Assert.True(pluginManager.SaveManifest(manifest, tempPath));
+
+ var res = pluginManager.LoadManifest(tempPath);
+
+ Assert.Equal(manifest.Category, res.Manifest.Category);
+ Assert.Equal(manifest.Changelog, res.Manifest.Changelog);
+ Assert.Equal(manifest.Description, res.Manifest.Description);
+ Assert.Equal(manifest.Id, res.Manifest.Id);
+ Assert.Equal(manifest.Name, res.Manifest.Name);
+ Assert.Equal(manifest.Overview, res.Manifest.Overview);
+ Assert.Equal(manifest.Owner, res.Manifest.Owner);
+ Assert.Equal(manifest.TargetAbi, res.Manifest.TargetAbi);
+ Assert.Equal(manifest.Timestamp, res.Manifest.Timestamp);
+ Assert.Equal(manifest.Version, res.Manifest.Version);
+ Assert.Equal(manifest.Status, res.Manifest.Status);
+ Assert.Equal(manifest.AutoUpdate, res.Manifest.AutoUpdate);
+ Assert.Equal(manifest.ImagePath, res.Manifest.ImagePath);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ForceKeepAlive.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ForceKeepAlive.json
new file mode 100644
index 0000000000..0472a3cd0c
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ForceKeepAlive.json
@@ -0,0 +1 @@
+{"MessageType":"ForceKeepAlive","MessageId":"00000000-0000-0000-0000-000000000000","ServerId":null,"Data":60}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/Partial.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/Partial.json
new file mode 100644
index 0000000000..72f810725a
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/Partial.json
@@ -0,0 +1 @@
+{"MessageType":"KeepAlive","MessageId":"d29ef449-6965-4000
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ValidPartial.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ValidPartial.json
new file mode 100644
index 0000000000..62d9099c8b
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/HttpServer/ValidPartial.json
@@ -0,0 +1 @@
+{"MessageType":"ForceKeepAlive","MessageId":"00000000-0000-0000-0000-000000000000","ServerId":null,"Data":60}{"MessageType":"KeepAlive","MessageId":"d29ef449-6965-4000
diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/discover.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/discover.json
index 851f17bb26..851f17bb26 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/discover.json
+++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/discover.json
diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/lineup.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/lineup.json
index 4cb5ebc8ec..4cb5ebc8ec 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/lineup.json
+++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/LiveTv/lineup.json
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
index fe40122a35..aed3e8ac5d 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
@@ -18,7 +18,7 @@
<PackageReference Include="Moq" Version="4.16.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="3.0.1" />
+ <PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<!-- Code Analyzers -->
@@ -31,6 +31,7 @@
<ItemGroup>
<ProjectReference Include="../../MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj" />
+ <ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
index 67b4b969a3..d0cd8b2878 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.Movies;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@@ -23,8 +24,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public EpisodeNfoProviderTests()
{
var providerManager = new Mock<IProviderManager>();
+
+ var imdbExternalId = new ImdbExternalId();
+ var externalIdInfo = new ExternalIdInfo(imdbExternalId.ProviderName, imdbExternalId.Key, imdbExternalId.Type, imdbExternalId.UrlFormatString);
+
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
- .Returns(Enumerable.Empty<ExternalIdInfo>());
+ .Returns(new[] { externalIdInfo });
+
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());
@@ -56,6 +62,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal(2017, item.ProductionYear);
Assert.Single(item.Studios);
Assert.Contains("Starz", item.Studios);
+ Assert.Equal("tt5017734", item.ProviderIds[MetadataProvider.Imdb.ToString()]);
+ Assert.Equal("1276153", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
// Credits
var writers = result.People.Where(x => x.Type == PersonType.Writer).ToArray();
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
index e1f50876fb..2f7ee65d51 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.Plugins.Tmdb.Movies;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@@ -21,8 +22,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public MovieNfoParserTests()
{
var providerManager = new Mock<IProviderManager>();
+
+ var tmdbExternalId = new TmdbMovieExternalId();
+ var externalIdInfo = new ExternalIdInfo(tmdbExternalId.ProviderName, tmdbExternalId.Key, tmdbExternalId.Type, tmdbExternalId.UrlFormatString);
+
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
- .Returns(Enumerable.Empty<ExternalIdInfo>());
+ .Returns(new[] { externalIdInfo });
+
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());
@@ -42,7 +48,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal("Justice League", item.OriginalTitle);
Assert.Equal("Justice for all.", item.Tagline);
- Assert.Equal("tt0974015", item.ProviderIds["imdb"]);
+ Assert.Equal("tt0974015", item.ProviderIds[MetadataProvider.Imdb.ToString()]);
+ Assert.Equal("141052", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
Assert.Equal(4, item.Genres.Length);
Assert.Contains("Action", item.Genres);
@@ -60,7 +67,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal(new TimeSpan(0, 0, 6268).Ticks, item.RunTimeTicks);
Assert.True(item.HasSubtitles);
- Assert.Equal(18, result.People.Count);
+ Assert.Equal(19, result.People.Count);
var writers = result.People.Where(x => x.Type == PersonType.Writer).ToArray();
Assert.Equal(2, writers.Length);
@@ -82,6 +89,10 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal(5, aquaman!.SortOrder);
Assert.Equal("https://m.media-amazon.com/images/M/MV5BMTI5MTU5NjM1MV5BMl5BanBnXkFtZTcwODc4MDk0Mw@@._V1_SX1024_SY1024_.jpg", aquaman!.ImageUrl);
+ var lyricist = result.People.FirstOrDefault(x => x.Type == PersonType.Lyricist);
+ Assert.NotNull(lyricist);
+ Assert.Equal("Test Lyricist", lyricist!.Name);
+
Assert.Equal(new DateTime(2019, 8, 6, 9, 1, 18), item.DateCreated);
}
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs
index bdffea560c..1fe56caddb 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs
@@ -9,6 +9,8 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.Music;
+using MediaBrowser.Providers.Plugins.MusicBrainz;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@@ -23,8 +25,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public MusicAlbumNfoProviderTests()
{
var providerManager = new Mock<IProviderManager>();
+
+ var musicBrainzArtist = new MusicBrainzArtistExternalId();
+ var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
+
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
- .Returns(Enumerable.Empty<ExternalIdInfo>());
+ .Returns(new[] { externalIdInfo });
+
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs
index 2a4d376c6b..4869cf088a 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.Music;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
@@ -21,8 +22,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public MusicArtistNfoParserTests()
{
var providerManager = new Mock<IProviderManager>();
+
+ var musicBrainzArtist = new MusicBrainzArtistExternalId();
+ var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
+
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
- .Returns(Enumerable.Empty<ExternalIdInfo>());
+ .Returns(new[] { externalIdInfo });
+
var config = new Mock<IConfigurationManager>();
config.Setup(x => x.GetConfiguration(It.IsAny<string>()))
.Returns(new XbmcMetadataOptions());
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs
index 3bbfb66e3e..9e535182e2 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs
@@ -43,8 +43,8 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal("American Gods", item.OriginalTitle);
Assert.Equal(string.Empty, item.Tagline);
Assert.Equal(0, item.RunTimeTicks);
- Assert.Equal("46639", item.ProviderIds["tmdb"]);
- Assert.Equal("253573", item.ProviderIds["tvdb"]);
+ Assert.Equal("46639", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
+ Assert.Equal("253573", item.ProviderIds[MetadataProvider.Tvdb.ToString()]);
Assert.Equal(3, item.Genres.Length);
Assert.Contains("Drama", item.Genres);
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
index f838af8d04..18b44d9448 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
@@ -30,6 +30,7 @@
<plot>Fueled by his restored faith in humanity and inspired by Superman&apos;s selfless act, Bruce Wayne enlists the help of his newfound ally, Diana Prince, to face an even greater enemy. Together, Batman and Wonder Woman work quickly to find and recruit a team of meta-humans to stand against this newly awakened threat. But despite the formation of this unprecedented league of heroes-Batman, Wonder Woman, Aquaman, Cyborg and The Flash-it may already be too late to save the planet from an assault of catastrophic proportions.</plot>
<tagline>Justice for all.</tagline>
<runtime>120</runtime>
+ <tmdbId>141052</tmdbId>
<thumb aspect="set.poster" preview="https://assets.fanart.tv/preview/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg">https://assets.fanart.tv/fanart/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg</thumb>
<thumb aspect="set.poster" preview="https://assets.fanart.tv/preview/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg">https://assets.fanart.tv/fanart/movies/468551/movieposter/justice-league-collection-5c24ea65591d3.jpg</thumb>
<thumb aspect="set.clearlogo" preview="https://assets.fanart.tv/preview/movies/468551/hdmovielogo/justice-league-collection-5ba855ed4239a.png">https://assets.fanart.tv/fanart/movies/468551/hdmovielogo/justice-league-collection-5ba855ed4239a.png</thumb>
@@ -221,6 +222,11 @@
<order>14</order>
<thumb>https://m.media-amazon.com/images/M/MV5BOTFjOTFhNTgtZjk3Ny00MTNjLWE3MWUtMWI3ZWM5NDljZjQwXkEyXkFqcGdeQXVyMjQwMDg0Ng@@._V1_SX1024_SY1024_.jpg</thumb>
</actor>
+ <actor>
+ <name>Test Lyricist</name>
+ <type>Lyricist</type>
+ <order>15</order>
+ </actor>
<resume>
<position>0.000000</position>
<total>0.000000</total>
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo
index e77c02a349..14feffcbaf 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo
@@ -24,6 +24,7 @@
<lastplayed></lastplayed>
<id>1276153</id>
<uniqueid type="tmdb" default="true">1276153</uniqueid>
+ <imdbId>tt5017734</imdbId>
<genre>Drama</genre>
<genre>Mystery</genre>
<genre>Sci-Fi &amp; Fantasy</genre>