aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci-codeql-analysis.yml6
-rw-r--r--Directory.Packages.props36
-rw-r--r--Emby.Naming/Video/VideoInfo.cs8
-rw-r--r--Emby.Naming/Video/VideoListResolver.cs188
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs16
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs17
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketManager.cs9
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs58
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs25
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/AudioSimilarItemsProvider.cs55
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/LiveTvProgramSimilarItemsProvider.cs94
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/MovieSimilarItemsProvider.cs91
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/MusicAlbumSimilarItemsProvider.cs55
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/MusicArtistSimilarItemsProvider.cs55
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/SeriesSimilarItemsProvider.cs54
-rw-r--r--Emby.Server.Implementations/Library/SimilarItems/SimilarItemsManager.cs406
-rw-r--r--Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ab.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/af.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/as.json11
-rw-r--r--Emby.Server.Implementations/Localization/Core/be.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/bg-BG.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/bn.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/bs.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ca.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/chr.json14
-rw-r--r--Emby.Server.Implementations/Localization/Core/cs.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/cy.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/de.json32
-rw-r--r--Emby.Server.Implementations/Localization/Core/el.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-GB.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-US.json30
-rw-r--r--Emby.Server.Implementations/Localization/Core/eo.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-AR.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/es.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/es_419.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/es_DO.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/et.json32
-rw-r--r--Emby.Server.Implementations/Localization/Core/eu.json33
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/fil.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/fo.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json33
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json33
-rw-r--r--Emby.Server.Implementations/Localization/Core/ga.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/gl.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/gsw.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/he.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/he_IL.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/hi.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ht.json20
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/hy.json13
-rw-r--r--Emby.Server.Implementations/Localization/Core/id.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/is.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/it.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ja.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/jbo.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/ka.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/kab.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/kk.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/km.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/kn.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ko.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/kw.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/lb.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/lt-LT.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/lv.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/lzh.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/mi.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/mk.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ml.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/mn.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/mr.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/mt.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/my.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/nb.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ne.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json34
-rw-r--r--Emby.Server.Implementations/Localization/Core/nn.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/or.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/pa.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/pl.json32
-rw-r--r--Emby.Server.Implementations/Localization/Core/pr.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-BR.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-PT.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ro.json33
-rw-r--r--Emby.Server.Implementations/Localization/Core/ru.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/sk.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/sn.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/sq.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/sr.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/ta.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/te.json20
-rw-r--r--Emby.Server.Implementations/Localization/Core/th.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/tr.json33
-rw-r--r--Emby.Server.Implementations/Localization/Core/ug.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/uk.json32
-rw-r--r--Emby.Server.Implementations/Localization/Core/ur.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/ur_PK.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/uz.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/vi.json32
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-CN.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-TW.json29
-rw-r--r--Emby.Server.Implementations/Localization/Core/zu.json15
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs233
-rw-r--r--Jellyfin.Api/Controllers/FilterController.cs37
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs35
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs82
-rw-r--r--Jellyfin.Api/Controllers/TrailersController.cs6
-rw-r--r--Jellyfin.Api/Models/LibraryDtos/LibraryTypeOptionsDto.cs14
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs4
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs2
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs37
-rw-r--r--Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs11
-rw-r--r--Jellyfin.Server/Startup.cs24
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs8
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs7
-rw-r--r--MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs63
-rw-r--r--MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs62
-rw-r--r--MediaBrowser.Controller/Library/ISimilarItemsManager.cs50
-rw-r--r--MediaBrowser.Controller/Library/ISimilarItemsProvider.cs26
-rw-r--r--MediaBrowser.Controller/Library/SimilarItemReference.cs22
-rw-r--r--MediaBrowser.Controller/Library/SimilarItemsQuery.cs37
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs5
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketConnection.cs9
-rw-r--r--MediaBrowser.Controller/Persistence/IMediaStreamRepository.cs7
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs11
-rw-r--r--MediaBrowser.Model/Channels/ChannelFeatures.cs13
-rw-r--r--MediaBrowser.Model/Configuration/MetadataPluginType.cs4
-rw-r--r--MediaBrowser.Model/Configuration/TypeOptions.cs16
-rw-r--r--MediaBrowser.Model/Globalization/ILocalizationManager.cs9
-rw-r--r--MediaBrowser.Model/Querying/QueryFilters.cs11
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs17
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj6
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs128
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs16
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg60
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md23
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs65
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs37
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs23
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html109
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs64
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs89
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html15
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs96
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs96
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs48
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs4
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs5
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs23
-rw-r--r--src/Jellyfin.LiveTv/Channels/RefreshChannelsScheduledTask.cs4
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs843
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs106
-rw-r--r--tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs3
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs59
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs93
185 files changed, 3729 insertions, 2966 deletions
diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml
index 7b1d8b4132..b14e5958ab 100644
--- a/.github/workflows/ci-codeql-analysis.yml
+++ b/.github/workflows/ci-codeql-analysis.yml
@@ -32,13 +32,13 @@ jobs:
dotnet-version: '10.0.x'
- name: Initialize CodeQL
- uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
+ uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
- uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
+ uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
+ uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
diff --git a/Directory.Packages.props b/Directory.Packages.props
index e8901b4a1d..e722bed973 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -26,27 +26,27 @@
<PackageVersion Include="libse" Version="4.0.12" />
<PackageVersion Include="LrcParser" Version="2025.623.0" />
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="8.0.1" />
- <PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="10.0.7" />
- <PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.7" />
+ <PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="5.3.0" />
- <PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.7" />
- <PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7" />
- <PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
- <PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
- <PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
- <PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
+ <PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.8" />
+ <PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.8" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="MimeTypes" Version="2.5.2" />
<PackageVersion Include="Morestachio" Version="5.0.1.670" />
@@ -77,7 +77,7 @@
<PackageVersion Include="Svg.Skia" Version="3.4.1" />
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="10.1.7" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.1.7" />
- <PackageVersion Include="System.Text.Json" Version="10.0.7" />
+ <PackageVersion Include="System.Text.Json" Version="10.0.8" />
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
<PackageVersion Include="z440.atl.core" Version="7.13.0" />
<PackageVersion Include="TMDbLib" Version="3.0.0" />
diff --git a/Emby.Naming/Video/VideoInfo.cs b/Emby.Naming/Video/VideoInfo.cs
index 8847ee9bc9..028b639122 100644
--- a/Emby.Naming/Video/VideoInfo.cs
+++ b/Emby.Naming/Video/VideoInfo.cs
@@ -17,8 +17,8 @@ namespace Emby.Naming.Video
{
Name = name;
- Files = Array.Empty<VideoFileInfo>();
- AlternateVersions = Array.Empty<VideoFileInfo>();
+ Files = [];
+ AlternateVersions = [];
}
/// <summary>
@@ -40,10 +40,10 @@ namespace Emby.Naming.Video
public IReadOnlyList<VideoFileInfo> Files { get; set; }
/// <summary>
- /// Gets or sets the alternate versions.
+ /// Gets or sets the alternate versions. Each alternate may itself span multiple files.
/// </summary>
/// <value>The alternate versions.</value>
- public IReadOnlyList<VideoFileInfo> AlternateVersions { get; set; }
+ public IReadOnlyList<VideoInfo> AlternateVersions { get; set; }
/// <summary>
/// Gets or sets the extra type.
diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs
index a4bfb8d4a1..29330b132d 100644
--- a/Emby.Naming/Video/VideoListResolver.cs
+++ b/Emby.Naming/Video/VideoListResolver.cs
@@ -5,7 +5,8 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Emby.Naming.Common;
-using Jellyfin.Extensions;
+using Emby.Naming.TV;
+using Jellyfin.Data.Enums;
using MediaBrowser.Model.IO;
namespace Emby.Naming.Video
@@ -13,8 +14,23 @@ namespace Emby.Naming.Video
/// <summary>
/// Resolves alternative versions and extras from list of video files.
/// </summary>
- public static partial class VideoListResolver
+ public partial class VideoListResolver
{
+ private static readonly StringComparer _numericOrdinalComparer = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.NumericOrdering);
+
+ private readonly NamingOptions _namingOptions;
+ private readonly EpisodePathParser _episodePathParser;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="VideoListResolver"/> class.
+ /// </summary>
+ /// <param name="namingOptions">The naming options.</param>
+ public VideoListResolver(NamingOptions namingOptions)
+ {
+ _namingOptions = namingOptions;
+ _episodePathParser = new EpisodePathParser(namingOptions);
+ }
+
[GeneratedRegex("[0-9]{2}[0-9]+[ip]", RegexOptions.IgnoreCase)]
private static partial Regex ResolutionRegex();
@@ -25,12 +41,12 @@ namespace Emby.Naming.Video
/// Resolves alternative versions and extras from list of video files.
/// </summary>
/// <param name="videoInfos">List of related video files.</param>
- /// <param name="namingOptions">The naming options.</param>
/// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param>
/// <param name="parseName">Whether to parse the name or use the filename.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
+ /// <param name="collectionType">The type of the containing collection, if known.</param>
/// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files together when related.</returns>
- public static IReadOnlyList<VideoInfo> Resolve(IReadOnlyList<VideoFileInfo> videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true, string? libraryRoot = "")
+ public IReadOnlyList<VideoInfo> Resolve(IReadOnlyList<VideoFileInfo> videoInfos, bool supportMultiVersion = true, bool parseName = true, string? libraryRoot = "", CollectionType? collectionType = null)
{
// Filter out all extras, otherwise they could cause stacks to not be resolved
// See the unit test TestStackedWithTrailer
@@ -38,7 +54,7 @@ namespace Emby.Naming.Video
.Where(i => i.ExtraType is null)
.Select(i => new FileSystemMetadata { FullName = i.Path, IsDirectory = i.IsDirectory });
- var stackResult = StackResolver.Resolve(nonExtras, namingOptions).ToList();
+ var stackResult = StackResolver.Resolve(nonExtras, _namingOptions).ToList();
var remainingFiles = new List<VideoFileInfo>();
var standaloneMedia = new List<VideoFileInfo>();
@@ -67,7 +83,7 @@ namespace Emby.Naming.Video
{
var info = new VideoInfo(stack.Name)
{
- Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName, libraryRoot))
+ Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, _namingOptions, parseName, libraryRoot))
.OfType<VideoFileInfo>()
.ToList()
};
@@ -86,7 +102,9 @@ namespace Emby.Naming.Video
if (supportMultiVersion)
{
- list = GetVideosGroupedByVersion(list, namingOptions);
+ list = collectionType is CollectionType.tvshows
+ ? GetEpisodesGroupedByVersion(list)
+ : GetVideosGroupedByVersion(list);
}
// Whatever files are left, just add them
@@ -100,7 +118,7 @@ namespace Emby.Naming.Video
return list;
}
- private static List<VideoInfo> GetVideosGroupedByVersion(List<VideoInfo> videos, NamingOptions namingOptions)
+ private List<VideoInfo> GetVideosGroupedByVersion(List<VideoInfo> videos)
{
if (videos.Count == 0)
{
@@ -124,7 +142,7 @@ namespace Emby.Naming.Video
continue;
}
- if (!IsEligibleForMultiVersion(folderName, video.Files[0].FileNameWithoutExtension, namingOptions))
+ if (!IsEligibleForMultiVersion(folderName, video.Files[0].FileNameWithoutExtension))
{
return videos;
}
@@ -135,45 +153,9 @@ namespace Emby.Naming.Video
}
}
- if (videos.Count > 1)
- {
- var groups = videos
- .Select(x => (filename: x.Files[0].FileNameWithoutExtension.ToString(), value: x))
- .Select(x => (x.filename, resolutionMatch: ResolutionRegex().Match(x.filename), x.value))
- .GroupBy(x => x.resolutionMatch.Success)
- .ToList();
-
- videos.Clear();
+ var organized = OrganizeAlternateVersions(videos, primary, folderName.ToString());
- StringComparer comparer = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.NumericOrdering);
- foreach (var group in groups)
- {
- if (group.Key)
- {
- videos.InsertRange(0, group
- .OrderByDescending(x => x.resolutionMatch.Value, comparer)
- .ThenBy(x => x.filename, comparer)
- .Select(x => x.value));
- }
- else
- {
- videos.AddRange(group.OrderBy(x => x.filename, comparer).Select(x => x.value));
- }
- }
- }
-
- primary ??= videos[0];
- videos.Remove(primary);
-
- var list = new List<VideoInfo>
- {
- primary
- };
-
- list[0].AlternateVersions = videos.Select(x => x.Files[0]).ToArray();
- list[0].Name = folderName.ToString();
-
- return list;
+ return [organized];
}
private static bool HaveSameYear(IReadOnlyList<VideoInfo> videos)
@@ -195,7 +177,7 @@ namespace Emby.Naming.Video
return true;
}
- private static bool IsEligibleForMultiVersion(ReadOnlySpan<char> folderName, ReadOnlySpan<char> testFilename, NamingOptions namingOptions)
+ private bool IsEligibleForMultiVersion(ReadOnlySpan<char> folderName, ReadOnlySpan<char> testFilename)
{
if (!testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
{
@@ -209,7 +191,7 @@ namespace Emby.Naming.Video
}
// There are no span overloads for regex unfortunately
- if (CleanStringParser.TryClean(testFilename.ToString(), namingOptions.CleanStringRegexes, out var cleanName))
+ if (CleanStringParser.TryClean(testFilename.ToString(), _namingOptions.CleanStringRegexes, out var cleanName))
{
testFilename = cleanName.AsSpan().Trim();
}
@@ -221,5 +203,113 @@ namespace Emby.Naming.Video
|| testFilename[0] == '.'
|| CheckMultiVersionRegex().IsMatch(testFilename);
}
+
+ private List<VideoInfo> GetEpisodesGroupedByVersion(List<VideoInfo> videos)
+ {
+ if (videos.Count < 2)
+ {
+ return videos;
+ }
+
+ var result = new List<VideoInfo>();
+ var groups = new Dictionary<string, List<VideoInfo>>(StringComparer.OrdinalIgnoreCase);
+
+ for (var i = 0; i < videos.Count; i++)
+ {
+ var video = videos[i];
+ var episodeResult = _episodePathParser.Parse(video.Files[0].Path, false);
+ string? key = null;
+ if (episodeResult.Success)
+ {
+ if (episodeResult.IsByDate
+ && episodeResult.Year.HasValue
+ && episodeResult.Month.HasValue
+ && episodeResult.Day.HasValue)
+ {
+ key = FormattableString.Invariant(
+ $"D{episodeResult.Year.Value}{episodeResult.Month.Value:D2}{episodeResult.Day.Value:D2}");
+ }
+ else if (episodeResult.EpisodeNumber.HasValue)
+ {
+ key = FormattableString.Invariant(
+ $"S{episodeResult.SeasonNumber ?? 0}E{episodeResult.EpisodeNumber.Value}");
+ }
+ }
+
+ if (key is null)
+ {
+ result.Add(video);
+ continue;
+ }
+
+ if (!groups.TryGetValue(key, out var group))
+ {
+ group = [];
+ groups[key] = group;
+ }
+
+ group.Add(video);
+ }
+
+ foreach (var group in groups.Values)
+ {
+ if (group.Count == 1)
+ {
+ result.Add(group[0]);
+ continue;
+ }
+
+ result.Add(OrganizeAlternateVersions(group));
+ }
+
+ return result;
+ }
+
+ private static VideoInfo OrganizeAlternateVersions(
+ List<VideoInfo> videos,
+ VideoInfo? primaryOverride = null,
+ string? nameOverride = null)
+ {
+ if (videos.Count > 1)
+ {
+ var groups = videos
+ .Select(x => (filename: x.Files[0].FileNameWithoutExtension.ToString(), value: x))
+ .Select(x => (x.filename, resolutionMatch: ResolutionRegex().Match(x.filename), x.value))
+ .GroupBy(x => x.resolutionMatch.Success)
+ .ToList();
+
+ videos = [];
+
+ foreach (var group in groups)
+ {
+ if (group.Key)
+ {
+ videos.InsertRange(0, group
+ .OrderByDescending(x => x.resolutionMatch.Value, _numericOrdinalComparer)
+ .ThenBy(x => x.filename, _numericOrdinalComparer)
+ .Select(x => x.value));
+ }
+ else
+ {
+ videos.AddRange(group.OrderBy(x => x.filename, _numericOrdinalComparer).Select(x => x.value));
+ }
+ }
+ }
+
+ // Prefer a stacked entry (more than one part) as primary
+ var primary = primaryOverride
+ ?? videos.FirstOrDefault(v => v.Files.Count > 1)
+ ?? videos[0];
+ videos.Remove(primary);
+
+ primary.AlternateVersions = videos;
+
+ if (nameOverride is not null)
+ {
+ primary.Name = nameOverride;
+ }
+
+ return primary;
+ }
}
}
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 3e98a5276c..c81829688f 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -14,6 +14,7 @@ using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Emby.Naming.Common;
+using Emby.Naming.Video;
using Emby.Photos;
using Emby.Server.Implementations.Chapters;
using Emby.Server.Implementations.Collections;
@@ -25,6 +26,7 @@ using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.HttpServer.Security;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Library;
+using Emby.Server.Implementations.Library.SimilarItems;
using Emby.Server.Implementations.Localization;
using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.Plugins;
@@ -92,7 +94,11 @@ using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.Lyric;
using MediaBrowser.Providers.Manager;
+using MediaBrowser.Providers.Plugins.ListenBrainz;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Api;
using MediaBrowser.Providers.Plugins.Tmdb;
+using MediaBrowser.Providers.Plugins.Tmdb.Movies;
+using MediaBrowser.Providers.Plugins.Tmdb.TV;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.AspNetCore.Http;
@@ -483,6 +489,11 @@ namespace Emby.Server.Implementations
serviceCollection.AddScoped<ISystemManager, SystemManager>();
serviceCollection.AddSingleton<TmdbClientManager>();
+ serviceCollection.AddSingleton<TmdbMovieSimilarProvider>();
+ serviceCollection.AddSingleton<TmdbSeriesSimilarProvider>();
+
+ serviceCollection.AddSingleton<ListenBrainzLabsClient>();
+ serviceCollection.AddSingleton<ListenBrainzSimilarArtistProvider>();
serviceCollection.AddSingleton(NetManager);
@@ -530,12 +541,15 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
serviceCollection.AddSingleton<NamingOptions>();
+ serviceCollection.AddSingleton<VideoListResolver>();
serviceCollection.AddSingleton<IMusicManager, MusicManager>();
serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
serviceCollection.AddSingleton<DotIgnoreIgnoreRule>();
+ serviceCollection.AddSingleton<ISimilarItemsManager, SimilarItemsManager>();
+
serviceCollection.AddSingleton<ISearchEngine, SearchEngine>();
serviceCollection.AddSingleton<IWebSocketManager, WebSocketManager>();
@@ -693,6 +707,8 @@ namespace Emby.Server.Implementations
GetExports<IExternalUrlProvider>());
Resolve<IMediaSourceManager>().AddParts(GetExports<IMediaSourceProvider>());
+
+ Resolve<ISimilarItemsManager>().AddParts(GetExports<ISimilarItemsProvider>());
}
/// <summary>
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index 373b0994a6..e9bf3b93a7 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -1,5 +1,6 @@
using System;
using System.Buffers;
+using System.Globalization;
using System.IO.Pipelines;
using System.Net;
using System.Net.WebSockets;
@@ -69,6 +70,11 @@ namespace Emby.Server.Implementations.HttpServer
/// <inheritdoc />
public IPAddress? RemoteEndPoint { get; }
+ /// <summary>
+ /// Gets or initializes the UI culture captured from the upgrade request.
+ /// </summary>
+ public CultureInfo? RequestUICulture { get; init; }
+
/// <inheritdoc />
public Func<WebSocketMessageInfo, Task>? OnReceive { get; set; }
@@ -82,6 +88,17 @@ namespace Emby.Server.Implementations.HttpServer
public WebSocketState State => _socket.State;
/// <inheritdoc />
+ public void ApplyRequestCulture()
+ {
+ if (RequestUICulture is null)
+ {
+ return;
+ }
+
+ CultureInfo.CurrentUICulture = RequestUICulture;
+ }
+
+ /// <inheritdoc />
public async Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken)
{
var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions);
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
index cb5b3993b8..072034c4bf 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Net.WebSockets;
using System.Threading.Tasks;
@@ -47,14 +48,18 @@ namespace Emby.Server.Implementations.HttpServer
_logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress);
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
-
var connection = new WebSocketConnection(
_loggerFactory.CreateLogger<WebSocketConnection>(),
webSocket,
authorizationInfo,
context.GetNormalizedRemoteIP())
{
- OnReceive = ProcessWebSocketMessageReceived
+ RequestUICulture = CultureInfo.CurrentUICulture
+ };
+ connection.OnReceive = result =>
+ {
+ connection.ApplyRequestCulture();
+ return ProcessWebSocketMessageReceived(result);
};
await using (connection.ConfigureAwait(false))
{
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 11f1496086..30ff1bd333 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
using BitFaster.Caching.Lru;
using Emby.Naming.Common;
using Emby.Naming.TV;
+using Emby.Naming.Video;
using Emby.Server.Implementations.Library.Resolvers;
using Emby.Server.Implementations.Library.Validators;
using Emby.Server.Implementations.Playlists;
@@ -87,6 +88,7 @@ namespace Emby.Server.Implementations.Library
private readonly IPathManager _pathManager;
private readonly FastConcurrentLru<Guid, BaseItem> _cache;
private readonly DotIgnoreIgnoreRule _dotIgnoreIgnoreRule;
+ private readonly IMediaStreamRepository _mediaStreamRepository;
/// <summary>
/// The _root folder sync lock.
@@ -129,6 +131,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="peopleRepository">The people repository.</param>
/// <param name="pathManager">The path manager.</param>
/// <param name="dotIgnoreIgnoreRule">The .ignore rule handler.</param>
+ /// <param name="mediaStreamRepository">The media stream repository.</param>
public LibraryManager(
IServerApplicationHost appHost,
ILoggerFactory loggerFactory,
@@ -151,7 +154,8 @@ namespace Emby.Server.Implementations.Library
IDirectoryService directoryService,
IPeopleRepository peopleRepository,
IPathManager pathManager,
- DotIgnoreIgnoreRule dotIgnoreIgnoreRule)
+ DotIgnoreIgnoreRule dotIgnoreIgnoreRule,
+ IMediaStreamRepository mediaStreamRepository)
{
_appHost = appHost;
_logger = loggerFactory.CreateLogger<LibraryManager>();
@@ -181,6 +185,8 @@ namespace Emby.Server.Implementations.Library
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
+ _mediaStreamRepository = mediaStreamRepository;
+
RecordConfigurationValues(_configurationManager.Configuration);
}
@@ -787,6 +793,42 @@ namespace Emby.Server.Implementations.Library
CollectionType? collectionType = null)
=> ResolvePath(fileInfo, directoryService ?? new DirectoryService(_fileSystem), null, parent, collectionType);
+ private void SetAdditionalPartsFromStack(Video altVideo, string path)
+ {
+ if (altVideo.AdditionalParts is { Length: > 0 })
+ {
+ return;
+ }
+
+ var directory = Path.GetDirectoryName(path);
+ if (string.IsNullOrEmpty(directory))
+ {
+ return;
+ }
+
+ IEnumerable<FileSystemMetadata> siblings;
+ try
+ {
+ siblings = _fileSystem.GetFiles(directory);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to enumerate siblings to detect stack for {Path}", path);
+ return;
+ }
+
+ var stacks = StackResolver.Resolve(siblings, _namingOptions);
+ foreach (var stack in stacks)
+ {
+ if (stack.Files.Count > 1
+ && string.Equals(stack.Files[0], path, StringComparison.OrdinalIgnoreCase))
+ {
+ altVideo.AdditionalParts = stack.Files.Skip(1).ToArray();
+ return;
+ }
+ }
+ }
+
/// <inheritdoc />
public Video? ResolveAlternateVersion(string path, Type expectedVideoType, Folder? parent, CollectionType? collectionType)
{
@@ -2307,6 +2349,10 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ // ResolveAlternateVersion only sees the alternate's primary file.
+ // If the alternate is itself a stack (e.g. 1080p part1 + part2),
+ // detect its parts from sibling files so its AdditionalParts persist.
+ SetAdditionalPartsFromStack(altVideo, path);
allItems.Add(altVideo);
}
}
@@ -2510,6 +2556,10 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ // ResolveAlternateVersion only sees the alternate's primary file.
+ // If the alternate is itself a stack (e.g. 1080p part1 + part2),
+ // detect its parts from sibling files so its AdditionalParts persist.
+ SetAdditionalPartsFromStack(altVideo, path);
allItems.Add(altVideo);
}
}
@@ -3800,5 +3850,11 @@ namespace Emby.Server.Implementations.Library
SetTopParentOrAncestorIds(query);
return _itemRepository.GetQueryFiltersLegacy(query);
}
+
+ /// <inheritdoc />
+ public IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType)
+ {
+ return _mediaStreamRepository.GetMediaStreamLanguages(mediaStreamType);
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 98e8f5350b..68b66ab7f5 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -28,15 +28,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
public partial class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
{
private readonly IImageProcessor _imageProcessor;
+ private readonly VideoListResolver _videoListResolver;
- private static readonly CollectionType[] _validCollectionTypes = new[]
- {
+ private static readonly CollectionType[] _validCollectionTypes =
+ [
CollectionType.movies,
CollectionType.homevideos,
CollectionType.musicvideos,
CollectionType.tvshows,
CollectionType.photos
- };
+ ];
/// <summary>
/// Initializes a new instance of the <see cref="MovieResolver"/> class.
@@ -45,10 +46,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="directoryService">The directory service.</param>
- public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ /// <param name="videoListResolver">The video list resolver.</param>
+ public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService, VideoListResolver videoListResolver)
: base(logger, namingOptions, directoryService)
{
_imageProcessor = imageProcessor;
+ _videoListResolver = videoListResolver;
}
/// <summary>
@@ -228,7 +231,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (collectionType == CollectionType.tvshows)
{
- return ResolveVideos<Episode>(parent, files, false, collectionType, true);
+ return ResolveVideos<Episode>(parent, files, true, collectionType, true);
}
return null;
@@ -274,7 +277,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
.Where(f => f is not null)
.ToList();
- var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName, parent.ContainingFolderPath);
+ var resolverResult = _videoListResolver.Resolve(videoInfos, supportMultiEditions, parseName, parent.ContainingFolderPath, collectionType);
var result = new MultiItemResolverResult
{
@@ -302,7 +305,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
ProductionYear = video.Year,
Name = parseName ? video.Name : firstVideo.Name,
AdditionalParts = additionalParts,
- LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
+ LocalAlternateVersions = video.AlternateVersions.Select(av => av.Files[0].Path).ToArray()
};
SetVideoType(videoItem, firstVideo);
@@ -331,9 +334,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
for (var j = 0; j < current.AlternateVersions.Count; j++)
{
- if (ContainsFile(current.AlternateVersions[j], file))
+ var alternate = current.AlternateVersions[j];
+ for (var k = 0; k < alternate.Files.Count; k++)
{
- return true;
+ if (ContainsFile(alternate.Files[k], file))
+ {
+ return true;
+ }
}
}
}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/AudioSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/AudioSimilarItemsProvider.cs
new file mode 100644
index 0000000000..1cc670b8ee
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/AudioSimilarItemsProvider.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for audio tracks.
+/// </summary>
+public class AudioSimilarItemsProvider : ILocalSimilarItemsProvider<Audio>
+{
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AudioSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public AudioSimilarItemsProvider(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(Audio item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ ExcludeArtistIds = [.. query.ExcludeArtistIds],
+ IncludeItemTypes = [BaseItemKind.Audio],
+ EnableGroupByMetadataKey = false,
+ EnableTotalRecordCount = true,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return Task.FromResult(_libraryManager.GetItemList(internalQuery));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/LiveTvProgramSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/LiveTvProgramSimilarItemsProvider.cs
new file mode 100644
index 0000000000..7665ee2f79
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/LiveTvProgramSimilarItemsProvider.cs
@@ -0,0 +1,94 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for Live TV programs.
+/// </summary>
+public class LiveTvProgramSimilarItemsProvider : ILocalSimilarItemsProvider<LiveTvProgram>
+{
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LiveTvProgramSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="serverConfigurationManager">The server configuration manager.</param>
+ public LiveTvProgramSimilarItemsProvider(
+ ILibraryManager libraryManager,
+ IServerConfigurationManager serverConfigurationManager)
+ {
+ _libraryManager = libraryManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(LiveTvProgram item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ BaseItemKind[] includeItemTypes;
+ bool enableGroupByMetadataKey;
+ bool enableTotalRecordCount;
+
+ if (item.IsMovie)
+ {
+ // Movie-like program
+ var itemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
+
+ if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
+ {
+ itemTypes.Add(BaseItemKind.Trailer);
+ itemTypes.Add(BaseItemKind.LiveTvProgram);
+ }
+
+ includeItemTypes = [.. itemTypes];
+ enableGroupByMetadataKey = true;
+ enableTotalRecordCount = false;
+ }
+ else if (item.IsSeries)
+ {
+ // Series-like program
+ includeItemTypes = [BaseItemKind.Series];
+ enableGroupByMetadataKey = false;
+ enableTotalRecordCount = true;
+ }
+ else
+ {
+ // Default - match same type
+ includeItemTypes = [item.GetBaseItemKind()];
+ enableGroupByMetadataKey = false;
+ enableTotalRecordCount = true;
+ }
+
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ IncludeItemTypes = includeItemTypes,
+ EnableGroupByMetadataKey = enableGroupByMetadataKey,
+ EnableTotalRecordCount = enableTotalRecordCount,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return Task.FromResult(_libraryManager.GetItemList(internalQuery));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/MovieSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/MovieSimilarItemsProvider.cs
new file mode 100644
index 0000000000..93aa0574c0
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/MovieSimilarItemsProvider.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for movies and trailers.
+/// </summary>
+public sealed class MovieSimilarItemsProvider : ILocalSimilarItemsProvider<Movie>, ILocalSimilarItemsProvider<Trailer>
+{
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MovieSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="serverConfigurationManager">The server configuration manager.</param>
+ public MovieSimilarItemsProvider(
+ ILibraryManager libraryManager,
+ IServerConfigurationManager serverConfigurationManager)
+ {
+ _libraryManager = libraryManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(Movie item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(GetSimilarMovieItems(item, query));
+ }
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(Trailer item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(GetSimilarMovieItems(item, query));
+ }
+
+ bool ILocalSimilarItemsProvider.Supports(Type itemType)
+ => typeof(Movie).IsAssignableFrom(itemType) || typeof(Trailer).IsAssignableFrom(itemType);
+
+ Task<IReadOnlyList<BaseItem>> ILocalSimilarItemsProvider.GetSimilarItemsAsync(BaseItem item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ => item switch
+ {
+ Movie movie => GetSimilarItemsAsync(movie, query, cancellationToken),
+ Trailer trailer => GetSimilarItemsAsync(trailer, query, cancellationToken),
+ _ => throw new ArgumentException($"Unsupported item type {item.GetType()}", nameof(item))
+ };
+
+ private IReadOnlyList<BaseItem> GetSimilarMovieItems(BaseItem item, SimilarItemsQuery query)
+ {
+ var includeItemTypes = new List<BaseItemKind> { BaseItemKind.Movie };
+
+ if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
+ {
+ includeItemTypes.Add(BaseItemKind.Trailer);
+ includeItemTypes.Add(BaseItemKind.LiveTvProgram);
+ }
+
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ IncludeItemTypes = [.. includeItemTypes],
+ EnableGroupByMetadataKey = true,
+ EnableTotalRecordCount = false,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return _libraryManager.GetItemList(internalQuery);
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/MusicAlbumSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/MusicAlbumSimilarItemsProvider.cs
new file mode 100644
index 0000000000..c13045deda
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/MusicAlbumSimilarItemsProvider.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for music albums.
+/// </summary>
+public class MusicAlbumSimilarItemsProvider : ILocalSimilarItemsProvider<MusicAlbum>
+{
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MusicAlbumSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public MusicAlbumSimilarItemsProvider(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(MusicAlbum item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ ExcludeArtistIds = [.. query.ExcludeArtistIds],
+ IncludeItemTypes = [BaseItemKind.MusicAlbum],
+ EnableGroupByMetadataKey = false,
+ EnableTotalRecordCount = true,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return Task.FromResult(_libraryManager.GetItemList(internalQuery));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/MusicArtistSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/MusicArtistSimilarItemsProvider.cs
new file mode 100644
index 0000000000..3331419442
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/MusicArtistSimilarItemsProvider.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for music artists.
+/// </summary>
+public class MusicArtistSimilarItemsProvider : ILocalSimilarItemsProvider<MusicArtist>
+{
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MusicArtistSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public MusicArtistSimilarItemsProvider(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(MusicArtist item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ ExcludeArtistIds = [.. query.ExcludeArtistIds],
+ IncludeItemTypes = [BaseItemKind.MusicArtist],
+ EnableGroupByMetadataKey = false,
+ EnableTotalRecordCount = true,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return Task.FromResult(_libraryManager.GetItemList(internalQuery));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/SeriesSimilarItemsProvider.cs b/Emby.Server.Implementations/Library/SimilarItems/SeriesSimilarItemsProvider.cs
new file mode 100644
index 0000000000..0366fb752e
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/SeriesSimilarItemsProvider.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Provides similar items for TV series.
+/// </summary>
+public class SeriesSimilarItemsProvider : ILocalSimilarItemsProvider<Series>
+{
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SeriesSimilarItemsProvider"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public SeriesSimilarItemsProvider(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "Local Genre/Tag";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.LocalSimilarityProvider;
+
+ /// <inheritdoc/>
+ public Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(Series item, SimilarItemsQuery query, CancellationToken cancellationToken)
+ {
+ var internalQuery = new InternalItemsQuery(query.User)
+ {
+ Genres = item.Genres,
+ Tags = item.Tags,
+ Limit = query.Limit,
+ DtoOptions = query.DtoOptions ?? new DtoOptions(),
+ ExcludeItemIds = [.. query.ExcludeItemIds],
+ IncludeItemTypes = [BaseItemKind.Series],
+ EnableGroupByMetadataKey = false,
+ EnableTotalRecordCount = true,
+ OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
+ };
+
+ return Task.FromResult(_libraryManager.GetItemList(internalQuery));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SimilarItems/SimilarItemsManager.cs b/Emby.Server.Implementations/Library/SimilarItems/SimilarItemsManager.cs
new file mode 100644
index 0000000000..b56779cf3f
--- /dev/null
+++ b/Emby.Server.Implementations/Library/SimilarItems/SimilarItemsManager.cs
@@ -0,0 +1,406 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Extensions.Json;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Querying;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Server.Implementations.Library.SimilarItems;
+
+/// <summary>
+/// Manages similar items providers and orchestrates similar items operations.
+/// </summary>
+public class SimilarItemsManager : ISimilarItemsManager
+{
+ private readonly ILogger<SimilarItemsManager> _logger;
+ private readonly IServerApplicationPaths _appPaths;
+ private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
+ private ISimilarItemsProvider[] _similarItemsProviders = [];
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SimilarItemsManager"/> class.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ /// <param name="appPaths">The server application paths.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="fileSystem">The file system.</param>
+ public SimilarItemsManager(
+ ILogger<SimilarItemsManager> logger,
+ IServerApplicationPaths appPaths,
+ ILibraryManager libraryManager,
+ IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+ _libraryManager = libraryManager;
+ _fileSystem = fileSystem;
+ }
+
+ /// <inheritdoc/>
+ public void AddParts(IEnumerable<ISimilarItemsProvider> providers)
+ {
+ _similarItemsProviders = providers.ToArray();
+ }
+
+ /// <inheritdoc/>
+ public IReadOnlyList<ISimilarItemsProvider> GetSimilarItemsProviders<T>()
+ where T : BaseItem
+ {
+ var itemType = typeof(T);
+ return _similarItemsProviders
+ .Where(p => (p is ILocalSimilarItemsProvider local && local.Supports(itemType))
+ || (p is IRemoteSimilarItemsProvider remote && remote.Supports(itemType)))
+ .ToList();
+ }
+
+ /// <inheritdoc/>
+ public async Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ BaseItem item,
+ IReadOnlyList<Guid> excludeArtistIds,
+ User? user,
+ DtoOptions dtoOptions,
+ int? limit,
+ LibraryOptions? libraryOptions,
+ CancellationToken cancellationToken)
+ {
+ ArgumentNullException.ThrowIfNull(item);
+ ArgumentNullException.ThrowIfNull(excludeArtistIds);
+
+ var itemType = item.GetType();
+ var requestedLimit = limit ?? 50;
+ var itemKind = item.GetBaseItemKind();
+
+ // Ensure ProviderIds is included in DtoOptions for matching remote provider responses
+ if (!dtoOptions.Fields.Contains(ItemFields.ProviderIds))
+ {
+ dtoOptions.Fields = dtoOptions.Fields.Concat([ItemFields.ProviderIds]).ToArray();
+ }
+
+ // Local providers are always enabled. Remote providers must be explicitly enabled.
+ var localProviders = _similarItemsProviders
+ .OfType<ILocalSimilarItemsProvider>()
+ .Where(p => p.Supports(itemType))
+ .ToList();
+ var remoteProviders = _similarItemsProviders
+ .OfType<IRemoteSimilarItemsProvider>()
+ .Where(p => p.Supports(itemType));
+ var matchingProviders = new List<ISimilarItemsProvider>(localProviders);
+
+ var typeOptions = libraryOptions?.GetTypeOptions(itemType.Name);
+ if (typeOptions?.SimilarItemProviders?.Length > 0)
+ {
+ matchingProviders.AddRange(remoteProviders
+ .Where(p => typeOptions.SimilarItemProviders.Contains(p.Name, StringComparer.OrdinalIgnoreCase)));
+ }
+
+ var orderConfig = typeOptions?.SimilarItemProviderOrder is { Length: > 0 } order
+ ? order
+ : typeOptions?.SimilarItemProviders;
+ var orderedProviders = matchingProviders
+ .OrderBy(p => GetConfiguredSimilarProviderOrder(orderConfig, p.Name))
+ .ToList();
+
+ var allResults = new List<(BaseItem Item, float Score)>();
+ var excludeIds = new HashSet<Guid> { item.Id };
+ foreach (var (providerOrder, provider) in orderedProviders.Index())
+ {
+ if (allResults.Count >= requestedLimit || cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+
+ try
+ {
+ if (provider is ILocalSimilarItemsProvider localProvider)
+ {
+ var query = new SimilarItemsQuery
+ {
+ User = user,
+ Limit = requestedLimit - allResults.Count,
+ DtoOptions = dtoOptions,
+ ExcludeItemIds = [.. excludeIds],
+ ExcludeArtistIds = excludeArtistIds
+ };
+
+ var items = await localProvider.GetSimilarItemsAsync(item, query, cancellationToken).ConfigureAwait(false);
+
+ foreach (var (position, resultItem) in items.Index())
+ {
+ if (excludeIds.Add(resultItem.Id))
+ {
+ var score = CalculateScore(null, providerOrder, position);
+ allResults.Add((resultItem, score));
+ }
+ }
+ }
+ else if (provider is IRemoteSimilarItemsProvider remoteProvider)
+ {
+ var cachePath = GetSimilarItemsCachePath(provider.Name, itemType.Name, item.Id);
+
+ var cachedReferences = await TryReadSimilarItemsCacheAsync(cachePath, cancellationToken).ConfigureAwait(false);
+ if (cachedReferences is not null)
+ {
+ var resolvedItems = ResolveRemoteReferences(cachedReferences, providerOrder, user, dtoOptions, itemKind, excludeIds);
+ allResults.AddRange(resolvedItems);
+ continue;
+ }
+
+ var query = new SimilarItemsQuery
+ {
+ User = user,
+ Limit = requestedLimit - allResults.Count,
+ DtoOptions = dtoOptions,
+ ExcludeItemIds = [.. excludeIds],
+ ExcludeArtistIds = excludeArtistIds
+ };
+
+ // Collect references in batches and resolve against local library.
+ // Stop fetching once we have enough resolved local items.
+ const int BatchSize = 20;
+ var remaining = requestedLimit - allResults.Count;
+ var collectedReferences = new List<SimilarItemReference>();
+ var pendingBatch = new List<SimilarItemReference>();
+
+ await foreach (var reference in remoteProvider.GetSimilarItemsAsync(item, query, cancellationToken).ConfigureAwait(false))
+ {
+ collectedReferences.Add(reference);
+ pendingBatch.Add(reference);
+
+ if (pendingBatch.Count >= BatchSize)
+ {
+ var resolvedItems = ResolveRemoteReferences(pendingBatch, providerOrder, user, dtoOptions, itemKind, excludeIds);
+ allResults.AddRange(resolvedItems);
+ remaining -= resolvedItems.Count;
+ pendingBatch.Clear();
+
+ if (remaining <= 0)
+ {
+ break;
+ }
+ }
+ }
+
+ // Resolve any remaining references in the last partial batch
+ if (pendingBatch.Count > 0)
+ {
+ var resolvedItems = ResolveRemoteReferences(pendingBatch, providerOrder, user, dtoOptions, itemKind, excludeIds);
+ allResults.AddRange(resolvedItems);
+ }
+
+ if (collectedReferences.Count > 0 && provider.CacheDuration is not null)
+ {
+ await SaveSimilarItemsCacheAsync(cachePath, collectedReferences, provider.CacheDuration.Value, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ break;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Similar items provider {ProviderName} failed for item {ItemId}", provider.Name, item.Id);
+ }
+ }
+
+ return allResults
+ .OrderByDescending(x => x.Score)
+ .Select(x => x.Item)
+ .Take(requestedLimit)
+ .ToList();
+ }
+
+ private List<(BaseItem Item, float Score)> ResolveRemoteReferences(
+ IReadOnlyList<SimilarItemReference> references,
+ int providerOrder,
+ User? user,
+ DtoOptions dtoOptions,
+ BaseItemKind itemKind,
+ HashSet<Guid> excludeIds)
+ {
+ if (references.Count == 0)
+ {
+ return [];
+ }
+
+ var resolvedById = new Dictionary<Guid, (BaseItem Item, float Score)>();
+ var providerLookup = new Dictionary<(string ProviderName, string ProviderId), (float? Score, int Position)>(StringTupleComparer.Instance);
+
+ foreach (var (position, match) in references.Index())
+ {
+ var lookupKey = (match.ProviderName, match.ProviderId);
+ if (!providerLookup.TryGetValue(lookupKey, out var existing))
+ {
+ providerLookup[lookupKey] = (match.Score, position);
+ }
+ else if (match.Score > existing.Score || (match.Score == existing.Score && position < existing.Position))
+ {
+ providerLookup[lookupKey] = (match.Score, position);
+ }
+ }
+
+ var allProviderIds = providerLookup
+ .GroupBy(kvp => kvp.Key.ProviderName)
+ .ToDictionary(g => g.Key, g => g.Select(x => x.Key.ProviderId).ToArray());
+
+ var query = new InternalItemsQuery(user)
+ {
+ HasAnyProviderIds = allProviderIds,
+ IncludeItemTypes = [itemKind],
+ DtoOptions = dtoOptions
+ };
+
+ var items = _libraryManager.GetItemList(query);
+
+ foreach (var item in items)
+ {
+ if (excludeIds.Contains(item.Id) || resolvedById.ContainsKey(item.Id))
+ {
+ continue;
+ }
+
+ foreach (var providerName in allProviderIds.Keys)
+ {
+ if (item.TryGetProviderId(providerName, out var itemProviderId) && providerLookup.TryGetValue((providerName, itemProviderId), out var matchInfo))
+ {
+ var score = CalculateScore(matchInfo.Score, providerOrder, matchInfo.Position);
+ if (!resolvedById.TryGetValue(item.Id, out var existing) || existing.Score < score)
+ {
+ excludeIds.Add(item.Id);
+ resolvedById[item.Id] = (item, score);
+ }
+
+ break;
+ }
+ }
+ }
+
+ return [.. resolvedById.Values];
+ }
+
+ private static float CalculateScore(float? matchScore, int providerOrder, int position)
+ {
+ // Use provider-supplied score if available, otherwise derive from position
+ var baseScore = matchScore ?? (1.0f - (position * 0.02f));
+
+ // Apply small boost based on provider order (higher priority providers get small bonus)
+ var priorityBoost = Math.Max(0, 10 - providerOrder) * 0.005f;
+
+ return Math.Clamp(baseScore + priorityBoost, 0f, 1f);
+ }
+
+ private static int GetConfiguredSimilarProviderOrder(string[]? orderConfig, string providerName)
+ {
+ if (orderConfig is null || orderConfig.Length == 0)
+ {
+ return int.MaxValue;
+ }
+
+ var index = Array.FindIndex(orderConfig, name => string.Equals(name, providerName, StringComparison.OrdinalIgnoreCase));
+ return index >= 0 ? index : int.MaxValue;
+ }
+
+ private string GetSimilarItemsCachePath(string providerName, string baseItemType, Guid itemId)
+ {
+ var dataPath = Path.Combine(
+ _appPaths.CachePath,
+ $"{providerName.ToLowerInvariant()}-similar-{baseItemType.ToLowerInvariant()}");
+ return Path.Combine(dataPath, $"{itemId.ToString("N", CultureInfo.InvariantCulture)}.json");
+ }
+
+ private async Task<List<SimilarItemReference>?> TryReadSimilarItemsCacheAsync(string cachePath, CancellationToken cancellationToken)
+ {
+ var fileInfo = _fileSystem.GetFileSystemInfo(cachePath);
+ if (!fileInfo.Exists || fileInfo.Length == 0)
+ {
+ return null;
+ }
+
+ try
+ {
+ var stream = File.OpenRead(cachePath);
+ await using (stream.ConfigureAwait(false))
+ {
+ var cache = await JsonSerializer.DeserializeAsync<SimilarItemsCache>(stream, JsonDefaults.Options, cancellationToken).ConfigureAwait(false);
+ if (cache?.References is not null && DateTime.UtcNow < cache.ExpiresAt)
+ {
+ return cache.References;
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ _logger.LogWarning(ex, "Failed to read similar items cache from {CachePath}", cachePath);
+ }
+ catch (JsonException ex)
+ {
+ _logger.LogWarning(ex, "Failed to parse similar items cache from {CachePath}", cachePath);
+ }
+
+ return null;
+ }
+
+ private async Task SaveSimilarItemsCacheAsync(string cachePath, List<SimilarItemReference> references, TimeSpan cacheDuration, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var directory = Path.GetDirectoryName(cachePath);
+ if (!string.IsNullOrEmpty(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ var cache = new SimilarItemsCache
+ {
+ References = references,
+ ExpiresAt = DateTime.UtcNow.Add(cacheDuration)
+ };
+
+ var stream = File.Create(cachePath);
+ await using (stream.ConfigureAwait(false))
+ {
+ await JsonSerializer.SerializeAsync(stream, cache, JsonDefaults.Options, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ catch (IOException ex)
+ {
+ _logger.LogWarning(ex, "Failed to save similar items cache to {CachePath}", cachePath);
+ }
+ }
+
+ private sealed class SimilarItemsCache
+ {
+ public List<SimilarItemReference>? References { get; set; }
+
+ public DateTime ExpiresAt { get; set; }
+ }
+
+ private sealed class StringTupleComparer : IEqualityComparer<(string Key, string Value)>
+ {
+ public static readonly StringTupleComparer Instance = new();
+
+ public bool Equals((string Key, string Value) x, (string Key, string Value) y)
+ => string.Equals(x.Key, y.Key, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(x.Value, y.Value, StringComparison.OrdinalIgnoreCase);
+
+ public int GetHashCode((string Key, string Value) obj)
+ => HashCode.Combine(
+ StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Key),
+ StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Value));
+ }
+}
diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
index 71ce3b6012..7c605036cf 100644
--- a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
@@ -80,7 +80,7 @@ public class SplashscreenPostScanTask : ILibraryPostScanTask
ImageTypes = [imageType],
Limit = 30,
// TODO max parental rating configurable
- MaxParentalRating = new(10, null),
+ MaxParentalRating = new(13, null),
OrderBy =
[
(ItemSortBy.Random, SortOrder.Ascending)
diff --git a/Emby.Server.Implementations/Localization/Core/ab.json b/Emby.Server.Implementations/Localization/Core/ab.json
index d6d257c5ba..d67f2d67e9 100644
--- a/Emby.Server.Implementations/Localization/Core/ab.json
+++ b/Emby.Server.Implementations/Localization/Core/ab.json
@@ -1,5 +1,3 @@
{
- "Albums": "аальбомқәа",
- "AppDeviceValues": "Апп: {0}, Априбор: {1}",
- "Application": "Апрограмма"
+ "AppDeviceValues": "Апп: {0}, Априбор: {1}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/af.json b/Emby.Server.Implementations/Localization/Core/af.json
index 80c1bd0940..308341ad49 100644
--- a/Emby.Server.Implementations/Localization/Core/af.json
+++ b/Emby.Server.Implementations/Localization/Core/af.json
@@ -1,11 +1,8 @@
{
"Artists": "Kunstenare",
- "Channels": "Kanale",
"Folders": "Lêergidse",
"Favorites": "Gunstelinge",
"HeaderFavoriteShows": "Gunsteling Vertonings",
- "ValueSpecialEpisodeName": "Spesiale - {0}",
- "HeaderAlbumArtists": "Album kunstenaars",
"Books": "Boeke",
"HeaderNextUp": "Volgende",
"Movies": "Flieks",
@@ -13,24 +10,13 @@
"HeaderContinueWatching": "Hou aan kyk",
"HeaderFavoriteEpisodes": "Gunsteling Episodes",
"Photos": "Foto's",
- "Playlists": "Snitlyste",
- "HeaderFavoriteArtists": "Gunsteling Kunstenaars",
- "HeaderFavoriteAlbums": "Gunsteling Albums",
- "Sync": "Sinkroniseer",
- "HeaderFavoriteSongs": "Gunsteling Liedjies",
- "Songs": "Liedjies",
- "DeviceOnlineWithName": "{0} is aanlyn",
- "DeviceOfflineWithName": "{0} is ontkoppel",
"Collections": "Versamelings",
"Inherit": "Ontvang",
"HeaderLiveTV": "Lewendige TV",
- "Application": "Program",
"AppDeviceValues": "App: {0}, Toestel: {1}",
"VersionNumber": "Weergawe {0}",
- "ValueHasBeenAddedToLibrary": "{0} is by jou media biblioteek bygevoeg",
"UserStoppedPlayingItemWithValues": "{0} het klaar {1} op {2} gespeel",
"UserStartedPlayingItemWithValues": "{0} is besig om {1} op {2} te speel",
- "UserPolicyUpdatedWithName": "Gebruiker beleid is verander vir {0}",
"UserPasswordChangedWithName": "Gebruiker {0} se wagwoord is verander",
"UserOnlineFromDevice": "{0} is aanlyn van {1}",
"UserOfflineFromDevice": "{0} is ontkoppel van {1}",
@@ -38,19 +24,13 @@
"UserDownloadingItemWithValues": "{0} is besig om {1} af te laai",
"UserDeletedWithName": "Gebruiker {0} is verwyder",
"UserCreatedWithName": "Gebruiker {0} is geskep",
- "User": "Gebruiker",
"TvShows": "TV Programme",
- "System": "Stelsel",
"SubtitleDownloadFailureFromForItem": "Ondertitels het misluk om af te laai van {0} vir {1}",
"StartupEmbyServerIsLoading": "Jellyfin Bediener is besig om te laai. Probeer weer in 'n kort tyd.",
- "ServerNameNeedsToBeRestarted": "{0} moet herbegin word",
- "ScheduledTaskStartedWithName": "{0} het begin",
"ScheduledTaskFailedWithName": "{0} het misluk",
- "ProviderValue": "Voorsiener: {0}",
"PluginUpdatedWithName": "{0} was opgedateer",
"PluginUninstalledWithName": "{0} was verwyder",
"PluginInstalledWithName": "{0} is geïnstalleer",
- "Plugin": "Inprop module",
"NotificationOptionVideoPlaybackStopped": "Video terugspeel het gestop",
"NotificationOptionVideoPlayback": "Video terugspeel het begin",
"NotificationOptionUserLockedOut": "Gebruiker uitgeslyt",
@@ -74,23 +54,14 @@
"MusicVideos": "Musiek Videos",
"Music": "Musiek",
"MixedContent": "Gemengde inhoud",
- "MessageServerConfigurationUpdated": "Bediener konfigurasie is opgedateer",
- "MessageNamedServerConfigurationUpdatedWithValue": "Bediener konfigurasie seksie {0} is opgedateer",
- "MessageApplicationUpdatedTo": "Jellyfin Bediener is opgedateer na {0}",
- "MessageApplicationUpdated": "Jellyfin Bediener is opgedateer",
"Latest": "Nuutste",
"LabelRunningTimeValue": "Werktyd: {0}",
"LabelIpAddressValue": "IP adres: {0}",
- "ItemRemovedWithName": "{0} is uit versameling verwyder",
- "ItemAddedWithName": "{0} is by die versameling gevoeg",
"HomeVideos": "Tuis Videos",
- "HeaderRecordingGroups": "Groep Opnames",
"Genres": "Genres",
"FailedLoginAttemptWithUserName": "Mislukte aanmeldpoging van {0}",
"ChapterNameValue": "Hoofstuk {0}",
- "CameraImageUploadedFrom": "'n Nuwe kamera foto is opgelaai vanaf {0}",
"AuthenticationSucceededWithUserName": "{0} suksesvol geverifieer",
- "Albums": "Albums",
"TasksChannelsCategory": "Internet kanale",
"TasksApplicationCategory": "aansoek",
"TasksLibraryCategory": "biblioteek",
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index e48939b4d7..1eaf1d79e8 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -1,41 +1,24 @@
{
- "Albums": "الألبومات",
"AppDeviceValues": "التطبيق: {0}، الجهاز: {1}",
- "Application": "التطبيق",
"Artists": "الفنانون",
"AuthenticationSucceededWithUserName": "تمت مصادقة {0} بنجاح",
"Books": "الكتب",
- "CameraImageUploadedFrom": "تم رفع صورة كاميرا جديدة من {0}",
- "Channels": "القنوات",
"ChapterNameValue": "الفصل {0}",
"Collections": "المجموعات",
- "DeviceOfflineWithName": "انقطع اتصال {0}",
- "DeviceOnlineWithName": "{0} متصل",
"FailedLoginAttemptWithUserName": "محاولة تسجيل دخول فاشلة من {0}",
"Favorites": "المفضلة",
"Folders": "المجلدات",
"Genres": "الأنواع",
- "HeaderAlbumArtists": "فنانو الألبوم",
"HeaderContinueWatching": "متابعة المشاهدة",
- "HeaderFavoriteAlbums": "الألبومات المفضلة",
- "HeaderFavoriteArtists": "الفنانون المفضلون",
"HeaderFavoriteEpisodes": "الحلقات المفضلة",
"HeaderFavoriteShows": "المسلسلات المفضلة",
- "HeaderFavoriteSongs": "الأغاني المفضلة",
"HeaderLiveTV": "البث التلفزيوني المباشر",
"HeaderNextUp": "التالي",
- "HeaderRecordingGroups": "مجموعات التسجيل",
"HomeVideos": "فيديوهات منزلية",
"Inherit": "وراثة",
- "ItemAddedWithName": "تمت إضافة {0} إلى المكتبة",
- "ItemRemovedWithName": "تمت إزالة {0} من المكتبة",
"LabelIpAddressValue": "عنوان IP: {0}",
"LabelRunningTimeValue": "مدة التشغيل: {0}",
"Latest": "الأحدث",
- "MessageApplicationUpdated": "تم تحديث خادم Jellyfin",
- "MessageApplicationUpdatedTo": "تم تحديث خادم Jellyfin إلى {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "تم تحديث قسم إعدادات الخادم {0}",
- "MessageServerConfigurationUpdated": "تم تحديث إعدادات الخادم",
"MixedContent": "محتوى مختلط",
"Movies": "الأفلام",
"Music": "الموسيقى",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "بدأ تشغيل الفيديو",
"NotificationOptionVideoPlaybackStopped": "توقف تشغيل الفيديو",
"Photos": "الصور",
- "Playlists": "قوائم التشغيل",
- "Plugin": "الملحق",
"PluginInstalledWithName": "تم تثبيت {0}",
"PluginUninstalledWithName": "تمت إزالة {0}",
"PluginUpdatedWithName": "تم تحديث {0}",
- "ProviderValue": "المزوّد: {0}",
"ScheduledTaskFailedWithName": "فشلت {0}",
- "ScheduledTaskStartedWithName": "بدأت {0}",
- "ServerNameNeedsToBeRestarted": "يحتاج {0} إلى إعادة التشغيل",
"Shows": "المسلسلات",
- "Songs": "الأغاني",
"StartupEmbyServerIsLoading": "يتم الآن تحميل خادم Jellyfin. يرجى المحاولة مرة أخرى بعد قليل.",
"SubtitleDownloadFailureFromForItem": "فشل تنزيل الترجمات من {0} لـ {1}",
- "Sync": "مزامنة",
- "System": "النظام",
"TvShows": "البرامج التلفزيونية",
- "User": "المستخدم",
"UserCreatedWithName": "تم إنشاء المستخدم {0}",
"UserDeletedWithName": "تم حذف المستخدم {0}",
"UserDownloadingItemWithValues": "{0} يقوم بتنزيل {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "انقطع اتصال {0} من {1}",
"UserOnlineFromDevice": "{0} متصل من {1}",
"UserPasswordChangedWithName": "تم تغيير كلمة المرور للمستخدم {0}",
- "UserPolicyUpdatedWithName": "تم تحديث سياسة المستخدم لـ {0}",
"UserStartedPlayingItemWithValues": "{0} يقوم بتشغيل {1} على {2}",
"UserStoppedPlayingItemWithValues": "أنهى {0} تشغيل {1} على {2}",
- "ValueHasBeenAddedToLibrary": "تمت إضافة {0} إلى مكتبة المحتوى الخاصة بك",
- "ValueSpecialEpisodeName": "خاص - {0}",
"VersionNumber": "الإصدار {0}",
"TaskCleanCacheDescription": "يحذف ملفات ذاكرة التخزين المؤقت التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "تنظيف مجلد ذاكرة التخزين المؤقت",
diff --git a/Emby.Server.Implementations/Localization/Core/as.json b/Emby.Server.Implementations/Localization/Core/as.json
index 7c7dd26e92..bc0c2c5ff5 100644
--- a/Emby.Server.Implementations/Localization/Core/as.json
+++ b/Emby.Server.Implementations/Localization/Core/as.json
@@ -1,18 +1,13 @@
{
- "Albums": "এলবাম",
- "Application": "আবেদন",
"AppDeviceValues": "এপ্‌: {0}, ডিভাইচ: {1}",
"Artists": "শিল্পী",
- "Channels": "চেনেলস",
"Default": "ডিফল্ট",
"AuthenticationSucceededWithUserName": "{0} সফলভাবে প্রমাণিত",
"Books": "পুস্তক",
"Movies": "চলচ্চিত্ৰ",
- "CameraImageUploadedFrom": "একটি নতুন ক্যামেরা চিত্র আপলোড করা হয়েছে {0}",
"Collections": "সংগ্রহ",
"HeaderFavoriteShows": "প্রিয় শোসমূহ",
"Latest": "শেহতীয়া",
- "MessageApplicationUpdated": "জেলিফিন চাইভাৰ আপডেট কৰা হৈছে",
"MixedContent": "মিশ্ৰিত সমগ্ৰতা",
"NewVersionIsAvailable": "ডাউনলোড কৰিবলৈ জেলিফিন চাইভাৰৰ এটা নতুন সংস্কৰণ উপলব্ধ আছে.",
"NotificationOptionCameraImageUploaded": "কেমেৰাৰ চিত্ৰ আপল'ড কৰা হ'ল",
@@ -21,20 +16,14 @@
"Folders": "ফোল্ডাৰ",
"Forced": "বলপূর্বক",
"Genres": "শ্রেণী",
- "HeaderAlbumArtists": "অ্যালবাম শিল্পী",
"HeaderContinueWatching": "দেখা চালিয়ে যান",
"FailedLoginAttemptWithUserName": "লগইন ব্যর্থ চেষ্টা কৰা হৈছে থেকে {0}",
- "HeaderFavoriteAlbums": "প্রিয় অ্যালবামসমূহ",
- "HeaderFavoriteArtists": "প্রিয় শিল্পীসমূহ",
"HeaderFavoriteEpisodes": "প্রিয় পর্বসমূহ",
- "HeaderFavoriteSongs": "প্ৰিয় গীত",
"HeaderLiveTV": "প্ৰতিবেদন টিভি",
"HeaderNextUp": "পৰৱৰ্তী অংশ",
- "HeaderRecordingGroups": "অলংকৰণ গোষ্ঠীসমূহ",
"HearingImpaired": "শ্ৰবণ অক্ষম",
"HomeVideos": "ঘৰৰ ভিডিঅ'সমূহ",
"Inherit": "উত্তপ্ত কৰা",
- "MessageServerConfigurationUpdated": "চাইভাৰ কনফিগাৰেশ্যন আপডেট কৰা হৈছে",
"NotificationOptionApplicationUpdateAvailable": "অ্যাপ্লিকেশ্যন আপডেট উপলব্ধ",
"NotificationOptionApplicationUpdateInstalled": "অ্যাপ্লিকেশ্যন আপডেট ইনষ্টল কৰা হ'ল",
"NotificationOptionAudioPlayback": "অডিঅ' প্লেবেক আৰম্ভ হ'ল",
diff --git a/Emby.Server.Implementations/Localization/Core/be.json b/Emby.Server.Implementations/Localization/Core/be.json
index 543d227e73..5d0ef65842 100644
--- a/Emby.Server.Implementations/Localization/Core/be.json
+++ b/Emby.Server.Implementations/Localization/Core/be.json
@@ -1,17 +1,10 @@
{
- "Sync": "Сінхранізаваць",
- "Playlists": "Плэй-лісты",
"Latest": "Апошняе",
"LabelIpAddressValue": "IP-адрас: {0}",
- "ItemAddedWithName": "{0} дададзены ў бібліятэку",
- "MessageApplicationUpdated": "Сервер Jellyfin абноўлены",
"NotificationOptionApplicationUpdateInstalled": "Абнаўленне праграмы ўсталявана",
"PluginInstalledWithName": "{0} быў усталяваны",
"UserCreatedWithName": "Карыстальнік {0} быў створаны",
- "Albums": "Альбомы",
- "Application": "Праграма",
"AuthenticationSucceededWithUserName": "{0} паспяхова аўтарызаваны",
- "Channels": "Каналы",
"ChapterNameValue": "Раздзел {0}",
"Collections": "Калекцыі",
"Default": "Прадвызначана",
@@ -21,16 +14,11 @@
"External": "Знешні",
"Genres": "Жанры",
"HeaderContinueWatching": "Працягнуць прагляд",
- "HeaderFavoriteAlbums": "Абраныя альбомы",
"HeaderFavoriteEpisodes": "Абраныя серыі",
"HeaderFavoriteShows": "Абраныя шоу",
- "HeaderFavoriteSongs": "Абраныя песні",
"HeaderLiveTV": "Прамы эфір",
- "HeaderAlbumArtists": "Выканаўцы альбома",
"LabelRunningTimeValue": "Працягласць: {0}",
"HomeVideos": "Хатнія відэа",
- "ItemRemovedWithName": "{0} выдалены з бібліятэкі",
- "MessageApplicationUpdatedTo": "Сервер Jellyfin абноўлены да версіі {0}",
"Movies": "Фільмы",
"Music": "Музыка",
"MusicVideos": "Музычныя кліпы",
@@ -41,19 +29,13 @@
"NotificationOptionPluginUpdateInstalled": "Абнаўленне плагіна ўсталявана",
"NotificationOptionServerRestartRequired": "Патрабуецца перазапуск сервера",
"Photos": "Фотаздымкі",
- "Plugin": "Плагін",
"PluginUninstalledWithName": "{0} быў выдалены",
"PluginUpdatedWithName": "{0} быў абноўлены",
- "ProviderValue": "Пастаўшчык: {0}",
- "Songs": "Песні",
- "System": "Сістэма",
- "User": "Карыстальнік",
"UserDeletedWithName": "Карыстальнік {0} быў выдалены",
"UserDownloadingItemWithValues": "{0} спампоўваецца {1}",
"TaskOptimizeDatabase": "Аптымізацыя базы даных",
"Artists": "Выканаўцы",
"UserOfflineFromDevice": "{0} адлучыўся ад {1}",
- "UserPolicyUpdatedWithName": "Палітыка карыстальніка абноўлена для {0}",
"TaskCleanActivityLogDescription": "Выдаляе запісы старэйшыя за зададзены ўзрост ў журнале актыўнасці.",
"TaskRefreshChapterImagesDescription": "Стварае мініяцюры для відэа, якія маюць раздзелы.",
"TaskCleanLogsDescription": "Выдаляе файлы журналу, якім больш за {0} дзён.",
@@ -65,17 +47,10 @@
"TasksApplicationCategory": "Праграма",
"AppDeviceValues": "Праграма: {0}, Прылада: {1}",
"Books": "Кнігі",
- "CameraImageUploadedFrom": "Новая выява камеры была загружана з {0}",
- "DeviceOfflineWithName": "{0} адлучыўся",
- "DeviceOnlineWithName": "{0} падлучаны",
"Forced": "Прымусова",
- "HeaderRecordingGroups": "Групы запісаў",
"HeaderNextUp": "Наступнае",
- "HeaderFavoriteArtists": "Абраныя выканаўцы",
"HearingImpaired": "Са слабым слыхам",
"Inherit": "Атрымаць у спадчыну",
- "MessageNamedServerConfigurationUpdatedWithValue": "Канфігурацыя сервера (секцыя {0}) абноўлена",
- "MessageServerConfigurationUpdated": "Канфігурацыя сервера абноўлена",
"MixedContent": "Змешаны змест",
"NameSeasonUnknown": "Невядомы сезон",
"NotificationOptionInstallationFailed": "Збой усталёўкі",
@@ -91,8 +66,6 @@
"NotificationOptionVideoPlayback": "Пачалося прайграванне відэа",
"NotificationOptionVideoPlaybackStopped": "Прайграванне відэа спынена",
"ScheduledTaskFailedWithName": "{0} не атрымалася",
- "ScheduledTaskStartedWithName": "{0} пачалося",
- "ServerNameNeedsToBeRestarted": "{0} патрабуе перазапуску",
"Shows": "Шоу",
"StartupEmbyServerIsLoading": "Jellyfin Server загружаецца. Калі ласка, паўтарыце спробу крыху пазней.",
"SubtitleDownloadFailureFromForItem": "Субцітры для {1} не ўдалося спампаваць з {0}",
@@ -103,8 +76,6 @@
"UserPasswordChangedWithName": "Пароль быў зменены для карыстальніка {0}",
"UserStartedPlayingItemWithValues": "{0} прайграваецца {1} на {2}",
"UserStoppedPlayingItemWithValues": "{0} скончыў прайграванне {1} на {2}",
- "ValueHasBeenAddedToLibrary": "{0} быў дададзены ў вашу медыятэку",
- "ValueSpecialEpisodeName": "Спецвыпуск - {0}",
"VersionNumber": "Версія {0}",
"TasksMaintenanceCategory": "Абслугоўванне",
"TasksLibraryCategory": "Бібліятэка",
diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json
index 7340180241..0710a39708 100644
--- a/Emby.Server.Implementations/Localization/Core/bg-BG.json
+++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json
@@ -1,41 +1,24 @@
{
- "Albums": "Албуми",
"AppDeviceValues": "Програма: {0}, Устройство: {1}",
- "Application": "Програма",
"Artists": "Артисти",
"AuthenticationSucceededWithUserName": "{0} се удостовери успешно",
"Books": "Книги",
- "CameraImageUploadedFrom": "Нова снимка от камера беше качена от {0}",
- "Channels": "Канали",
"ChapterNameValue": "Глава {0}",
"Collections": "Колекции",
- "DeviceOfflineWithName": "{0} се разкачи",
- "DeviceOnlineWithName": "{0} е свързан",
"FailedLoginAttemptWithUserName": "Неуспешен опит за влизане от {0}",
"Favorites": "Любими",
"Folders": "Папки",
"Genres": "Жанрове",
- "HeaderAlbumArtists": "Изпълнители на албума",
"HeaderContinueWatching": "Продължаване на гледането",
- "HeaderFavoriteAlbums": "Любими албуми",
- "HeaderFavoriteArtists": "Любими изпълнители",
"HeaderFavoriteEpisodes": "Любими епизоди",
"HeaderFavoriteShows": "Любими сериали",
- "HeaderFavoriteSongs": "Любими песни",
"HeaderLiveTV": "Телевизия на живо",
"HeaderNextUp": "Следва",
- "HeaderRecordingGroups": "Запис групи",
"HomeVideos": "Домашни Клипове",
"Inherit": "Наследяване",
- "ItemAddedWithName": "{0} е добавено към библиотеката",
- "ItemRemovedWithName": "{0} е премахнато от библиотеката",
"LabelIpAddressValue": "IP адрес: {0}",
"LabelRunningTimeValue": "Продължителност: {0}",
"Latest": "Последни",
- "MessageApplicationUpdated": "Сървърът беше обновен",
- "MessageApplicationUpdatedTo": "Сървърът беше обновен до {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Секцията {0} от сървърната конфигурация беше актуализирана",
- "MessageServerConfigurationUpdated": "Конфигурацията на сървъра беше актуализирана",
"MixedContent": "Смесено съдържание",
"Movies": "Филми",
"Music": "Музика",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Възпроизвеждането на видео започна",
"NotificationOptionVideoPlaybackStopped": "Възпроизвеждането на видео е спряно",
"Photos": "Снимки",
- "Playlists": "Списъци",
- "Plugin": "Добавка",
"PluginInstalledWithName": "{0} е инсталиранa",
"PluginUninstalledWithName": "{0} е деинсталиранa",
"PluginUpdatedWithName": "{0} е обновенa",
- "ProviderValue": "Доставчик: {0}",
"ScheduledTaskFailedWithName": "{0} се провали",
- "ScheduledTaskStartedWithName": "{0} започна",
- "ServerNameNeedsToBeRestarted": "{0} трябва да се рестартира",
"Shows": "Сериали",
- "Songs": "Песни",
"StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
"SubtitleDownloadFailureFromForItem": "Субтитрите за {1} от {0} не можаха да бъдат изтеглени",
- "Sync": "Синхронизиране",
- "System": "Система",
"TvShows": "Телевизионни сериали",
- "User": "Потребител",
"UserCreatedWithName": "Потребителят {0} е създаден",
"UserDeletedWithName": "Потребителят {0} е изтрит",
"UserDownloadingItemWithValues": "{0} изтегля {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} се разкачи от {1}",
"UserOnlineFromDevice": "{0} е на линия от {1}",
"UserPasswordChangedWithName": "Паролата на потребителя {0} е променена",
- "UserPolicyUpdatedWithName": "Потребителската политика за {0} се актуализира",
"UserStartedPlayingItemWithValues": "{0} пусна {1}",
"UserStoppedPlayingItemWithValues": "{0} спря {1}",
- "ValueHasBeenAddedToLibrary": "{0} беше добавен във Вашата библиотека",
- "ValueSpecialEpisodeName": "Специални - {0}",
"VersionNumber": "Версия {0}",
"TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи субтитри, на база конфигурацията за мета-данни.",
"TaskDownloadMissingSubtitles": "Изтегляне на липсващи субтитри",
diff --git a/Emby.Server.Implementations/Localization/Core/bn.json b/Emby.Server.Implementations/Localization/Core/bn.json
index c6cfbe3c67..eb7fdf2b68 100644
--- a/Emby.Server.Implementations/Localization/Core/bn.json
+++ b/Emby.Server.Implementations/Localization/Core/bn.json
@@ -1,31 +1,19 @@
{
- "DeviceOnlineWithName": "{0}-এর সাথে সংযুক্ত হয়েছে",
- "DeviceOfflineWithName": "{0}-এর সাথে সংযোগ বিচ্ছিন্ন হয়েছে",
"Collections": "সংগ্রহশালা",
"ChapterNameValue": "অধ্যায় {0}",
- "Channels": "চ্যানেলসমূহ",
- "CameraImageUploadedFrom": "{0} থেকে একটি নতুন ক্যামেরার চিত্র আপলোড করা হয়েছে",
"Books": "পুস্তকসমূহ",
"AuthenticationSucceededWithUserName": "{0} সফলভাবে অথেন্টিকেট করেছেন",
"Artists": "শিল্পীগণ",
- "Application": "অ্যাপ্লিকেশন",
- "Albums": "অ্যালবামসমূহ",
"HeaderFavoriteEpisodes": "প্রিয় পর্বগুলো",
- "HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
- "HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
"HeaderContinueWatching": "দেখতে থাকুন",
- "HeaderAlbumArtists": "অ্যালবাম শিল্পীবৃন্দ",
"Genres": "ধরণ",
"Folders": "ফোল্ডারসমূহ",
"Favorites": "পছন্দসমূহ",
"FailedLoginAttemptWithUserName": "{0} লগিন করতে ব্যর্থ হয়েছে",
"AppDeviceValues": "অ্যাপ: {0}, ডিভাইস: {1}",
"VersionNumber": "সংস্করণ {0}",
- "ValueSpecialEpisodeName": "বিশেষ পর্ব - {0}",
- "ValueHasBeenAddedToLibrary": "আপনার লাইব্রেরিতে {0} যোগ করা হয়েছে",
"UserStoppedPlayingItemWithValues": "{2}তে {1} প্লে শেষ করেছেন {0}",
"UserStartedPlayingItemWithValues": "{2}তে {1} প্লে করেছেন {0}",
- "UserPolicyUpdatedWithName": "{0} এর জন্য ব্যবহার নীতি আপডেট করা হয়েছে",
"UserPasswordChangedWithName": "ব্যবহারকারী {0} এর পাসওয়ার্ড পরিবর্তিত হয়েছে",
"UserOnlineFromDevice": "{0}, {1} থেকে অনলাইন আছে",
"UserOfflineFromDevice": "{0} {1} থেকে বিচ্ছিন্ন হয়ে গেছে",
@@ -33,23 +21,14 @@
"UserDownloadingItemWithValues": "{0}, {1} ডাউনলোড করছে",
"UserDeletedWithName": "ব্যবহারকারী {0}কে বাদ দেয়া হয়েছে",
"UserCreatedWithName": "ব্যবহারকারী {0} সৃষ্টি করা হয়েছে",
- "User": "ব্যবহারকারী",
"TvShows": "টিভি শোগুলো",
- "System": "সিস্টেম",
- "Sync": "সমন্বয় করুন",
"SubtitleDownloadFailureFromForItem": "{0} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ হয়েছে",
"StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
- "Songs": "সঙ্গীত সমূহ",
"Shows": "শো সমূহ",
- "ServerNameNeedsToBeRestarted": "{0} রিস্টার্ট করা প্রয়োজন",
- "ScheduledTaskStartedWithName": "{0} শুরু হয়েছে",
"ScheduledTaskFailedWithName": "{0} ব্যর্থ",
- "ProviderValue": "প্রদানকারী: {0}",
"PluginUpdatedWithName": "{0} আপডেট করা হয়েছে",
"PluginUninstalledWithName": "{0} আনইন্সটল হয়েছে",
"PluginInstalledWithName": "{0} ইন্সটল হয়েছে",
- "Plugin": "প্লাগিন",
- "Playlists": "প্লে লিস্ট সমূহ",
"Photos": "ছবিসমূহ",
"NotificationOptionVideoPlaybackStopped": "ভিডিও প্লেব্যাক বন্ধ হয়েছে",
"NotificationOptionVideoPlayback": "ভিডিও প্লেব্যাক শুরু হয়েছে",
@@ -75,21 +54,13 @@
"Music": "গান",
"Movies": "চলচ্চিত্রসমূহ",
"MixedContent": "মিশ্র কন্টেন্ট",
- "MessageServerConfigurationUpdated": "সার্ভারের কনফিগারেশন আপডেট করা হয়েছে",
- "HeaderRecordingGroups": "রেকর্ডিং গ্রুপগুলো",
- "MessageNamedServerConfigurationUpdatedWithValue": "সার্ভার কনফিগারেশন সেকশন {0} আপডেট করা হয়েছে",
- "MessageApplicationUpdatedTo": "জেলিফিন সার্ভার {0} তে আপডেট করা হয়েছে",
- "MessageApplicationUpdated": "জেলিফিন সার্ভার আপডেট করা হয়েছে",
"Latest": "সর্বশেষ",
"LabelRunningTimeValue": "চলার সময়: {0}",
"LabelIpAddressValue": "আইপি এড্রেস: {0}",
- "ItemRemovedWithName": "{0} লাইব্রেরি থেকে বাদ দেয়া হয়েছে",
- "ItemAddedWithName": "{0} লাইব্রেরিতে যোগ করা হয়েছে",
"Inherit": "উত্তরাধিকারসূত্র থেকে গ্রহণ করুন",
"HomeVideos": "হোম ভিডিও",
"HeaderNextUp": "এরপরে আসছে",
"HeaderLiveTV": "লাইভ টিভি",
- "HeaderFavoriteSongs": "প্রিয় গানগুলো",
"HeaderFavoriteShows": "প্রিয় শোগুলো",
"TasksLibraryCategory": "লাইব্রেরি",
"TasksMaintenanceCategory": "রক্ষণাবেক্ষণ",
diff --git a/Emby.Server.Implementations/Localization/Core/bs.json b/Emby.Server.Implementations/Localization/Core/bs.json
index 3bf5ebd35a..aa7fe4eb24 100644
--- a/Emby.Server.Implementations/Localization/Core/bs.json
+++ b/Emby.Server.Implementations/Localization/Core/bs.json
@@ -1,52 +1,32 @@
{
- "Albums": "Albumi",
"Artists": "Umjetnici",
"Books": "Knjige",
- "Channels": "Kanalima",
"Collections": "Zbirke",
"Default": "Zadano",
"Favorites": "Omiljeni",
"Folders": "Mape",
"Genres": "Žanrovi",
- "HeaderAlbumArtists": "Umjetnici albuma",
"HeaderContinueWatching": "Nastavi gledati",
"Movies": "Filmovi",
"MusicVideos": "Muzički spotovi",
"Photos": "Slike",
- "Playlists": "Plejliste",
"Shows": "Pokazuje",
- "Songs": "Pjesme",
- "ValueSpecialEpisodeName": "Posebno - {0}",
"AppDeviceValues": "Aplikacija: {0}, Uređaj: {1}",
- "Application": "Prijava",
"AuthenticationSucceededWithUserName": "{0} uspješno autentificirano",
- "CameraImageUploadedFrom": "Nova slika s kamere je postavljena sa {0}",
"ChapterNameValue": "Poglavlje {0}",
- "DeviceOfflineWithName": "{0} se odspojio",
- "DeviceOnlineWithName": "{0} je povezan",
"External": "Vanjsko",
"FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave sa {0}",
"Forced": "Prisilno",
- "HeaderFavoriteAlbums": "Omiljeni albumi",
- "HeaderFavoriteArtists": "Omiljeni umjetnici",
"HeaderFavoriteEpisodes": "Omiljene epizode",
"HeaderFavoriteShows": "Omiljene emisije",
- "HeaderFavoriteSongs": "Omiljene pjesme",
"HeaderLiveTV": "TV uživo",
"HeaderNextUp": "Slijedi",
- "HeaderRecordingGroups": "Grupe za snimanje",
"HearingImpaired": "Oštećen sluh",
"HomeVideos": "Kućni videozapisi",
"Inherit": "Nasljedi",
- "ItemAddedWithName": "{0} je dodan u biblioteku",
- "ItemRemovedWithName": "{0} je uklonjen iz biblioteke",
"LabelIpAddressValue": "IP adresa: {0}",
"LabelRunningTimeValue": "Trajanje: {0}",
"Latest": "Posljednje dodano",
- "MessageApplicationUpdated": "Jellyfin Server je ažuriran",
- "MessageApplicationUpdatedTo": "Jellyfin Server je ažuriran na {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Sekcija za konfiguraciju servera {0} je ažurirana",
- "MessageServerConfigurationUpdated": "Konfiguracija servera je ažurirana",
"MixedContent": "Miješani sadržaj",
"Music": "Muzika",
"NameInstallFailed": "{0} instalacija je propala",
@@ -69,21 +49,14 @@
"NotificationOptionUserLockedOut": "Korisnik je zaključan",
"NotificationOptionVideoPlayback": "Pokrenuto je reproduciranje videa",
"NotificationOptionVideoPlaybackStopped": "Reprodukcija videa je zaustavljena",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} je instaliran",
"PluginUninstalledWithName": "{0} je deinstaliran",
"PluginUpdatedWithName": "{0} je ažurirano",
- "ProviderValue": "Pružatelj: {0}",
"ScheduledTaskFailedWithName": "{0} nije uspjelo",
- "ScheduledTaskStartedWithName": "{0} počelo",
- "ServerNameNeedsToBeRestarted": "{0} treba ponovo pokrenuti",
"StartupEmbyServerIsLoading": "Jellyfin Server se učitava. Molimo pokušajte ponovo za kratko vrijeme.",
"SubtitleDownloadFailureFromForItem": "Podtitlovi nisu uspjeli preuzeti sa {0} za {1}",
- "Sync": "Sinkronizacija",
- "System": "Sistem",
"TvShows": "TV serije",
"Undefined": "Nedefinirano",
- "User": "Korisnik",
"UserCreatedWithName": "Korisnik {0} je kreiran",
"UserDeletedWithName": "Korisnik {0} je izbrisan",
"UserDownloadingItemWithValues": "{0} preuzima {1}",
@@ -91,10 +64,8 @@
"UserOfflineFromDevice": "{0} se odspojio od {1}",
"UserOnlineFromDevice": "{0} je online od {1}",
"UserPasswordChangedWithName": "Lozinka je promijenjena za korisnika {0}",
- "UserPolicyUpdatedWithName": "Pravila za korisnike su ažurirana za {0}",
"UserStartedPlayingItemWithValues": "{0} igra protiv {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je završio igru protiv {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} je dodan u vašu medijsku biblioteku",
"VersionNumber": "Verzija {0}",
"TasksMaintenanceCategory": "Održavanje",
"TasksLibraryCategory": "Biblioteka",
diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json
index 14838e8c34..1465a4d5e1 100644
--- a/Emby.Server.Implementations/Localization/Core/ca.json
+++ b/Emby.Server.Implementations/Localization/Core/ca.json
@@ -1,41 +1,24 @@
{
- "Albums": "Àlbums",
"AppDeviceValues": "Aplicació: {0}, Dispositiu: {1}",
- "Application": "Aplicació",
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} s'ha autenticat correctament",
"Books": "Llibres",
- "CameraImageUploadedFrom": "S'ha pujat una nova imatge de càmera des de {0}",
- "Channels": "Canals",
"ChapterNameValue": "Capítol {0}",
"Collections": "Col·leccions",
- "DeviceOfflineWithName": "{0} s'ha desconnectat",
- "DeviceOnlineWithName": "{0} està connectat",
"FailedLoginAttemptWithUserName": "Intent de connexió fallit des de {0}",
"Favorites": "Preferits",
"Folders": "Directoris",
"Genres": "Gèneres",
- "HeaderAlbumArtists": "Artistes de l'àlbum",
"HeaderContinueWatching": "Continueu mirant",
- "HeaderFavoriteAlbums": "Àlbums preferits",
- "HeaderFavoriteArtists": "Artistes preferits",
"HeaderFavoriteEpisodes": "Episodis preferits",
"HeaderFavoriteShows": "Sèries preferides",
- "HeaderFavoriteSongs": "Cançons preferides",
"HeaderLiveTV": "TV en directe",
"HeaderNextUp": "A continuació",
- "HeaderRecordingGroups": "Grups musicals",
"HomeVideos": "Vídeos domèstics",
"Inherit": "Heretat",
- "ItemAddedWithName": "{0} s'ha afegit a la mediateca",
- "ItemRemovedWithName": "{0} s'ha eliminat de la mediateca",
"LabelIpAddressValue": "Adreça IP: {0}",
"LabelRunningTimeValue": "Temps en marxa: {0}",
"Latest": "Darrers",
- "MessageApplicationUpdated": "El servidor de Jellyfin ha estat actualitzat",
- "MessageApplicationUpdatedTo": "El servidor de Jellyfin ha estat actualitzat a {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "La secció {0} de la configuració del servidor ha estat actualitzada",
- "MessageServerConfigurationUpdated": "S'ha actualitzat la configuració del servidor",
"MixedContent": "Contingut barrejat",
"Movies": "Pel·lícules",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Reproducció de vídeo iniciada",
"NotificationOptionVideoPlaybackStopped": "Reproducció de vídeo aturada",
"Photos": "Fotos",
- "Playlists": "Llistes de reproducció",
- "Plugin": "Complement",
"PluginInstalledWithName": "S'ha instal·lat {0}",
"PluginUninstalledWithName": "S'ha desinstal·lat {0}",
"PluginUpdatedWithName": "S'ha actualitzat {0}",
- "ProviderValue": "Proveïdor: {0}",
"ScheduledTaskFailedWithName": "{0} ha fallat",
- "ScheduledTaskStartedWithName": "S'ha iniciat {0}",
- "ServerNameNeedsToBeRestarted": "S'ha de reiniciar {0}",
"Shows": "Sèries",
- "Songs": "Cançons",
"StartupEmbyServerIsLoading": "El servidor de Jellyfin s'està carregant. Proveu-ho de nou en una estona.",
"SubtitleDownloadFailureFromForItem": "Els subtítols per a {1} no s'han pogut baixar de {0}",
- "Sync": "Sincronitza",
- "System": "Sistema",
"TvShows": "Sèries de TV",
- "User": "Usuari",
"UserCreatedWithName": "S'ha creat l'usuari {0}",
"UserDeletedWithName": "S'ha eliminat l'usuari {0}",
"UserDownloadingItemWithValues": "{0} està descarregant {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} s'ha desconnectat de {1}",
"UserOnlineFromDevice": "{0} està connectat des de {1}",
"UserPasswordChangedWithName": "S'ha canviat la contrasenya per a l'usuari {0}",
- "UserPolicyUpdatedWithName": "La política d'usuari s'ha actualitzat per a {0}",
"UserStartedPlayingItemWithValues": "{0} ha començat a reproduir {1} a {2}",
"UserStoppedPlayingItemWithValues": "{0} ha parat de reproduir {1} a {2}",
- "ValueHasBeenAddedToLibrary": "S'ha afegit {0} a la mediateca",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versió {0}",
"TaskDownloadMissingSubtitlesDescription": "Cerca a internet els subtítols que faltin a partir de la configuració de metadades.",
"TaskDownloadMissingSubtitles": "Descàrrega dels subtítols que faltin",
diff --git a/Emby.Server.Implementations/Localization/Core/chr.json b/Emby.Server.Implementations/Localization/Core/chr.json
index 85d1f4c881..7e039bafc2 100644
--- a/Emby.Server.Implementations/Localization/Core/chr.json
+++ b/Emby.Server.Implementations/Localization/Core/chr.json
@@ -1,44 +1,30 @@
{
"ChapterNameValue": "Didanedi {0}",
- "HeaderAlbumArtists": "Didanidanolisgisgi",
- "HeaderFavoriteAlbums": "Dvganidi didanidisgisgi",
"HeaderLiveTV": "Anigadi didanidisgosgi",
- "HeaderRecordingGroups": "Didanisquodiisgisgi",
"HomeVideos": "Diganadi dinagadisgisgi",
"Inherit": "Anigwe",
- "MessageApplicationUpdatedTo": "Tsenigwidinonvhi Jellyfin Server tsadanidigwe anigadi {0}",
"MixedContent": "Ganinidi dininoladisgisgi",
"Movies": "Anidvnisgisgi",
"MusicVideos": "Danodisgisgi didanidisgosgi",
"NotificationOptionAudioPlayback": "Didanidigwe diganuyisgisgi anigadi",
"NotificationOptionInstallationFailed": "Diudvdi anadvnatisgisgi",
"NotificationOptionPluginUninstalled": "Ditsigvhnidv anawvdisgisgi",
- "Albums": "Anigawidaniyv",
- "Application": "Didanvyi",
"Artists": "Dinidaniyi",
"AuthenticationSucceededWithUserName": "{0} Sesoquonisdi nagadani",
"Books": "Didanedi",
- "CameraImageUploadedFrom": "Anigawidaniyv nasgi didagwalanvyi {0}",
- "Channels": "Diganadasgi",
"Collections": "Diganadisgi",
"Default": "Dinadi",
- "DeviceOfflineWithName": "{0} Aniyvolehvi nasgi",
"External": "Amohdi",
"Favorites": "Nvdayelvdisgi",
"Folders": "Didanididisgi",
"Forced": "Ganedi",
"Genres": "Diganadisgi",
"HeaderContinueWatching": "Uwoditsu asdanidisgisgi",
- "HeaderFavoriteArtists": "Dvganidi dinidanolisgisgi",
"HeaderFavoriteEpisodes": "Dvganidi didanidilisgadisgisgi",
"HeaderFavoriteShows": "Dvganidi didanididanolisgisgi)",
- "HeaderFavoriteSongs": "Dvganidi danodisgisgi",
"HeaderNextUp": "Anidvli uwodoli",
"HearingImpaired": "Anitsunidi talunidisgisgi",
- "ItemAddedWithName": "{0} Dinigwe anididanidisgi",
"Latest": "Uwodoli",
- "MessageApplicationUpdated": "Tsenigwidinonvhi Jellyfin Server tsadanidigwe",
- "MessageServerConfigurationUpdated": "Sedanidvdi anigadi diganidinonvhi",
"Music": "Danodisgisgi",
"NameSeasonUnknown": "Tsunita anidvdisgi",
"NewVersionIsAvailable": "Danodigwe anigadi Jellyfin Server tsadanidigwe adisdi uwodvdi diganidinonvhi.",
diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json
index 3fc1895842..9e3d4456a8 100644
--- a/Emby.Server.Implementations/Localization/Core/cs.json
+++ b/Emby.Server.Implementations/Localization/Core/cs.json
@@ -1,41 +1,24 @@
{
- "Albums": "Alba",
"AppDeviceValues": "Aplikace: {0}, Zařízení: {1}",
- "Application": "Aplikace",
"Artists": "Umělci",
"AuthenticationSucceededWithUserName": "{0} úspěšně ověřen",
"Books": "Knihy",
- "CameraImageUploadedFrom": "Z {0} byla nahrána nová fotografie z fotoaparátu",
- "Channels": "Kanály",
"ChapterNameValue": "Kapitola {0}",
"Collections": "Kolekce",
- "DeviceOfflineWithName": "{0} se odpojil",
- "DeviceOnlineWithName": "{0} je připojen",
"FailedLoginAttemptWithUserName": "Neúspěšný pokus o přihlášení z {0}",
"Favorites": "Oblíbené",
"Folders": "Složky",
"Genres": "Žánry",
- "HeaderAlbumArtists": "Umělci alba",
"HeaderContinueWatching": "Pokračovat ve sledování",
- "HeaderFavoriteAlbums": "Oblíbená alba",
- "HeaderFavoriteArtists": "Oblíbení interpreti",
"HeaderFavoriteEpisodes": "Oblíbené epizody",
"HeaderFavoriteShows": "Oblíbené seriály",
- "HeaderFavoriteSongs": "Oblíbená hudba",
"HeaderLiveTV": "TV vysílání",
"HeaderNextUp": "Další díly",
- "HeaderRecordingGroups": "Skupiny nahrávek",
"HomeVideos": "Domácí videa",
"Inherit": "Zdědit",
- "ItemAddedWithName": "{0} byl přidán do knihovny",
- "ItemRemovedWithName": "{0} byl odstraněn z knihovny",
"LabelIpAddressValue": "IP adresa: {0}",
"LabelRunningTimeValue": "Délka média: {0}",
"Latest": "Nejnovější",
- "MessageApplicationUpdated": "Jellyfin Server byl aktualizován",
- "MessageApplicationUpdatedTo": "Jellyfin server byl aktualizován na verzi {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurace sekce {0} na serveru byla aktualizována",
- "MessageServerConfigurationUpdated": "Konfigurace serveru aktualizována",
"MixedContent": "Smíšený obsah",
"Movies": "Filmy",
"Music": "Hudba",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Přehrávání videa zahájeno",
"NotificationOptionVideoPlaybackStopped": "Přehrávání videa ukončeno",
"Photos": "Fotky",
- "Playlists": "Seznamy skladeb",
- "Plugin": "Zásuvný modul",
"PluginInstalledWithName": "{0} byl nainstalován",
"PluginUninstalledWithName": "{0} byl odinstalován",
"PluginUpdatedWithName": "{0} byl aktualizován",
- "ProviderValue": "Poskytl: {0}",
"ScheduledTaskFailedWithName": "{0} selhalo",
- "ScheduledTaskStartedWithName": "{0} zahájeno",
- "ServerNameNeedsToBeRestarted": "{0} vyžaduje restart",
"Shows": "Seriály",
- "Songs": "Skladby",
"StartupEmbyServerIsLoading": "Jellyfin Server je spouštěn. Zkuste to prosím v brzké době znovu.",
"SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
- "Sync": "Synchronizace",
- "System": "Systém",
"TvShows": "Seriály",
- "User": "Uživatel",
"UserCreatedWithName": "Uživatel {0} byl vytvořen",
"UserDeletedWithName": "Uživatel {0} byl smazán",
"UserDownloadingItemWithValues": "{0} stahuje {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} se odpojil ze zařízení {1}",
"UserOnlineFromDevice": "{0} se připojil ze zařízení {1}",
"UserPasswordChangedWithName": "Provedena změna hesla pro uživatele {0}",
- "UserPolicyUpdatedWithName": "Zásady uživatele pro {0} byly aktualizovány",
"UserStartedPlayingItemWithValues": "{0} spustil přehrávání {1}",
"UserStoppedPlayingItemWithValues": "{0} zastavil přehrávání {1}",
- "ValueHasBeenAddedToLibrary": "{0} byl přidán do vaší knihovny médií",
- "ValueSpecialEpisodeName": "Speciál - {0}",
"VersionNumber": "Verze {0}",
"TaskDownloadMissingSubtitlesDescription": "Vyhledá na internetu chybějící titulky na základě nastavení metadat.",
"TaskDownloadMissingSubtitles": "Stáhnout chybějící titulky",
diff --git a/Emby.Server.Implementations/Localization/Core/cy.json b/Emby.Server.Implementations/Localization/Core/cy.json
index af0e89bf80..e4d8ee7731 100644
--- a/Emby.Server.Implementations/Localization/Core/cy.json
+++ b/Emby.Server.Implementations/Localization/Core/cy.json
@@ -1,16 +1,11 @@
{
- "DeviceOnlineWithName": "Mae {0} wedi'i gysylltu",
- "DeviceOfflineWithName": "Mae {0} wedi datgysylltu",
"Default": "Diofyn",
"Collections": "Casgliadau",
"ChapterNameValue": "Pennod {0}",
- "Channels": "Sianeli",
- "CameraImageUploadedFrom": "Mae delwedd camera newydd wedi'i lanlwytho o {0}",
"Books": "Llyfrau",
"AuthenticationSucceededWithUserName": "{0} wedi’i ddilysu’n llwyddiannus",
"Artists": "Crewyr",
"AppDeviceValues": "Ap: {0}, Dyfais: {1}",
- "Albums": "Albwmau",
"Genres": "Genres",
"Folders": "Ffolderi",
"Favorites": "Ffefrynnau",
@@ -20,9 +15,7 @@
"TaskRefreshPeople": "Adnewyddu Pobl",
"TasksChannelsCategory": "Sianeli Internet",
"VersionNumber": "Fersiwn {0}",
- "ScheduledTaskStartedWithName": "{0} wedi dechrau",
"ScheduledTaskFailedWithName": "{0} wedi methu",
- "ProviderValue": "Darparwr: {0}",
"NotificationOptionInstallationFailed": "Fethu Gosod",
"NameSeasonUnknown": "Tymor Anhysbys",
"NameSeasonNumber": "Tymor {0}",
@@ -30,31 +23,20 @@
"MixedContent": "Cynnwys amrywiol",
"HomeVideos": "Genres",
"HeaderNextUp": "Nesaf i Fyny",
- "HeaderFavoriteArtists": "Ffefryn Artistiaid",
- "HeaderFavoriteAlbums": "Ffefryn Albwmau",
"HeaderContinueWatching": "Parhewch i Wylio",
"TasksApplicationCategory": "Rhaglen",
"TasksLibraryCategory": "Llyfrgell",
"TasksMaintenanceCategory": "Cynnal a Chadw",
- "System": "System",
- "Plugin": "Ategyn",
"Music": "Cerddoriaeth",
"Latest": "Diweddaraf",
"Inherit": "Etifeddu",
"Forced": "Orfodi",
- "Application": "Rhaglen",
- "HeaderAlbumArtists": "Artistiaid albwm",
- "Sync": "Cysoni",
- "Songs": "Caneuon",
"Shows": "Rhaglenni",
- "Playlists": "Rhestri Chwarae",
"Photos": "Lluniau",
- "ValueSpecialEpisodeName": "Arbennig - {0}",
"Movies": "Ffilmiau",
"Undefined": "Heb ddiffiniad",
"TvShows": "Rhaglenni teledu",
"HeaderLiveTV": "Teledu Byw",
- "User": "Defnyddiwr",
"TaskCleanLogsDescription": "Dileu ffeiliau log sy'n fwy na {0} diwrnod oed.",
"TaskCleanLogs": "Glanhau ffolder log",
"TaskRefreshLibraryDescription": "Sganio'ch llyfrgell gyfryngau am ffeiliau newydd ac yn adnewyddu metaddata.",
@@ -65,13 +47,9 @@
"NotificationOptionPluginError": "Methodd ategyn",
"NotificationOptionAudioPlaybackStopped": "Stopiwyd chwarae sain",
"NotificationOptionAudioPlayback": "Dechreuwyd chwarae sain",
- "MessageServerConfigurationUpdated": "Mae gosodiadau gweinydd wedi'i ddiweddaru",
- "MessageNamedServerConfigurationUpdatedWithValue": "Mae adran gosodiadau gweinydd {0} wedi'i diweddaru",
"FailedLoginAttemptWithUserName": "Cais mewngofnodi wedi methu o {0}",
- "ValueHasBeenAddedToLibrary": "{0} wedi'i hychwanegu at eich llyfrgell gyfryngau",
"UserStoppedPlayingItemWithValues": "{0} wedi gorffen chwarae {1} ar {2}",
"UserStartedPlayingItemWithValues": "{0} yn chwarae {1} ar {2}",
- "UserPolicyUpdatedWithName": "Polisi defnyddiwr wedi'i newid ar gyfer {0}",
"UserPasswordChangedWithName": "Cyfrinair wedi'i newid ar gyfer defnyddiwr {0}",
"UserOnlineFromDevice": "Mae {0} ar-lein o {1}",
"UserOfflineFromDevice": "Mae {0} wedi datgysylltu o {1}",
@@ -80,7 +58,6 @@
"UserDeletedWithName": "Defnyddiwr {0} wedi'i ddileu",
"UserCreatedWithName": "Defnyddiwr {0} wedi'i greu",
"StartupEmbyServerIsLoading": "Gweinydd Jellyfin yn llwytho. Triwch eto mewn ychydig.",
- "ServerNameNeedsToBeRestarted": "Mae angen ailddechrau {0}",
"PluginUpdatedWithName": "{0} wedi'i ddiweddaru",
"PluginUninstalledWithName": "{0} wedi'i ddadosod",
"PluginInstalledWithName": "{0} wedi'i osod",
@@ -98,13 +75,7 @@
"NotificationOptionApplicationUpdateAvailable": "Diweddariad ap ar gael",
"NewVersionIsAvailable": "Mae fersiwn diweddarach o'r gweinydd Jellyfin ar gael.",
"NameInstallFailed": "Gosodiad {0} wedi methu",
- "MessageApplicationUpdatedTo": "Gweinydd Jellyfin wedi'i ddiweddaru i {0}",
- "MessageApplicationUpdated": "Gweinydd Jellyfin wedi'i ddiweddaru",
"LabelIpAddressValue": "Cyfeiriad IP: {0}",
- "ItemRemovedWithName": "{0} wedi'i dynnu o'r llyfrgell",
- "ItemAddedWithName": "{0} wedi'i adio i'r llyfrgell",
- "HeaderRecordingGroups": "Grwpiau Recordio",
- "HeaderFavoriteSongs": "Ffefryn Ganeuon",
"HeaderFavoriteShows": "Ffefryn Shoeau",
"HeaderFavoriteEpisodes": "Ffefryn Rhaglenni",
"TaskDownloadMissingSubtitlesDescription": "Chwilio'r rhyngrwyd am is-deitlau coll yn seiliedig ar gosodiadau metaddata.",
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index 7d905f3300..e30528b3cd 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albummer",
"AppDeviceValues": "App: {0}, Enhed: {1}",
- "Application": "Applikation",
"Artists": "Kunstnere",
"AuthenticationSucceededWithUserName": "{0} er logget ind",
"Books": "Bøger",
- "CameraImageUploadedFrom": "Et nyt kamerabillede er blevet uploadet fra {0}",
- "Channels": "Kanaler",
"ChapterNameValue": "Kapitel {0}",
"Collections": "Samlinger",
- "DeviceOfflineWithName": "{0} har afbrudt forbindelsen",
- "DeviceOnlineWithName": "{0} er forbundet",
"FailedLoginAttemptWithUserName": "Mislykket loginforsøg fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
"Genres": "Genrer",
- "HeaderAlbumArtists": "Albumkunstnere",
"HeaderContinueWatching": "Fortsæt afspilning",
- "HeaderFavoriteAlbums": "Favoritalbum",
- "HeaderFavoriteArtists": "Favoritkunstnere",
"HeaderFavoriteEpisodes": "Yndlingsafsnit",
"HeaderFavoriteShows": "Yndlingsserier",
- "HeaderFavoriteSongs": "Yndlingssange",
"HeaderLiveTV": "Live-TV",
"HeaderNextUp": "Næste",
- "HeaderRecordingGroups": "Optagelsesgrupper",
"HomeVideos": "Hjemmevideoer",
"Inherit": "Nedarv",
- "ItemAddedWithName": "{0} blev tilføjet til biblioteket",
- "ItemRemovedWithName": "{0} blev fjernet fra biblioteket",
"LabelIpAddressValue": "IP-adresse: {0}",
"LabelRunningTimeValue": "Spilletid: {0}",
"Latest": "Seneste",
- "MessageApplicationUpdated": "Jellyfin Server er blevet opdateret",
- "MessageApplicationUpdatedTo": "Jellyfin Server er blevet opdateret til {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfiguration sektion {0} er blevet opdateret",
- "MessageServerConfigurationUpdated": "Serverkonfigurationen er blevet opdateret",
"MixedContent": "Blandet indhold",
"Movies": "Film",
"Music": "Musik",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Videoafspilning påbegyndt",
"NotificationOptionVideoPlaybackStopped": "Videoafspilning blev stoppet",
"Photos": "Fotos",
- "Playlists": "Afspilningslister",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} blev installeret",
"PluginUninstalledWithName": "{0} blev afinstalleret",
"PluginUpdatedWithName": "{0} blev opdateret",
- "ProviderValue": "Udbyder: {0}",
"ScheduledTaskFailedWithName": "{0} mislykkedes",
- "ScheduledTaskStartedWithName": "{0} påbegyndte",
- "ServerNameNeedsToBeRestarted": "{0} skal genstartes",
"Shows": "Serier",
- "Songs": "Sange",
"StartupEmbyServerIsLoading": "Jellyfin er i gang med at starte. Prøv igen om et øjeblik.",
"SubtitleDownloadFailureFromForItem": "Undertekster kunne ikke hentes fra {0} til {1}",
- "Sync": "Synkroniser",
- "System": "System",
"TvShows": "TV-serier",
- "User": "Bruger",
"UserCreatedWithName": "Bruger {0} er blevet oprettet",
"UserDeletedWithName": "Brugeren {0} er nu slettet",
"UserDownloadingItemWithValues": "{0} henter {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} har afbrudt fra {1}",
"UserOnlineFromDevice": "{0} er online fra {1}",
"UserPasswordChangedWithName": "Adgangskode er ændret for brugeren {0}",
- "UserPolicyUpdatedWithName": "Brugerpolitikken er blevet opdateret for {0}",
"UserStartedPlayingItemWithValues": "{0} afspiller {1} på {2}",
"UserStoppedPlayingItemWithValues": "{0} har afsluttet afspilning af {1} på {2}",
- "ValueHasBeenAddedToLibrary": "{0} er blevet tilføjet til dit mediebibliotek",
- "ValueSpecialEpisodeName": "Special - {0}",
"VersionNumber": "Version {0}",
"TaskDownloadMissingSubtitlesDescription": "Søger på internettet efter manglende undertekster baseret på metadata-konfigurationen.",
"TaskDownloadMissingSubtitles": "Hent manglende undertekster",
diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json
index b628f45ea7..8ac5fdf6fc 100644
--- a/Emby.Server.Implementations/Localization/Core/de.json
+++ b/Emby.Server.Implementations/Localization/Core/de.json
@@ -1,41 +1,24 @@
{
- "Albums": "Alben",
"AppDeviceValues": "App: {0}, Gerät: {1}",
- "Application": "Anwendung",
"Artists": "Interpreten",
"AuthenticationSucceededWithUserName": "{0} erfolgreich authentifiziert",
"Books": "Bücher",
- "CameraImageUploadedFrom": "Ein neues Kamerabild wurde von {0} hochgeladen",
- "Channels": "Kanäle",
"ChapterNameValue": "Kapitel {0}",
"Collections": "Sammlungen",
- "DeviceOfflineWithName": "{0} ist offline",
- "DeviceOnlineWithName": "{0} ist online",
"FailedLoginAttemptWithUserName": "Anmeldung von {0} fehlgeschlagen",
"Favorites": "Favoriten",
"Folders": "Verzeichnisse",
"Genres": "Genres",
- "HeaderAlbumArtists": "Album-Interpreten",
"HeaderContinueWatching": "Weiterschauen",
- "HeaderFavoriteAlbums": "Lieblingsalben",
- "HeaderFavoriteArtists": "Lieblingsinterpreten",
"HeaderFavoriteEpisodes": "Lieblingsfolgen",
"HeaderFavoriteShows": "Lieblingsserien",
- "HeaderFavoriteSongs": "Lieblingssongs",
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Als Nächstes",
- "HeaderRecordingGroups": "Aufnahme-Gruppen",
"HomeVideos": "Heimvideos",
"Inherit": "Vererben",
- "ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
- "ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
"LabelIpAddressValue": "IP-Adresse: {0}",
"LabelRunningTimeValue": "Laufzeit: {0}",
"Latest": "Neueste",
- "MessageApplicationUpdated": "Jellyfin-Server wurde aktualisiert",
- "MessageApplicationUpdatedTo": "Jellyfin-Server wurde auf Version {0} aktualisiert",
- "MessageNamedServerConfigurationUpdatedWithValue": "Der Server-Einstellungsbereich {0} wurde aktualisiert",
- "MessageServerConfigurationUpdated": "Servereinstellungen wurden aktualisiert",
"MixedContent": "Gemischte Inhalte",
"Movies": "Filme",
"Music": "Musik",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Video wird abgespielt",
"NotificationOptionVideoPlaybackStopped": "Videowiedergabe gestoppt",
"Photos": "Fotos",
- "Playlists": "Wiedergabelisten",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} wurde installiert",
"PluginUninstalledWithName": "{0} wurde deinstalliert",
"PluginUpdatedWithName": "{0} wurde aktualisiert",
- "ProviderValue": "Anbieter: {0}",
"ScheduledTaskFailedWithName": "{0} ist fehlgeschlagen",
- "ScheduledTaskStartedWithName": "{0} wurde gestartet",
- "ServerNameNeedsToBeRestarted": "{0} muss neu gestartet werden",
"Shows": "Serien",
- "Songs": "Lieder",
"StartupEmbyServerIsLoading": "Jellyfin-Server lädt. Bitte versuche es gleich noch einmal.",
"SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
- "Sync": "Synchronisation",
- "System": "System",
"TvShows": "Serien",
- "User": "Benutzer",
"UserCreatedWithName": "Benutzer {0} wurde erstellt",
"UserDeletedWithName": "Benutzer {0} wurde gelöscht",
"UserDownloadingItemWithValues": "{0} lädt {1} herunter",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} wurde getrennt von {1}",
"UserOnlineFromDevice": "{0} ist online von {1}",
"UserPasswordChangedWithName": "Das Passwort für Benutzer {0} wurde geändert",
- "UserPolicyUpdatedWithName": "Benutzerrichtlinie von {0} wurde aktualisiert",
"UserStartedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} gestartet",
"UserStoppedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} beendet",
- "ValueHasBeenAddedToLibrary": "{0} wurde deiner Bibliothek hinzugefügt",
- "ValueSpecialEpisodeName": "Extra – {0}",
"VersionNumber": "Version {0}",
"TaskDownloadMissingSubtitlesDescription": "Sucht im Internet basierend auf den Metadaten-Einstellungen nach fehlenden Untertiteln.",
"TaskDownloadMissingSubtitles": "Fehlende Untertitel herunterladen",
@@ -136,5 +107,6 @@
"TaskMoveTrickplayImagesDescription": "Trickplay-Bilder werden entsprechend der Bibliothekseinstellungen verschoben.",
"CleanupUserDataTask": "Aufgabe zur Bereinigung von Benutzerdaten",
"CleanupUserDataTaskDescription": "Löscht alle Benutzerdaten (Abspielstatus, Favoritenstatus, usw.) von Medien, die seit mindestens 90 Tagen nicht mehr vorhanden sind.",
- "Original": "Original"
+ "Original": "Original",
+ "LyricDownloadFailureFromForItem": "Fehler beim Download der Songtexte von {0} für {1}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/el.json b/Emby.Server.Implementations/Localization/Core/el.json
index 0443207ea6..d84afdc1b6 100644
--- a/Emby.Server.Implementations/Localization/Core/el.json
+++ b/Emby.Server.Implementations/Localization/Core/el.json
@@ -1,41 +1,24 @@
{
- "Albums": "Άλμπουμ",
"AppDeviceValues": "Εφαρμογή: {0}, Συσκευή: {1}",
- "Application": "Εφαρμογή",
"Artists": "Καλλιτέχνες",
"AuthenticationSucceededWithUserName": "Ο χρήστης {0} επαληθεύτηκε επιτυχώς",
"Books": "Βιβλία",
- "CameraImageUploadedFrom": "Μια νέα φωτογραφία φορτώθηκε από {0}",
- "Channels": "Κανάλια",
"ChapterNameValue": "Κεφάλαιο {0}",
"Collections": "Συλλογές",
- "DeviceOfflineWithName": "Ο/Η {0} αποσυνδέθηκε",
- "DeviceOnlineWithName": "Ο/Η {0} συνδέθηκε",
"FailedLoginAttemptWithUserName": "Αποτυχία προσπάθειας σύνδεσης από {0}",
"Favorites": "Αγαπημένα",
"Folders": "Φάκελοι",
"Genres": "Είδη",
- "HeaderAlbumArtists": "Καλλιτέχνες άλμπουμ",
"HeaderContinueWatching": "Συνεχίστε την παρακολούθηση",
- "HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ",
- "HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες",
"HeaderFavoriteEpisodes": "Αγαπημένα Επεισόδια",
"HeaderFavoriteShows": "Αγαπημένες Σειρές",
- "HeaderFavoriteSongs": "Αγαπημένα Τραγούδια",
"HeaderLiveTV": "Ζωντανή Τηλεόραση",
"HeaderNextUp": "Επόμενο",
- "HeaderRecordingGroups": "Ομάδες Ηχογράφησης",
"HomeVideos": "Προσωπικά Βίντεο",
"Inherit": "Κληρονόμηση",
- "ItemAddedWithName": "Το {0} προστέθηκε στη βιβλιοθήκη",
- "ItemRemovedWithName": "Το {0} διαγράφτηκε από τη βιβλιοθήκη",
"LabelIpAddressValue": "Διεύθυνση IP: {0}",
"LabelRunningTimeValue": "Διάρκεια: {0}",
"Latest": "Πρόσφατα",
- "MessageApplicationUpdated": "Ο διακομιστής Jellyfin έχει ενημερωθεί",
- "MessageApplicationUpdatedTo": "Ο διακομιστής Jellyfin αναβαθμίστηκε στην έκδοση {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Η ενότητα {0} ρύθμισης παραμέτρων του διακομιστή έχει ενημερωθεί",
- "MessageServerConfigurationUpdated": "Η ρύθμιση παραμέτρων του διακομιστή έχει ενημερωθεί",
"MixedContent": "Ανάμεικτο Περιεχόμενο",
"Movies": "Ταινίες",
"Music": "Μουσική",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Η αναπαραγωγή βίντεο ξεκίνησε",
"NotificationOptionVideoPlaybackStopped": "Η αναπαραγωγή βίντεο σταμάτησε",
"Photos": "Φωτογραφίες",
- "Playlists": "Λίστες αναπαραγωγής",
- "Plugin": "Πρόσθετο",
"PluginInstalledWithName": "Το {0} εγκαταστάθηκε",
"PluginUninstalledWithName": "Το {0} έχει απεγκατασταθεί",
"PluginUpdatedWithName": "Το {0} ενημερώθηκε",
- "ProviderValue": "Πάροχος: {0}",
"ScheduledTaskFailedWithName": "{0} αποτυχία",
- "ScheduledTaskStartedWithName": "{0} ξεκίνησε",
- "ServerNameNeedsToBeRestarted": "{0} χρειάζεται επανεκκίνηση",
"Shows": "Σειρές",
- "Songs": "Τραγούδια",
"StartupEmbyServerIsLoading": "Ο διακομιστής Jellyfin φορτώνει. Περιμένετε λίγο και δοκιμάστε ξανά.",
"SubtitleDownloadFailureFromForItem": "Αποτυχίες μεταφόρτωσης υποτίτλων από {0} για {1}",
- "Sync": "Συγχρονισμός",
- "System": "Σύστημα",
"TvShows": "Τηλεοπτικές Σειρές",
- "User": "Χρήστης",
"UserCreatedWithName": "Ο χρήστης {0} δημιουργήθηκε",
"UserDeletedWithName": "Ο χρήστης {0} έχει διαγραφεί",
"UserDownloadingItemWithValues": "{0} κατεβάζει {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} αποσυνδέθηκε από {1}",
"UserOnlineFromDevice": "{0} είναι online απο {1}",
"UserPasswordChangedWithName": "Ο κωδικός του χρήστη {0} έχει αλλάξει",
- "UserPolicyUpdatedWithName": "Η πολιτική χρήστη έχει ενημερωθεί για {0}",
"UserStartedPlayingItemWithValues": "{0} παίζει {1} σε {2}",
"UserStoppedPlayingItemWithValues": "{0} τελείωσε να παίζει {1} σε {2}",
- "ValueHasBeenAddedToLibrary": "{0} προστέθηκαν στη βιβλιοθήκη πολυμέσων σας",
- "ValueSpecialEpisodeName": "Σπέσιαλ - {0}",
"VersionNumber": "Έκδοση {0}",
"TaskRefreshPeople": "Ανανέωση Ατόμων",
"TaskCleanLogsDescription": "Διαγράφει αρχεία καταγραφής που είναι πάνω από {0} ημέρες.",
diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json
index b0094e33c3..be152b515f 100644
--- a/Emby.Server.Implementations/Localization/Core/en-GB.json
+++ b/Emby.Server.Implementations/Localization/Core/en-GB.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albums",
"AppDeviceValues": "App: {0}, Device: {1}",
- "Application": "Application",
"Artists": "Artists",
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
"Books": "Books",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
- "Channels": "Channels",
"ChapterNameValue": "Chapter {0}",
"Collections": "Collections",
- "DeviceOfflineWithName": "{0} has disconnected",
- "DeviceOnlineWithName": "{0} is connected",
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favourites",
"Folders": "Folders",
"Genres": "Genres",
- "HeaderAlbumArtists": "Album artists",
"HeaderContinueWatching": "Continue Watching",
- "HeaderFavoriteAlbums": "Favourite Albums",
- "HeaderFavoriteArtists": "Favourite Artists",
"HeaderFavoriteEpisodes": "Favourite Episodes",
"HeaderFavoriteShows": "Favourite Shows",
- "HeaderFavoriteSongs": "Favourite Songs",
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Next Up",
- "HeaderRecordingGroups": "Recording Groups",
"HomeVideos": "Home Videos",
"Inherit": "Inherit",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
"LabelIpAddressValue": "IP address: {0}",
"LabelRunningTimeValue": "Running time: {0}",
"Latest": "Latest",
- "MessageApplicationUpdated": "Jellyfin Server has been updated",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
"MixedContent": "Mixed content",
"Movies": "Movies",
"Music": "Music",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Video playback started",
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
"Photos": "Photos",
- "Playlists": "Playlists",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} was installed",
"PluginUninstalledWithName": "{0} was uninstalled",
"PluginUpdatedWithName": "{0} was updated",
- "ProviderValue": "Provider: {0}",
"ScheduledTaskFailedWithName": "{0} failed",
- "ScheduledTaskStartedWithName": "{0} started",
- "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
"Shows": "Shows",
- "Songs": "Songs",
"StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
- "Sync": "Sync",
- "System": "System",
"TvShows": "TV Shows",
- "User": "User",
"UserCreatedWithName": "User {0} has been created",
"UserDeletedWithName": "User {0} has been deleted",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} has disconnected from {1}",
"UserOnlineFromDevice": "{0} is online from {1}",
"UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
"UserStartedPlayingItemWithValues": "{0} has started playing {1}",
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
- "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
- "ValueSpecialEpisodeName": "Special - {0}",
"VersionNumber": "Version {0}",
"TaskDownloadMissingSubtitlesDescription": "Searches the internet for missing subtitles based on metadata configuration.",
"TaskDownloadMissingSubtitles": "Download missing subtitles",
diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json
index 9b5049c8c7..856941c61a 100644
--- a/Emby.Server.Implementations/Localization/Core/en-US.json
+++ b/Emby.Server.Implementations/Localization/Core/en-US.json
@@ -1,45 +1,29 @@
{
- "Albums": "Albums",
"AppDeviceValues": "App: {0}, Device: {1}",
- "Application": "Application",
"Artists": "Artists",
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
"Books": "Books",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
- "Channels": "Channels",
"ChapterNameValue": "Chapter {0}",
"Collections": "Collections",
"Default": "Default",
- "DeviceOfflineWithName": "{0} has disconnected",
- "DeviceOnlineWithName": "{0} is connected",
"External": "External",
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Forced": "Forced",
"Genres": "Genres",
- "HeaderAlbumArtists": "Album artists",
"HeaderContinueWatching": "Continue Watching",
- "HeaderFavoriteAlbums": "Favorite Albums",
- "HeaderFavoriteArtists": "Favorite Artists",
"HeaderFavoriteEpisodes": "Favorite Episodes",
"HeaderFavoriteShows": "Favorite Shows",
- "HeaderFavoriteSongs": "Favorite Songs",
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Next Up",
- "HeaderRecordingGroups": "Recording Groups",
"HearingImpaired": "Hearing Impaired",
"HomeVideos": "Home Videos",
"Inherit": "Inherit",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
"LabelIpAddressValue": "IP address: {0}",
"LabelRunningTimeValue": "Running time: {0}",
"Latest": "Latest",
- "MessageApplicationUpdated": "Jellyfin Server has been updated",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
+ "LyricDownloadFailureFromForItem": "Lyrics failed to download from {0} for {1}",
"MixedContent": "Mixed content",
"Movies": "Movies",
"Music": "Music",
@@ -66,24 +50,15 @@
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
"Original": "Original",
"Photos": "Photos",
- "Playlists": "Playlists",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} was installed",
"PluginUninstalledWithName": "{0} was uninstalled",
"PluginUpdatedWithName": "{0} was updated",
- "ProviderValue": "Provider: {0}",
"ScheduledTaskFailedWithName": "{0} failed",
- "ScheduledTaskStartedWithName": "{0} started",
- "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
"Shows": "Shows",
- "Songs": "Songs",
"StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
- "Sync": "Sync",
- "System": "System",
"TvShows": "TV Shows",
"Undefined": "Undefined",
- "User": "User",
"UserCreatedWithName": "User {0} has been created",
"UserDeletedWithName": "User {0} has been deleted",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
@@ -91,11 +66,8 @@
"UserOfflineFromDevice": "{0} has disconnected from {1}",
"UserOnlineFromDevice": "{0} is online from {1}",
"UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
"UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
- "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
- "ValueSpecialEpisodeName": "Special - {0}",
"VersionNumber": "Version {0}",
"TasksMaintenanceCategory": "Maintenance",
"TasksLibraryCategory": "Library",
diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json
index 42cce1096f..133a2755a8 100644
--- a/Emby.Server.Implementations/Localization/Core/eo.json
+++ b/Emby.Server.Implementations/Localization/Core/eo.json
@@ -7,35 +7,22 @@
"NameInstallFailed": "{0} instalado fiaskis",
"Music": "Muziko",
"Movies": "Filmoj",
- "ItemRemovedWithName": "{0} forigis el la plurmediteko",
- "ItemAddedWithName": "{0} aldonis al la plurmediteko",
"HeaderLiveTV": "TV-etero",
"HeaderContinueWatching": "Daŭrigi Spektadon",
- "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",
"TasksLibraryCategory": "Plurmediteko",
"VersionNumber": "Versio {0}",
"UserDownloadingItemWithValues": "{0} elŝutas {1}",
"UserCreatedWithName": "Uzanto {0} kreiĝis",
- "User": "Uzanto",
- "System": "Sistemo",
- "Songs": "Kantoj",
- "ScheduledTaskStartedWithName": "{0} lanĉis",
"ScheduledTaskFailedWithName": "{0} malsukcesis",
"PluginUninstalledWithName": "{0} malinstaliĝis",
"PluginInstalledWithName": "{0} instaliĝis",
- "Plugin": "Kromprogramo",
- "Playlists": "Ludlistoj",
"Photos": "Fotoj",
"NotificationOptionPluginUninstalled": "Kromprogramo malinstaliĝis",
"NotificationOptionNewLibraryContent": "Nova enhavo aldoniĝis",
@@ -43,36 +30,28 @@
"MusicVideos": "Muzikvideoj",
"LabelIpAddressValue": "IP-adreso: {0}",
"Genres": "Ĝenroj",
- "DeviceOfflineWithName": "{0} malkonektis",
- "HeaderFavoriteArtists": "Favorataj Artistoj",
"Shows": "Serioj",
"HeaderFavoriteShows": "Favorataj Serioj",
"TvShows": "TV-serioj",
"Favorites": "Favorataj",
"TaskCleanLogs": "Purigi Ĵurnalan Katalogon",
"TaskRefreshLibrary": "Skani Plurmeditekon",
- "ValueSpecialEpisodeName": "Speciala - {0}",
"TaskOptimizeDatabase": "Optimumigi datenbazon",
"TaskRefreshChannels": "Refreŝigi Kanalojn",
"TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn",
"TaskRefreshPeople": "Refreŝigi Homojn",
"TasksChannelsCategory": "Interretaj Kanaloj",
- "ProviderValue": "Provizanto: {0}",
"NotificationOptionPluginError": "Kromprogramo malsukcesis",
"MixedContent": "Miksita enhavo",
"TasksApplicationCategory": "Aplikaĵo",
"TasksMaintenanceCategory": "Prizorgado",
"Undefined": "Nedifinita",
- "Sync": "Sinkronigo",
"Latest": "Plej novaj",
"Inherit": "Hereda",
"HomeVideos": "Hejmaj Videoj",
"HeaderNextUp": "Sekva Plue",
- "HeaderFavoriteSongs": "Favorataj Kantoj",
"HeaderFavoriteEpisodes": "Favorataj Epizodoj",
- "HeaderFavoriteAlbums": "Favorataj Albumoj",
"Forced": "Forcita",
- "ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita",
"NotificationOptionVideoPlayback": "La videoludado lanĉis",
"NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata",
"TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la plurmediteka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.",
@@ -85,22 +64,16 @@
"TaskCleanCacheDescription": "Forigas stapla dosierojn ne plu necesajn de la sistemo.",
"TaskCleanActivityLogDescription": "Forigas aktivecan ĵurnalaĵojn pli malnovajn ol la agordita aĝo.",
"TaskCleanTranscodeDescription": "Forigas transkodajn dosierojn aĝajn pli ol unu tagon.",
- "ValueHasBeenAddedToLibrary": "{0} estis aldonita al via plurmediteko",
"SubtitleDownloadFailureFromForItem": "Subtekstoj malsukcesis elŝuti de {0} por {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server ŝarĝas. Provi denove baldaŭ.",
"TaskRefreshChapterImagesDescription": "Kreas bildetojn por videoj kiuj havas ĉapitrojn.",
"UserStoppedPlayingItemWithValues": "{0} finis ludi {1} ĉe {2}",
- "UserPolicyUpdatedWithName": "Uzanta politiko estis ĝisdatigita por {0}",
"UserPasswordChangedWithName": "Pasvorto estis ŝanĝita por uzanto {0}",
"UserStartedPlayingItemWithValues": "{0} ludas {1} ĉe {2}",
"UserLockedOutWithName": "Uzanto {0} estas elŝlosita",
"UserOnlineFromDevice": "{0} estas enreta de {1}",
"UserOfflineFromDevice": "{0} malkonektis de {1}",
"UserDeletedWithName": "Uzanto {0} estis forigita",
- "MessageServerConfigurationUpdated": "Servila agordaro estis ĝisdatigita",
- "MessageNamedServerConfigurationUpdatedWithValue": "Servila agorda sekcio {0} estis ĝisdatigita",
- "MessageApplicationUpdatedTo": "Jellyfin Server estis ĝisdatigita al {0}",
- "MessageApplicationUpdated": "Jellyfin Server estis ĝisdatigita",
"TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.",
"TaskDownloadMissingSubtitles": "Elŝuti mankantajn subtekstojn",
"TaskCleanTranscode": "Malplenigi Transkodadan Katalogon",
@@ -116,9 +89,7 @@
"NotificationOptionApplicationUpdateInstalled": "Aplikaĵa ĝisdatigo instalita",
"NotificationOptionApplicationUpdateAvailable": "Ĝisdatigo de aplikaĵo havebla",
"LabelRunningTimeValue": "Ludada tempo: {0}",
- "HeaderRecordingGroups": "Rikordadaj Grupoj",
"FailedLoginAttemptWithUserName": "Malsukcesa ensaluta provo de {0}",
- "CameraImageUploadedFrom": "Nova kamera bildo estis alŝutita de {0}",
"AuthenticationSucceededWithUserName": "{0} sukcese aŭtentikigis",
"TaskKeyframeExtractorDescription": "Eltiras ĉefkadrojn el videodosieroj por krei pli precizajn HLS-ludlistojn. Ĉi tiu tasko povas funkcii dum longa tempo.",
"TaskKeyframeExtractor": "Eltiri Ĉefkadrojn",
diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json
index 7fda507797..28366a41b7 100644
--- a/Emby.Server.Implementations/Localization/Core/es-AR.json
+++ b/Emby.Server.Implementations/Localization/Core/es-AR.json
@@ -1,41 +1,24 @@
{
- "Albums": "Álbumes",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
- "Application": "Aplicación",
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado correctamente",
"Books": "Libros",
- "CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}",
- "Channels": "Canales",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Colecciones",
- "DeviceOfflineWithName": "{0} se ha desconectado",
- "DeviceOnlineWithName": "{0} está conectado",
"FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Genres": "Géneros",
- "HeaderAlbumArtists": "Artistas del álbum",
"HeaderContinueWatching": "Seguir viendo",
- "HeaderFavoriteAlbums": "Álbumes favoritos",
- "HeaderFavoriteArtists": "Artistas favoritos",
"HeaderFavoriteEpisodes": "Capítulos favoritos",
"HeaderFavoriteShows": "Series favoritas",
- "HeaderFavoriteSongs": "Canciones favoritas",
"HeaderLiveTV": "TV en vivo",
"HeaderNextUp": "Siguiente",
- "HeaderRecordingGroups": "Grupos de grabación",
"HomeVideos": "Videos caseros",
"Inherit": "Heredar",
- "ItemAddedWithName": "{0} se ha añadido a la biblioteca",
- "ItemRemovedWithName": "{0} ha sido eliminado de la biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
"LabelRunningTimeValue": "Tiempo de funcionamiento: {0}",
"Latest": "Últimos",
- "MessageApplicationUpdated": "El servidor Jellyfin fue actualizado",
- "MessageApplicationUpdatedTo": "Se ha actualizado el servidor Jellyfin a la versión {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Se ha actualizado la sección {0} de la configuración del servidor",
- "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
"MixedContent": "Contenido mezclado",
"Movies": "Películas",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Se inició la reproducción de video",
"NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida",
"Photos": "Fotos",
- "Playlists": "Listas de reproducción",
- "Plugin": "Complemento",
"PluginInstalledWithName": "{0} fue instalado",
"PluginUninstalledWithName": "{0} fue desinstalado",
"PluginUpdatedWithName": "{0} fue actualizado",
- "ProviderValue": "Proveedor: {0}",
"ScheduledTaskFailedWithName": "{0} falló",
- "ScheduledTaskStartedWithName": "{0} iniciado",
- "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
"Shows": "Series",
- "Songs": "Canciones",
"StartupEmbyServerIsLoading": "El servidor Jellyfin se está cargando. Vuelve a intentarlo en breve.",
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtitulos desde {0} para {1}",
- "Sync": "Sincronizar",
- "System": "Sistema",
"TvShows": "Series de TV",
- "User": "Usuario",
"UserCreatedWithName": "El usuario {0} ha sido creado",
"UserDeletedWithName": "El usuario {0} ha sido borrado",
"UserDownloadingItemWithValues": "{0} está descargando {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} se ha desconectado de {1}",
"UserOnlineFromDevice": "{0} está en línea desde {1}",
"UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
- "UserPolicyUpdatedWithName": "Las política de usuario ha sido actualizada para {0}",
"UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}",
"UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
- "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versión {0}",
"TaskDownloadMissingSubtitlesDescription": "Busca en internet los subtítulos que falten basándose en la configuración de los metadatos.",
"TaskDownloadMissingSubtitles": "Descargar subtítulos faltantes",
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index d03d3ed2ff..ac489b9e77 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -1,41 +1,24 @@
{
- "Albums": "Álbumes",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
- "Application": "Aplicación",
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado con éxito",
"Books": "Libros",
- "CameraImageUploadedFrom": "Una nueva imagen de cámara ha sido subida desde {0}",
- "Channels": "Canales",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Colecciones",
- "DeviceOfflineWithName": "{0} se ha desconectado",
- "DeviceOnlineWithName": "{0} está conectado",
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Genres": "Géneros",
- "HeaderAlbumArtists": "Artistas del Álbum",
"HeaderContinueWatching": "Continuar viendo",
- "HeaderFavoriteAlbums": "Álbumes favoritos",
- "HeaderFavoriteArtists": "Artistas favoritos",
"HeaderFavoriteEpisodes": "Episodios favoritos",
"HeaderFavoriteShows": "Programas favoritos",
- "HeaderFavoriteSongs": "Canciones favoritas",
"HeaderLiveTV": "TV en vivo",
"HeaderNextUp": "A continuación",
- "HeaderRecordingGroups": "Grupos de grabación",
"HomeVideos": "Videos Caseros",
"Inherit": "Heredar",
- "ItemAddedWithName": "{0} fue agregado a la biblioteca",
- "ItemRemovedWithName": "{0} fue removido de la biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
"LabelRunningTimeValue": "Tiempo corriendo: {0}",
"Latest": "Recientes",
- "MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado",
- "MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Se ha actualizado la sección {0} de la configuración del servidor",
- "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
"MixedContent": "Contenido mezclado",
"Movies": "Películas",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Reproducción de video iniciada",
"NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida",
"Photos": "Fotos",
- "Playlists": "Listas de reproducción",
- "Plugin": "Complemento",
"PluginInstalledWithName": "{0} fue instalado",
"PluginUninstalledWithName": "{0} fue desinstalado",
"PluginUpdatedWithName": "{0} fue actualizado",
- "ProviderValue": "Proveedor: {0}",
"ScheduledTaskFailedWithName": "{0} falló",
- "ScheduledTaskStartedWithName": "{0} iniciado",
- "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
"Shows": "Programas",
- "Songs": "Canciones",
"StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo pronto.",
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtítulos desde {0} para {1}",
- "Sync": "Sincronizar",
- "System": "Sistema",
"TvShows": "Programas de TV",
- "User": "Usuario",
"UserCreatedWithName": "El usuario {0} ha sido creado",
"UserDeletedWithName": "El usuario {0} ha sido eliminado",
"UserDownloadingItemWithValues": "{0} está descargando {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} se ha desconectado desde {1}",
"UserOnlineFromDevice": "{0} está en línea desde {1}",
"UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
- "UserPolicyUpdatedWithName": "La política de usuario ha sido actualizada para {0}",
"UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}",
"UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
- "ValueHasBeenAddedToLibrary": "{0} se ha añadido a tu biblioteca de medios",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versión {0}",
"TaskDownloadMissingSubtitlesDescription": "Busca subtítulos faltantes en Internet basándose en la configuración de metadatos.",
"TaskDownloadMissingSubtitles": "Descargar subtítulos faltantes",
diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json
index 4f6a3544e4..d61ce396cb 100644
--- a/Emby.Server.Implementations/Localization/Core/es.json
+++ b/Emby.Server.Implementations/Localization/Core/es.json
@@ -1,41 +1,24 @@
{
- "Albums": "Álbumes",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
- "Application": "Aplicación",
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado correctamente",
"Books": "Libros",
- "CameraImageUploadedFrom": "Se ha subido una nueva imagen por cámara desde {0}",
- "Channels": "Canales",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Colecciones",
- "DeviceOfflineWithName": "{0} se ha desconectado",
- "DeviceOnlineWithName": "{0} está conectado",
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Genres": "Géneros",
- "HeaderAlbumArtists": "Artistas del álbum",
"HeaderContinueWatching": "Seguir viendo",
- "HeaderFavoriteAlbums": "Álbumes favoritos",
- "HeaderFavoriteArtists": "Artistas favoritos",
"HeaderFavoriteEpisodes": "Episodios favoritos",
"HeaderFavoriteShows": "Series favoritas",
- "HeaderFavoriteSongs": "Canciones favoritas",
"HeaderLiveTV": "Televisión en directo",
"HeaderNextUp": "Siguiente",
- "HeaderRecordingGroups": "Grupos de grabación",
"HomeVideos": "Vídeos caseros",
"Inherit": "Heredar",
- "ItemAddedWithName": "{0} se ha añadido a la biblioteca",
- "ItemRemovedWithName": "{0} ha sido eliminado de la biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
"LabelRunningTimeValue": "Duración: {0}",
"Latest": "Últimas",
- "MessageApplicationUpdated": "Se ha actualizado el servidor Jellyfin",
- "MessageApplicationUpdatedTo": "Se ha actualizado el servidor Jellyfin a la versión {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "La sección {0} de configuración del servidor ha sido actualizada",
- "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
"MixedContent": "Contenido mixto",
"Movies": "Películas",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Se inició la reproducción de vídeo",
"NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detenida",
"Photos": "Fotos",
- "Playlists": "Listas de reproducción",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} se ha instalado",
"PluginUninstalledWithName": "{0} se ha desinstalado",
"PluginUpdatedWithName": "{0} se actualizó",
- "ProviderValue": "Proveedor: {0}",
"ScheduledTaskFailedWithName": "{0} falló",
- "ScheduledTaskStartedWithName": "{0} iniciada",
- "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
"Shows": "Series",
- "Songs": "Canciones",
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
"SubtitleDownloadFailureFromForItem": "Fallo en la descarga de subtítulos desde {0} para {1}",
- "Sync": "Sincronizar",
- "System": "Sistema",
"TvShows": "Series",
- "User": "Usuario",
"UserCreatedWithName": "El usuario {0} ha sido creado",
"UserDeletedWithName": "El usuario {0} ha sido borrado",
"UserDownloadingItemWithValues": "{0} está descargando {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} se ha desconectado desde {1}",
"UserOnlineFromDevice": "{0} está en línea desde {1}",
"UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
- "UserPolicyUpdatedWithName": "Actualizada política de usuario para {0}",
"UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}",
"UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
- "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versión {0}",
"TasksMaintenanceCategory": "Mantenimiento",
"TasksLibraryCategory": "Biblioteca",
diff --git a/Emby.Server.Implementations/Localization/Core/es_419.json b/Emby.Server.Implementations/Localization/Core/es_419.json
index dec82b73e3..1f13451060 100644
--- a/Emby.Server.Implementations/Localization/Core/es_419.json
+++ b/Emby.Server.Implementations/Localization/Core/es_419.json
@@ -1,29 +1,19 @@
{
"LabelRunningTimeValue": "Tiempo en ejecución: {0}",
- "ValueSpecialEpisodeName": "Especial - {0}",
- "Sync": "Sincronizar",
- "Songs": "Canciones",
"Shows": "Programas",
- "Playlists": "Listas de reproducción",
"Photos": "Fotos",
"Movies": "Películas",
"HeaderNextUp": "A continuación",
"HeaderLiveTV": "TV en vivo",
- "HeaderFavoriteSongs": "Canciones favoritas",
- "HeaderFavoriteArtists": "Artistas favoritos",
- "HeaderFavoriteAlbums": "Álbumes favoritos",
"HeaderFavoriteEpisodes": "Episodios favoritos",
"HeaderFavoriteShows": "Programas favoritos",
"HeaderContinueWatching": "Continuar viendo",
- "HeaderAlbumArtists": "Artistas de álbum",
"Genres": "Géneros",
"Folders": "Carpetas",
"Favorites": "Favoritos",
"Collections": "Colecciones",
- "Channels": "Canales",
"Books": "Libros",
"Artists": "Artistas",
- "Albums": "Álbumes",
"TaskDownloadMissingSubtitlesDescription": "Busca subtítulos faltantes en Internet basándose en la configuración de metadatos.",
"TaskDownloadMissingSubtitles": "Descargar subtítulos faltantes",
"TaskRefreshChannelsDescription": "Actualiza la información de canales de Internet.",
@@ -47,10 +37,8 @@
"TasksLibraryCategory": "Biblioteca",
"TasksMaintenanceCategory": "Mantenimiento",
"VersionNumber": "Versión {0}",
- "ValueHasBeenAddedToLibrary": "{0} se ha añadido a tu biblioteca de medios",
"UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
"UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}",
- "UserPolicyUpdatedWithName": "La política de usuario ha sido actualizada para {0}",
"UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
"UserOnlineFromDevice": "{0} está en línea desde {1}",
"UserOfflineFromDevice": "{0} se ha desconectado desde {1}",
@@ -58,19 +46,13 @@
"UserDownloadingItemWithValues": "{0} está descargando {1}",
"UserDeletedWithName": "El usuario {0} ha sido eliminado",
"UserCreatedWithName": "El usuario {0} ha sido creado",
- "User": "Usuario",
"TvShows": "Programas de TV",
- "System": "Sistema",
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtítulos desde {0} para {1}",
"StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo pronto.",
- "ServerNameNeedsToBeRestarted": "{0} debe ser reiniciado",
- "ScheduledTaskStartedWithName": "{0} iniciado",
"ScheduledTaskFailedWithName": "{0} falló",
- "ProviderValue": "Proveedor: {0}",
"PluginUpdatedWithName": "{0} fue actualizado",
"PluginUninstalledWithName": "{0} fue desinstalado",
"PluginInstalledWithName": "{0} fue instalado",
- "Plugin": "Complemento",
"NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida",
"NotificationOptionVideoPlayback": "Reproducción de video iniciada",
"NotificationOptionUserLockedOut": "Usuario bloqueado",
@@ -94,24 +76,13 @@
"MusicVideos": "Videos musicales",
"Music": "Música",
"MixedContent": "Contenido mezclado",
- "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
- "MessageNamedServerConfigurationUpdatedWithValue": "Se ha actualizado la sección {0} de la configuración del servidor",
- "MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}",
- "MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado",
"Latest": "Recientes",
"LabelIpAddressValue": "Dirección IP: {0}",
- "ItemRemovedWithName": "{0} fue removido de la biblioteca",
- "ItemAddedWithName": "{0} fue agregado a la biblioteca",
"Inherit": "Heredar",
"HomeVideos": "Videos caseros",
- "HeaderRecordingGroups": "Grupos de grabación",
"FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido desde {0}",
- "DeviceOnlineWithName": "{0} está conectado",
- "DeviceOfflineWithName": "{0} se ha desconectado",
"ChapterNameValue": "Capítulo {0}",
- "CameraImageUploadedFrom": "Una nueva imagen de cámara ha sido subida desde {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado con éxito",
- "Application": "Aplicación",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
"TaskCleanActivityLogDescription": "Elimina las entradas del registro de actividad anteriores al periodo configurado.",
"TaskCleanActivityLog": "Limpiar registro de actividades",
diff --git a/Emby.Server.Implementations/Localization/Core/es_DO.json b/Emby.Server.Implementations/Localization/Core/es_DO.json
index 8d991fa74a..a1b9944125 100644
--- a/Emby.Server.Implementations/Localization/Core/es_DO.json
+++ b/Emby.Server.Implementations/Localization/Core/es_DO.json
@@ -1,35 +1,24 @@
{
- "Channels": "Canales",
"Books": "Libros",
- "Albums": "Álbumes",
"Collections": "Colecciones",
"Artists": "Artistas",
- "DeviceOnlineWithName": "{0} está conectado",
- "DeviceOfflineWithName": "{0} se ha desconectado",
"ChapterNameValue": "Capítulo {0}",
- "CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado con éxito",
- "Application": "Aplicación",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
"HeaderContinueWatching": "Continuar Viendo",
- "HeaderAlbumArtists": "Artistas del álbum",
"Genres": "Géneros",
"Folders": "Carpetas",
"Favorites": "Favoritos",
"FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido desde {0}",
- "HeaderFavoriteSongs": "Canciones Favoritas",
"HeaderFavoriteEpisodes": "Episodios Favoritos",
- "HeaderFavoriteArtists": "Artistas Favoritos",
"External": "Externo",
"Default": "Predeterminado",
"Movies": "Películas",
- "MessageNamedServerConfigurationUpdatedWithValue": "La sección {0} de la configuración ha sido actualizada",
"MixedContent": "Contenido mixto",
"Music": "Música",
"NotificationOptionCameraImageUploaded": "Imagen de la cámara subida",
"NotificationOptionServerRestartRequired": "Se necesita reiniciar el servidor",
"NotificationOptionVideoPlayback": "Reproducción de video iniciada",
- "Sync": "Sincronizar",
"Shows": "Series",
"UserDownloadingItemWithValues": "{0} está descargando {1}",
"UserOfflineFromDevice": "{0} se ha desconectado desde {1}",
@@ -48,17 +37,12 @@
"HeaderFavoriteShows": "Programas favoritos",
"TaskCleanActivityLog": "Limpiar registro de actividades",
"UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
- "System": "Sistema",
- "User": "Usuario",
"Forced": "Forzado",
"PluginInstalledWithName": "{0} ha sido instalado",
- "HeaderFavoriteAlbums": "Álbumes favoritos",
"TaskUpdatePlugins": "Actualizar Plugins",
"Latest": "Recientes",
"UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
- "Songs": "Canciones",
"NotificationOptionPluginError": "Falla de plugin",
- "ScheduledTaskStartedWithName": "{0} iniciado",
"TasksApplicationCategory": "Aplicación",
"UserDeletedWithName": "El usuario {0} ha sido eliminado",
"TaskRefreshChapterImages": "Extraer imágenes de los capítulos",
@@ -71,34 +55,26 @@
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida",
"TasksLibraryCategory": "Biblioteca",
"NotificationOptionPluginInstalled": "Plugin instalado",
- "UserPolicyUpdatedWithName": "La política de usuario ha sido actualizada para {0}",
"VersionNumber": "Versión {0}",
"HeaderNextUp": "A continuación",
- "ValueHasBeenAddedToLibrary": "{0} se ha añadido a tu biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
"NameSeasonNumber": "Temporada {0}",
"NotificationOptionNewLibraryContent": "Nuevo contenido agregado",
- "Plugin": "Plugin",
"NotificationOptionAudioPlayback": "Reproducción de audio iniciada",
"NotificationOptionTaskFailed": "Falló la tarea programada",
"LabelRunningTimeValue": "Tiempo en ejecución: {0}",
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtítulos desde {0} para {1}",
"TaskRefreshLibrary": "Escanear biblioteca de medios",
- "ServerNameNeedsToBeRestarted": "{0} debe ser reiniciado",
"TasksMaintenanceCategory": "Mantenimiento",
- "ProviderValue": "Proveedor: {0}",
"UserCreatedWithName": "El usuario {0} ha sido creado",
"PluginUninstalledWithName": "{0} ha sido desinstalado",
- "ValueSpecialEpisodeName": "Especial - {0}",
"ScheduledTaskFailedWithName": "{0} falló",
"TaskCleanLogs": "Limpiar directorio de registros",
"NameInstallFailed": "Falló la instalación de {0}",
"UserLockedOutWithName": "El usuario {0} ha sido bloqueado",
"TaskRefreshLibraryDescription": "Escanea tu biblioteca de medios para encontrar archivos nuevos y actualizar los metadatos.",
"StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo en un momento.",
- "Playlists": "Listas de reproducción",
"TaskDownloadMissingSubtitlesDescription": "Busca subtítulos faltantes en Internet basándose en la configuración de metadatos.",
- "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
"TaskRefreshPeople": "Actualizar personas",
"NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida",
"HeaderLiveTV": "TV en vivo",
@@ -108,15 +84,10 @@
"TaskCleanCache": "Limpiar directorio caché",
"TaskRefreshChapterImagesDescription": "Crea miniaturas para videos que tienen capítulos.",
"Inherit": "Heredar",
- "HeaderRecordingGroups": "Grupos de grabación",
- "ItemAddedWithName": "{0} fue agregado a la biblioteca",
"TaskOptimizeDatabase": "Optimizar base de datos",
"TaskKeyframeExtractor": "Extractor de Fotogramas Clave",
"HearingImpaired": "Discapacidad auditiva",
"HomeVideos": "Videos caseros",
- "ItemRemovedWithName": "{0} fue removido de la biblioteca",
- "MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado",
- "MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}",
"MusicVideos": "Videos musicales",
"NewVersionIsAvailable": "Una nueva versión de Jellyfin está disponible para descargar.",
"PluginUpdatedWithName": "{0} ha sido actualizado",
diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json
index d751e35af2..bc089d836c 100644
--- a/Emby.Server.Implementations/Localization/Core/et.json
+++ b/Emby.Server.Implementations/Localization/Core/et.json
@@ -1,7 +1,6 @@
{
"TaskCleanActivityLogDescription": "Kustutab määratud ajast vanemad tegevuslogi kirjed.",
"UserDownloadingItemWithValues": "{0} laadib alla {1}",
- "HeaderRecordingGroups": "Salvestusrühmad",
"TaskOptimizeDatabaseDescription": "Tihendab ja puhastab andmebaasi. Selle toimingu tegemine pärast meediakogu andmebaasiga seotud muudatuste skannimist võib jõudlust parandada.",
"TaskOptimizeDatabase": "Optimeeri andmebaasi",
"TaskDownloadMissingSubtitlesDescription": "Otsib veebist puuduvaid subtiitreid vastavalt määratud metaandmete seadetele.",
@@ -29,30 +28,19 @@
"TasksLibraryCategory": "Meediakogu",
"TasksMaintenanceCategory": "Hooldus",
"VersionNumber": "Versioon {0}",
- "ValueSpecialEpisodeName": "Eriepisood - {0}",
- "ValueHasBeenAddedToLibrary": "{0} lisati meediakogusse",
"UserStartedPlayingItemWithValues": "{0} taasesitab {1} seadmes {2}",
"UserPasswordChangedWithName": "Kasutaja {0} parool muudeti",
"UserLockedOutWithName": "Kasutaja {0} lukustati",
"UserDeletedWithName": "Kasutaja {0} kustutati",
"UserCreatedWithName": "Kasutaja {0} on loodud",
- "ScheduledTaskStartedWithName": "{0} käivitati",
- "ProviderValue": "Allikas: {0}",
"StartupEmbyServerIsLoading": "Jellyfin server laadib. Proovi varsti uuesti.",
- "User": "Kasutaja",
"Undefined": "Määratlemata",
"TvShows": "Sarjad",
- "System": "Süsteem",
- "Sync": "Sünkrooni",
- "Songs": "Lood",
"Shows": "Sarjad",
- "ServerNameNeedsToBeRestarted": "{0} tuleb taaskäivitada",
"ScheduledTaskFailedWithName": "{0} nurjus",
"PluginUpdatedWithName": "{0} uuendati",
"PluginUninstalledWithName": "{0} eemaldati",
"PluginInstalledWithName": "{0} paigaldati",
- "Plugin": "Plugin",
- "Playlists": "Esitusloendid",
"Photos": "Fotod",
"NotificationOptionVideoPlaybackStopped": "Video taasesitus lõppes",
"NotificationOptionVideoPlayback": "Video taasesitus algas",
@@ -78,46 +66,29 @@
"Music": "Muusika",
"Movies": "Filmid",
"MixedContent": "Segatud sisu",
- "MessageServerConfigurationUpdated": "Serveri seadistust uuendati",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serveri seadistusosa {0} uuendati",
- "MessageApplicationUpdatedTo": "Jellyfin server uuendati versioonile {0}",
- "MessageApplicationUpdated": "Jellyfin server uuendati",
"Latest": "Uusimad",
"LabelRunningTimeValue": "Kestus: {0}",
"LabelIpAddressValue": "IP aadress: {0}",
- "ItemRemovedWithName": "{0} eemaldati meediakogust",
- "ItemAddedWithName": "{0} lisati meediakogusse",
"Inherit": "Päri",
"HomeVideos": "Koduvideod",
"HeaderNextUp": "Järgmisena",
"HeaderLiveTV": "Otse TV",
- "HeaderFavoriteSongs": "Lemmiklood",
"HeaderFavoriteShows": "Lemmiksarjad",
"HeaderFavoriteEpisodes": "Lemmikepisoodid",
- "HeaderFavoriteArtists": "Lemmikesitajad",
- "HeaderFavoriteAlbums": "Lemmikalbumid",
"HeaderContinueWatching": "Jätka vaatamist",
- "HeaderAlbumArtists": "Albumi esitajad",
"Genres": "Žanrid",
"Forced": "Sunnitud",
"Folders": "Kaustad",
"Favorites": "Lemmikud",
"FailedLoginAttemptWithUserName": "Sisselogimine nurjus aadressilt {0}",
- "DeviceOnlineWithName": "{0} on ühendatud",
- "DeviceOfflineWithName": "{0} katkestas ühenduse",
"Default": "Vaikimisi",
"ChapterNameValue": "Peatükk {0}",
- "Channels": "Kanalid",
- "CameraImageUploadedFrom": "Uus kaamera pilt laaditi üles allikalt {0}",
"Books": "Raamatud",
"AuthenticationSucceededWithUserName": "{0} autentimine õnnestus",
"Artists": "Esitajad",
- "Application": "Rakendus",
"AppDeviceValues": "Rakendus: {0}, seade: {1}",
- "Albums": "Albumid",
"UserOfflineFromDevice": "{0} katkestas ühenduse seadmega {1}",
"SubtitleDownloadFailureFromForItem": "Subtiitrite allalaadimine {0} > {1} nurjus",
- "UserPolicyUpdatedWithName": "Kasutaja {0} õigusi värskendati",
"UserStoppedPlayingItemWithValues": "{0} lõpetas {1} taasesituse seadmes {2}",
"UserOnlineFromDevice": "{0} on ühendatud seadmest {1}",
"External": "Väline",
@@ -135,5 +106,6 @@
"TaskExtractMediaSegmentsDescription": "Eraldab või võtab meedialõigud MediaSegment'i toega pluginatest.",
"TaskMoveTrickplayImages": "Muuda trickplay piltide asukoht",
"CleanupUserDataTask": "Puhasta kasutajaandmed",
- "CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mida pole enam vähemalt 90 päeva saadaval olnud."
+ "CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mida pole enam vähemalt 90 päeva saadaval olnud.",
+ "LyricDownloadFailureFromForItem": "Laulusõnade hankimine teenusest {0} loole {1} nurjus"
}
diff --git a/Emby.Server.Implementations/Localization/Core/eu.json b/Emby.Server.Implementations/Localization/Core/eu.json
index 9e1390484f..71c351adcd 100644
--- a/Emby.Server.Implementations/Localization/Core/eu.json
+++ b/Emby.Server.Implementations/Localization/Core/eu.json
@@ -1,23 +1,16 @@
{
- "ValueSpecialEpisodeName": "Berezia - {0}",
- "Sync": "Sinkronizatu",
- "Songs": "Abestiak",
"Shows": "Serieak",
- "Playlists": "Erreprodukzio-zerrendak",
"Photos": "Argazkiak",
"MusicVideos": "Bideo musikalak",
"Movies": "Filmak",
"HeaderContinueWatching": "Ikusten jarraitu",
- "HeaderAlbumArtists": "Albumeko artistak",
"Genres": "Generoak",
"Folders": "Karpetak",
"Favorites": "Gogokoak",
"Default": "Lehenetsia",
"Collections": "Bildumak",
- "Channels": "Kanalak",
"Books": "Liburuak",
"Artists": "Artistak",
- "Albums": "Albumak",
"TaskOptimizeDatabase": "Datu basea optimizatu",
"TaskDownloadMissingSubtitlesDescription": "Falta diren azpitituluak bilatzen ditu interneten metadatuen konfigurazioaren arabera.",
"TaskDownloadMissingSubtitles": "Falta diren azpitituluak deskargatu",
@@ -44,10 +37,8 @@
"TasksLibraryCategory": "Liburutegia",
"TasksMaintenanceCategory": "Mantenua",
"VersionNumber": "Bertsioa {0}",
- "ValueHasBeenAddedToLibrary": "{0} zure multimedia liburutegian gehitu da",
"UserStoppedPlayingItemWithValues": "{0} {1} ikusten bukatu du {2}-(e)n",
"UserStartedPlayingItemWithValues": "{0} {1} ikusten ari da {2}-(e)n",
- "UserPolicyUpdatedWithName": "{0} erabiltzailearen politikak aldatu dira",
"UserPasswordChangedWithName": "{0} erabiltzailearen pasahitza aldatu da",
"UserOnlineFromDevice": "{0} online dago {1}-(e)tik",
"UserOfflineFromDevice": "{0} {1}-(e)tik deskonektatu da",
@@ -55,19 +46,14 @@
"UserDownloadingItemWithValues": "{0} {1} deskargatzen ari da",
"UserDeletedWithName": "{0} Erabiltzailea ezabatu da",
"UserCreatedWithName": "{0} Erabiltzailea sortu da",
- "User": "Erabiltzailea",
"Undefined": "Ezezaguna",
"TvShows": "TB serieak",
- "System": "Sistema",
"SubtitleDownloadFailureFromForItem": "{1}-en azpitutuluak {0}-tik deskargatzeak huts egin du",
"StartupEmbyServerIsLoading": "Jellyfin zerbitzaria kargatzen. Saiatu berriro beranduago.",
- "ServerNameNeedsToBeRestarted": "{0} berrabiarazi behar da",
- "ScheduledTaskStartedWithName": "{0} hasi da",
"ScheduledTaskFailedWithName": "{0} huts egin du",
"PluginUpdatedWithName": "{0} eguneratu da",
"PluginUninstalledWithName": "{0} desinstalatu da",
"PluginInstalledWithName": "{0} instalatu da",
- "Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Bideoa geldituta",
"NotificationOptionVideoPlayback": "Bideoa martxan",
"NotificationOptionUserLockedOut": "Erabiltzailea blokeatua",
@@ -90,37 +76,22 @@
"NameInstallFailed": "{0} instalazioak huts egin du",
"Music": "Musika",
"MixedContent": "Eduki mistoa",
- "MessageServerConfigurationUpdated": "Zerbitzariaren konfigurazioa eguneratu da",
- "MessageNamedServerConfigurationUpdatedWithValue": "Zerbitzariaren {0} konfigurazio atala eguneratu da",
- "MessageApplicationUpdatedTo": "Jellyfin zerbitzaria {0}-ra eguneratu da",
- "MessageApplicationUpdated": "Jellyfin zerbitzaria eguneratu da",
"Latest": "Azkena",
"LabelRunningTimeValue": "Iraupena: {0}",
"LabelIpAddressValue": "IP helbidea: {0}",
- "ItemRemovedWithName": "{0} liburutegitik kendu da",
- "ItemAddedWithName": "{0} liburutegira gehitu da",
"HomeVideos": "Etxeko bideoak",
"HeaderNextUp": "Hurrengoa",
"HeaderLiveTV": "Zuzeneko TB",
- "HeaderFavoriteSongs": "Gogoko abestiak",
"HeaderFavoriteShows": "Gogoko serieak",
"HeaderFavoriteEpisodes": "Gogoko atalak",
- "HeaderFavoriteArtists": "Gogoko artistak",
- "HeaderFavoriteAlbums": "Gogoko albumak",
"Forced": "Behartuta",
"FailedLoginAttemptWithUserName": "{0}-tik saioa hasteak huts egin du",
"External": "Kanpokoa",
- "DeviceOnlineWithName": "{0} konektatu da",
- "DeviceOfflineWithName": "{0} deskonektatu da",
"ChapterNameValue": "{0} Kapitulua",
- "CameraImageUploadedFrom": "{0}-tik kamera irudi berri bat igo da",
"AuthenticationSucceededWithUserName": "{0} ongi autentifikatu da",
- "Application": "Aplikazioa",
"AppDeviceValues": "App: {0}, Gailua: {1}",
"HearingImpaired": "Entzumen urritasuna",
- "ProviderValue": "Hornitzailea: {0}",
"TaskKeyframeExtractorDescription": "Bideo fitxategietako fotograma gakoak ateratzen ditu HLS erreprodukzio-zerrenda zehatzagoak sortzeko. Zeregin honek denbora asko iraun dezake.",
- "HeaderRecordingGroups": "Grabaketa taldeak",
"Inherit": "Oinordetu",
"TaskOptimizeDatabaseDescription": "Datu-basea trinkotu eta bertatik espazioa askatzen du. Liburutegia eskaneatu ondoren edo datu-basean aldaketak egin ondoren ataza hau exekutatzeak errendimendua hobetu lezake.",
"TaskKeyframeExtractor": "Fotograma gakoen erauzgailua",
@@ -135,5 +106,7 @@
"TaskMoveTrickplayImagesDescription": "Lehendik dauden trickplay fitxategiak liburutegiaren ezarpenen arabera mugitzen dira.",
"TaskAudioNormalizationDescription": "Audio normalizazio datuak lortzeko fitxategiak eskaneatzen ditu.",
"CleanupUserDataTaskDescription": "Gutxienez 90 egunez dagoeneko existitzen ez den multimediatik erabiltzaile-datu guztiak (ikusteko egoera, gogokoen egoera, etab.) garbitzen ditu.",
- "CleanupUserDataTask": "Erabiltzaileen datuak garbitzeko zeregina"
+ "CleanupUserDataTask": "Erabiltzaileen datuak garbitzeko zeregina",
+ "LyricDownloadFailureFromForItem": "Ezin izan dira {1}-ren letrak deskargatu {0}-tik",
+ "Original": "Jatorrizkoa"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index 435485db7c..17ed54b117 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -1,41 +1,24 @@
{
- "Albums": "آلبوم‌ها",
"AppDeviceValues": "برنامه: {0} ، دستگاه: {1}",
- "Application": "برنامه",
"Artists": "هنرمندان",
"AuthenticationSucceededWithUserName": "{0} با موفقیت تایید اعتبار شد",
"Books": "کتاب‌ها",
- "CameraImageUploadedFrom": "یک عکس جدید از دوربین ارسال شده است {0}",
- "Channels": "کانالها",
"ChapterNameValue": "قسمت {0}",
"Collections": "مجموعه‌ها",
- "DeviceOfflineWithName": "ارتباط {0} قطع شد",
- "DeviceOnlineWithName": "{0} متصل شد",
"FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود",
"Favorites": "مورد علاقه‌ها",
"Folders": "پوشه‌ها",
"Genres": "ژانرها",
- "HeaderAlbumArtists": "هنرمندان آلبوم",
"HeaderContinueWatching": "ادامه تماشا",
- "HeaderFavoriteAlbums": "آلبوم‌های مورد علاقه",
- "HeaderFavoriteArtists": "هنرمندان مورد علاقه",
"HeaderFavoriteEpisodes": "قسمت‌های مورد علاقه",
"HeaderFavoriteShows": "سریال‌های مورد علاقه",
- "HeaderFavoriteSongs": "آهنگ‌های مورد علاقه",
"HeaderLiveTV": "پخش زنده",
"HeaderNextUp": "قسمت بعدی",
- "HeaderRecordingGroups": "گروه‌های ضبط",
"HomeVideos": "ویدیوهای خانگی",
"Inherit": "به ارث برده",
- "ItemAddedWithName": "{0} به کتابخانه افزوده شد",
- "ItemRemovedWithName": "{0} از کتابخانه حذف شد",
"LabelIpAddressValue": "آدرس آی پی: {0}",
"LabelRunningTimeValue": "زمان اجرا: {0}",
"Latest": "جدیدترین‌ها",
- "MessageApplicationUpdated": "سرور Jellyfin بروزرسانی شد",
- "MessageApplicationUpdatedTo": "سرور Jellyfin به نسخه {0} بروزرسانی شد",
- "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور بروزرسانی شد",
- "MessageServerConfigurationUpdated": "پیکربندی سرور بروزرسانی شد",
"MixedContent": "محتوای مخلوط",
"Movies": "فیلم ها",
"Music": "موسیقی",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "پخش ویدیو آغاز شد",
"NotificationOptionVideoPlaybackStopped": "پخش ویدیو متوقف شد",
"Photos": "عکس‌ها",
- "Playlists": "لیست‌های پخش",
- "Plugin": "افزونه",
"PluginInstalledWithName": "{0} نصب شد",
"PluginUninstalledWithName": "{0} حذف شد",
"PluginUpdatedWithName": "{0} آپدیت شد",
- "ProviderValue": "ارائه دهنده: {0}",
"ScheduledTaskFailedWithName": "{0} شکست خورد",
- "ScheduledTaskStartedWithName": "{0} شروع شد",
- "ServerNameNeedsToBeRestarted": "{0} نیاز به راه اندازی مجدد دارد",
"Shows": "سریال‌ها",
- "Songs": "موسیقی‌ها",
"StartupEmbyServerIsLoading": "سرور Jellyfin در حال بارگیری است. لطفا کمی بعد دوباره تلاش کنید.",
"SubtitleDownloadFailureFromForItem": "بارگیری زیرنویس برای {1} از {0} شکست خورد",
- "Sync": "همگام‌سازی",
- "System": "سیستم",
"TvShows": "سریال‌های تلویزیونی",
- "User": "کاربر",
"UserCreatedWithName": "کاربر {0} ایجاد شد",
"UserDeletedWithName": "کاربر {0} حذف شد",
"UserDownloadingItemWithValues": "{0} در حال بارگیری {1} می‌باشد",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "ارتباط {0} از {1} قطع شد",
"UserOnlineFromDevice": "{0} از {1} آنلاین می‌باشد",
"UserPasswordChangedWithName": "گذرواژه برای کاربر {0} تغییر کرد",
- "UserPolicyUpdatedWithName": "سیاست کاربری برای {0} بروزرسانی شد",
"UserStartedPlayingItemWithValues": "{0} در حال پخش {1} بر روی {2} است",
"UserStoppedPlayingItemWithValues": "{0} پخش {1} را بر روی {2} به پایان رساند",
- "ValueHasBeenAddedToLibrary": "{0} به کتابخانه‌ی رسانه‌ی شما افزوده شد",
- "ValueSpecialEpisodeName": "ویژه - {0}",
"VersionNumber": "نسخه {0}",
"TaskCleanTranscodeDescription": "فایل‌های کدگذاری که قدیمی‌تر از یک روز هستند را حذف می‌کند.",
"TaskCleanTranscode": "پاکسازی مسیر کد گذاری",
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index d3237db8b0..d08f652e58 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -8,57 +8,33 @@
"Music": "Musiikki",
"Movies": "Elokuvat",
"MixedContent": "Sekalainen sisältö",
- "MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty",
- "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": "Peri",
"HomeVideos": "Kotivideot",
- "HeaderRecordingGroups": "Tallennusryhmät",
"HeaderNextUp": "Seuraavaksi",
- "HeaderFavoriteSongs": "Suosikkikappaleet",
"HeaderFavoriteShows": "Suosikkisarjat",
"HeaderFavoriteEpisodes": "Suosikkijaksot",
- "HeaderFavoriteArtists": "Suosikkiesittäjät",
- "HeaderFavoriteAlbums": "Suosikkialbumit",
"HeaderContinueWatching": "Jatka katselua",
- "HeaderAlbumArtists": "Albumin esittäjät",
"Genres": "Tyylilajit",
"Folders": "Kansiot",
"Favorites": "Suosikit",
"FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys lähteestä \"{0}\"",
- "DeviceOnlineWithName": "{0} on yhdistetty",
- "DeviceOfflineWithName": "{0} on katkaissut yhteyden",
"Collections": "Kokoelmat",
"ChapterNameValue": "Kappale {0}",
- "Channels": "Kanavat",
- "CameraImageUploadedFrom": "Uusi kameran kuva on sirretty lähteestä {0}",
"Books": "Kirjat",
"AuthenticationSucceededWithUserName": "{0} todennus onnistunut",
"Artists": "Artistit",
- "Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
- "Albums": "Albumit",
- "User": "Käyttäjä",
- "System": "Järjestelmä",
"ScheduledTaskFailedWithName": "{0} epäonnistui",
"PluginUpdatedWithName": "{0} päivitettiin",
"PluginInstalledWithName": "{0} asennettiin",
"Photos": "Valokuvat",
- "ScheduledTaskStartedWithName": "\"{0}\" käynnistetty",
"PluginUninstalledWithName": "{0} poistettiin",
- "Playlists": "Soittolistat",
"VersionNumber": "Versio {0}",
- "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}\"",
@@ -67,14 +43,9 @@
"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 on latautumassa. Yritä hetken kuluttua uudelleen.",
- "Songs": "Kappaleet",
"Shows": "Sarjat",
- "ServerNameNeedsToBeRestarted": "\"{0}\" on käynnistettävä uudelleen",
- "ProviderValue": "Lähde: {0}",
- "Plugin": "Lisäosa",
"NotificationOptionVideoPlaybackStopped": "Videon toisto lopetettu",
"NotificationOptionVideoPlayback": "Videon toisto aloitettu",
"NotificationOptionUserLockedOut": "Käyttäjä on lukittu",
diff --git a/Emby.Server.Implementations/Localization/Core/fil.json b/Emby.Server.Implementations/Localization/Core/fil.json
index 28c1d2be5e..30d90e9f98 100644
--- a/Emby.Server.Implementations/Localization/Core/fil.json
+++ b/Emby.Server.Implementations/Localization/Core/fil.json
@@ -1,10 +1,7 @@
{
"VersionNumber": "Bersyon {0}",
- "ValueSpecialEpisodeName": "Espesyal - {0}",
- "ValueHasBeenAddedToLibrary": "Naidagdag na ang {0} sa iyong librerya ng medya",
"UserStoppedPlayingItemWithValues": "Natapos ni {0} ang {1} sa {2}",
"UserStartedPlayingItemWithValues": "Si {0} ay nagpla-play ng {1} sa {2}",
- "UserPolicyUpdatedWithName": "Ang user policy ay nai-update para kay {0}",
"UserPasswordChangedWithName": "Napalitan na ang password ni {0}",
"UserOnlineFromDevice": "Si {0} ay naka-konekta galing sa {1}",
"UserOfflineFromDevice": "Si {0} ay na-diskonekta galing sa {1}",
@@ -12,23 +9,14 @@
"UserDownloadingItemWithValues": "Nagdadownload si {0} ng {1}",
"UserDeletedWithName": "Natanggal na is user {0}",
"UserCreatedWithName": "Nagawa na si user {0}",
- "User": "User",
"TvShows": "Mga Palabas sa Telebisyon",
- "System": "Sistema",
- "Sync": "Pag-sync",
"SubtitleDownloadFailureFromForItem": "Hindi nai-download ang subtitles {0} para sa {1}",
"StartupEmbyServerIsLoading": "Naglo-load ang Jellyfin Server. Mangyaring subukan ulit sandali.",
- "Songs": "Mga Kanta",
"Shows": "Mga Pelikula",
- "ServerNameNeedsToBeRestarted": "Kailangan irestart ang {0}",
- "ScheduledTaskStartedWithName": "Nagsimula na ang {0}",
"ScheduledTaskFailedWithName": "Hindi gumana ang {0}",
- "ProviderValue": "Tagapagtustos: {0}",
"PluginUpdatedWithName": "Naiupdate na ang {0}",
"PluginUninstalledWithName": "Naiuninstall na ang {0}",
"PluginInstalledWithName": "Nainstall na ang {0}",
- "Plugin": "Plugin",
- "Playlists": "Mga Playlist",
"Photos": "Mga Larawan",
"NotificationOptionVideoPlaybackStopped": "Huminto na ang pelikula",
"NotificationOptionVideoPlayback": "Nagsimula na ang pelikula",
@@ -54,42 +42,25 @@
"Music": "Mga Kanta",
"Movies": "Mga Pelikula",
"MixedContent": "Halo-halong content",
- "MessageServerConfigurationUpdated": "Naiupdate na ang server configuration",
- "MessageNamedServerConfigurationUpdatedWithValue": "Naiupdate na ang server configuration section {0}",
- "MessageApplicationUpdatedTo": "Ang bersyon ng Jellyfin Server ay naiupdate sa {0}",
- "MessageApplicationUpdated": "Naiupdate na ang Jellyfin Server",
"Latest": "Pinakabago",
"LabelRunningTimeValue": "Oras: {0}",
"LabelIpAddressValue": "IP address: {0}",
- "ItemRemovedWithName": "Naitanggal ang {0} sa librerya",
- "ItemAddedWithName": "Naidagdag ang {0} sa librerya",
"Inherit": "Manahin",
- "HeaderRecordingGroups": "Pagtatalang Grupo",
"HeaderNextUp": "Susunod",
"HeaderLiveTV": "Live TV",
- "HeaderFavoriteSongs": "Mga Paboritong Kanta",
"HeaderFavoriteShows": "Mga Paboritong Pelikula",
"HeaderFavoriteEpisodes": "Mga Paboritong Yugto",
- "HeaderFavoriteArtists": "Mga Paboritong Artista",
- "HeaderFavoriteAlbums": "Mga Paboritong Album",
"HeaderContinueWatching": "Magpatuloy sa Panonood",
- "HeaderAlbumArtists": "Mga Artista ng Album",
"Genres": "Mga Kategorya",
"Folders": "Mga Folder",
"Favorites": "Mga Paborito",
"FailedLoginAttemptWithUserName": "Maling login galing kay/sa {0}",
- "DeviceOnlineWithName": "Nakakonekta si/ang {0}",
- "DeviceOfflineWithName": "Nadiskonekta si/ang {0}",
"Collections": "Mga Koleksyon",
"ChapterNameValue": "Kabanata {0}",
- "Channels": "Mga Channel",
- "CameraImageUploadedFrom": "May bagong larawan na naupload galing sa/kay {0}",
"Books": "Mga Libro",
"AuthenticationSucceededWithUserName": "Napatunayan si/ang {0}",
"Artists": "Mga Artista",
- "Application": "Aplikasyon",
"AppDeviceValues": "Aplikasyon: {0}, Aparato: {1}",
- "Albums": "Mga Album",
"TaskRefreshLibrary": "Suriin and Librerya ng Medya",
"TaskRefreshChapterImagesDescription": "Gumawa ng larawan para sa mga pelikula na may kabanata.",
"TaskRefreshChapterImages": "Kunin ang mga larawan ng kabanata",
diff --git a/Emby.Server.Implementations/Localization/Core/fo.json b/Emby.Server.Implementations/Localization/Core/fo.json
index 044abc7fa3..4fb9f4329c 100644
--- a/Emby.Server.Implementations/Localization/Core/fo.json
+++ b/Emby.Server.Implementations/Localization/Core/fo.json
@@ -2,21 +2,15 @@
"Artists": "Listafólk",
"Collections": "Søvn",
"Default": "Sjálvgildi",
- "DeviceOfflineWithName": "{0} hevur slitið sambandið",
"External": "Ytri",
"Genres": "Greinar",
- "Albums": "Album",
"AppDeviceValues": "App: {0}, Eind: {1}",
- "Application": "Nýtsluskipan",
"Books": "Bøkur",
- "Channels": "Rásir",
"ChapterNameValue": "Kapittul {0}",
- "DeviceOnlineWithName": "{0} er sambundið",
"Favorites": "Yndis",
"Folders": "Mappur",
"Forced": "Kravt",
"FailedLoginAttemptWithUserName": "Miseydnað innritanarroynd frá {0}",
"HeaderFavoriteEpisodes": "Yndispartar",
- "HeaderFavoriteSongs": "Yndissangir",
"LabelIpAddressValue": "IP atsetur: {0}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index b05e0d10b4..e05cce47b0 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albums",
"AppDeviceValues": "App : {0}, Appareil : {1}",
- "Application": "Application",
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
- "CameraImageUploadedFrom": "Une nouvelle photo a été téléversée depuis {0}",
- "Channels": "Chaînes",
"ChapterNameValue": "Chapitre {0}",
"Collections": "Collections",
- "DeviceOfflineWithName": "{0} s'est déconnecté",
- "DeviceOnlineWithName": "{0} est connecté",
"FailedLoginAttemptWithUserName": "Tentative de connexion échouée par {0}",
"Favorites": "Favoris",
"Folders": "Dossiers",
"Genres": "Genres",
- "HeaderAlbumArtists": "Artistes de l'album",
"HeaderContinueWatching": "Reprendre le visionnement",
- "HeaderFavoriteAlbums": "Albums favoris",
- "HeaderFavoriteArtists": "Artistes favoris",
"HeaderFavoriteEpisodes": "Épisodes favoris",
"HeaderFavoriteShows": "Séries favorites",
- "HeaderFavoriteSongs": "Chansons favorites",
"HeaderLiveTV": "TV en direct",
"HeaderNextUp": "À Suivre",
- "HeaderRecordingGroups": "Groupes d'enregistrements",
"HomeVideos": "Vidéos personnelles",
"Inherit": "Hérite",
- "ItemAddedWithName": "{0} a été ajouté à la médiathèque",
- "ItemRemovedWithName": "{0} a été supprimé de la médiathèque",
"LabelIpAddressValue": "Adresse IP : {0}",
"LabelRunningTimeValue": "Durée : {0}",
"Latest": "Plus récent",
- "MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
- "MessageApplicationUpdatedTo": "Le serveur Jellyfin a été mis à jour vers la version {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
- "MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour",
"MixedContent": "Contenu mixte",
"Movies": "Films",
"Music": "Musique",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Lecture vidéo démarrée",
"NotificationOptionVideoPlaybackStopped": "Lecture vidéo arrêtée",
"Photos": "Photos",
- "Playlists": "Listes de lecture",
- "Plugin": "Extension",
"PluginInstalledWithName": "{0} a été installé",
"PluginUninstalledWithName": "{0} a été désinstallé",
"PluginUpdatedWithName": "{0} a été mis à jour",
- "ProviderValue": "Fournisseur : {0}",
"ScheduledTaskFailedWithName": "{0} a échoué",
- "ScheduledTaskStartedWithName": "{0} a commencé",
- "ServerNameNeedsToBeRestarted": "{0} doit être redémarré",
"Shows": "Séries",
- "Songs": "Chansons",
"StartupEmbyServerIsLoading": "Serveur Jellyfin en cours de chargement. Réessayez dans quelques instants.",
"SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
- "Sync": "Synchroniser",
- "System": "Système",
"TvShows": "Séries Télé",
- "User": "Utilisateur",
"UserCreatedWithName": "L'utilisateur {0} a été créé",
"UserDeletedWithName": "L'utilisateur {0} supprimé",
"UserDownloadingItemWithValues": "{0} télécharge {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} s'est déconnecté de {1}",
"UserOnlineFromDevice": "{0} s'est connecté de {1}",
"UserPasswordChangedWithName": "Le mot de passe de utilisateur {0} a été modifié",
- "UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}",
"UserStartedPlayingItemWithValues": "{0} joue {1} sur {2}",
"UserStoppedPlayingItemWithValues": "{0} a terminé la lecture de {1} sur {2}",
- "ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque",
- "ValueSpecialEpisodeName": "Spécial - {0}",
"VersionNumber": "Version {0}",
"TasksLibraryCategory": "Médiathèque",
"TasksMaintenanceCategory": "Entretien",
@@ -135,5 +106,7 @@
"TaskMoveTrickplayImages": "Changer l'emplacement des images Trickplay",
"TaskExtractMediaSegmentsDescription": "Extrait ou obtient des segments de média à partir des plugins compatibles avec MediaSegment.",
"CleanupUserDataTaskDescription": "Nettoie toutes les données utilisateur (état de la montre, statut favori, etc.) des supports qui ne sont plus présents depuis au moins 90 jours.",
- "CleanupUserDataTask": "Tâche de nettoyage des données utilisateur"
+ "CleanupUserDataTask": "Tâche de nettoyage des données utilisateur",
+ "LyricDownloadFailureFromForItem": "Le téléchargement des paroles a échoué de {0} pour {1}",
+ "Original": "Original"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 8937b1d0c9..ceba1dcb41 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albums",
"AppDeviceValues": "Application : {0}, Appareil : {1}",
- "Application": "Application",
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
- "CameraImageUploadedFrom": "Une photo a été téléchargée depuis {0}",
- "Channels": "Chaînes",
"ChapterNameValue": "Chapitre {0}",
"Collections": "Collections",
- "DeviceOfflineWithName": "{0} s'est déconnecté",
- "DeviceOnlineWithName": "{0} est connecté",
"FailedLoginAttemptWithUserName": "Échec de connexion depuis {0}",
"Favorites": "Favoris",
"Folders": "Dossiers",
"Genres": "Genres",
- "HeaderAlbumArtists": "Artistes d'albums",
"HeaderContinueWatching": "Continuer de regarder",
- "HeaderFavoriteAlbums": "Albums favoris",
- "HeaderFavoriteArtists": "Artistes préférés",
"HeaderFavoriteEpisodes": "Épisodes favoris",
"HeaderFavoriteShows": "Séries favorites",
- "HeaderFavoriteSongs": "Chansons préférées",
"HeaderLiveTV": "TV en direct",
"HeaderNextUp": "Prochain à venir",
- "HeaderRecordingGroups": "Groupes d'enregistrements",
"HomeVideos": "Vidéos personnelles",
"Inherit": "Hériter",
- "ItemAddedWithName": "{0} a été ajouté à la médiathèque",
- "ItemRemovedWithName": "{0} a été supprimé de la médiathèque",
"LabelIpAddressValue": "Adresse IP : {0}",
"LabelRunningTimeValue": "Durée : {0}",
"Latest": "Derniers",
- "MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
- "MessageApplicationUpdatedTo": "Le serveur Jellyfin a été mis à jour en version {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
- "MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour",
"MixedContent": "Contenu mixte",
"Movies": "Films",
"Music": "Musique",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Lecture vidéo démarrée",
"NotificationOptionVideoPlaybackStopped": "Lecture vidéo arrêtée",
"Photos": "Photos",
- "Playlists": "Listes de lecture",
- "Plugin": "Extension",
"PluginInstalledWithName": "{0} a été installé",
"PluginUninstalledWithName": "{0} a été désinstallé",
"PluginUpdatedWithName": "{0} a été mis à jour",
- "ProviderValue": "Fournisseur : {0}",
"ScheduledTaskFailedWithName": "{0} a échoué",
- "ScheduledTaskStartedWithName": "{0} a démarré",
- "ServerNameNeedsToBeRestarted": "{0} doit être redémarré",
"Shows": "Séries",
- "Songs": "Chansons",
"StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
"SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
- "Sync": "Synchroniser",
- "System": "Système",
"TvShows": "Séries TV",
- "User": "Utilisateur",
"UserCreatedWithName": "L'utilisateur {0} a été créé",
"UserDeletedWithName": "L'utilisateur {0} a été supprimé",
"UserDownloadingItemWithValues": "{0} est en train de télécharger {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} s'est déconnecté depuis {1}",
"UserOnlineFromDevice": "{0} s'est connecté depuis {1}",
"UserPasswordChangedWithName": "Le mot de passe pour l'utilisateur {0} a été modifié",
- "UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}",
"UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}",
"UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}",
- "ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque",
- "ValueSpecialEpisodeName": "Spécial - {0}",
"VersionNumber": "Version {0}",
"TasksChannelsCategory": "Chaînes en ligne",
"TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquants sur Internet en se basant sur la configuration des métadonnées.",
@@ -135,5 +106,7 @@
"TaskExtractMediaSegmentsDescription": "Extrait ou obtient des segments de média à partir des plugins compatibles avec MediaSegment.",
"TaskMoveTrickplayImagesDescription": "Déplace les fichiers trickplay existants en fonction des paramètres de la bibliothèque.",
"CleanupUserDataTaskDescription": "Nettoie toutes les données utilisateur (état de la montre, statut favori, etc.) des supports qui ne sont plus présents depuis au moins 90 jours.",
- "CleanupUserDataTask": "Tâche de nettoyage des données utilisateur"
+ "CleanupUserDataTask": "Tâche de nettoyage des données utilisateur",
+ "LyricDownloadFailureFromForItem": "Le téléchargement des paroles à échoué de {0} pour {1}",
+ "Original": "Original"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ga.json b/Emby.Server.Implementations/Localization/Core/ga.json
index ee6e8b8368..8badf551b3 100644
--- a/Emby.Server.Implementations/Localization/Core/ga.json
+++ b/Emby.Server.Implementations/Localization/Core/ga.json
@@ -1,15 +1,10 @@
{
- "Albums": "Albaim",
"Artists": "Ealaíontóirí",
"AuthenticationSucceededWithUserName": "D'éirigh le fíordheimhniú {0}",
"Books": "Leabhair",
- "CameraImageUploadedFrom": "Uaslódáladh íomhá ceamara nua ó {0}",
- "Channels": "Cainéil",
"ChapterNameValue": "Caibidil {0}",
"Collections": "Bailiúcháin",
"Default": "Réamhshocrú",
- "DeviceOfflineWithName": "Tá {0} dícheangailte",
- "DeviceOnlineWithName": "Tá {0} nasctha",
"External": "Seachtrach",
"FailedLoginAttemptWithUserName": "Theip ar iarracht logáil isteach ó {0}",
"Favorites": "Ceanáin",
@@ -36,32 +31,20 @@
"TaskOptimizeDatabaseDescription": "Comhdhlúthaíonn bunachar sonraí agus gearrtar spás saor in aisce. Má ritheann tú an tasc seo tar éis scanadh a dhéanamh ar an leabharlann nó athruithe eile a dhéanamh a thugann le tuiscint gur cheart go bhfeabhsófaí an fheidhmíocht.",
"TaskMoveTrickplayImagesDescription": "Bogtar comhaid trickplay atá ann cheana de réir socruithe na leabharlainne.",
"AppDeviceValues": "Aip: {0}, Gléas: {1}",
- "Application": "Feidhmchlár",
"Folders": "Fillteáin",
"Forced": "Éigean",
"Genres": "Seánraí",
- "HeaderAlbumArtists": "Ealaíontóirí albam",
"HeaderContinueWatching": "Leanúint ar aghaidh ag Breathnú",
- "HeaderFavoriteAlbums": "Albam is fearr leat",
- "HeaderFavoriteArtists": "Ealaíontóirí is Fearr",
"HeaderFavoriteEpisodes": "Eipeasóid is fearr leat",
"HeaderFavoriteShows": "Seónna is Fearr",
- "HeaderFavoriteSongs": "Amhráin is fearr leat",
"HeaderLiveTV": "Teilifís beo",
"HeaderNextUp": "Ar Aghaidh Suas",
- "HeaderRecordingGroups": "Grúpaí Taifeadta",
"HearingImpaired": "Lag éisteachta",
"HomeVideos": "Físeáin Baile",
"Inherit": "Oidhreacht",
- "ItemAddedWithName": "Cuireadh {0} leis an leabharlann",
- "ItemRemovedWithName": "Baineadh {0} den leabharlann",
"LabelIpAddressValue": "Seoladh IP: {0}",
"LabelRunningTimeValue": "Am rite: {0}",
"Latest": "Is déanaí",
- "MessageApplicationUpdated": "Tá Freastalaí Jellyfin nuashonraithe",
- "MessageApplicationUpdatedTo": "Nuashonraíodh Freastalaí Jellyfin go {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Nuashonraíodh an chuid cumraíochta freastalaí {0}",
- "MessageServerConfigurationUpdated": "Nuashonraíodh cumraíocht an fhreastalaí",
"MixedContent": "Ábhar measctha",
"Movies": "Scannáin",
"Music": "Ceol",
@@ -87,24 +70,15 @@
"NotificationOptionVideoPlayback": "Cuireadh tús le hathsheinm físe",
"NotificationOptionVideoPlaybackStopped": "Cuireadh deireadh le hathsheinm físe",
"Photos": "Grianghraif",
- "Playlists": "Seinmliostaí",
- "Plugin": "Breiseán",
"PluginInstalledWithName": "Suiteáladh {0}",
"PluginUninstalledWithName": "Díshuiteáladh {0}",
"PluginUpdatedWithName": "Nuashonraíodh {0}",
- "ProviderValue": "Soláthraí: {0}",
"ScheduledTaskFailedWithName": "Theip ar {0}",
- "ScheduledTaskStartedWithName": "Thosaigh {0}",
- "ServerNameNeedsToBeRestarted": "Ní mór {0} a atosú",
"Shows": "Seónna",
- "Songs": "Amhráin",
"StartupEmbyServerIsLoading": "Tá freastalaí Jellyfin á luchtú. Bain triail eile as gan mhoill.",
"SubtitleDownloadFailureFromForItem": "Theip ar fhotheidil a íoslódáil ó {0} le haghaidh {1}",
- "Sync": "Sioncrónaigh",
- "System": "Córas",
"TvShows": "Seónna Teilifíse",
"Undefined": "Neamhshainithe",
- "User": "Úsáideoir",
"UserCreatedWithName": "Cruthaíodh úsáideoir {0}",
"UserDeletedWithName": "Scriosadh úsáideoir {0}",
"UserDownloadingItemWithValues": "Tá {0} á íoslódáil {1}",
@@ -112,11 +86,8 @@
"UserOfflineFromDevice": "Tá {0} dícheangailte ó {1}",
"UserOnlineFromDevice": "Tá {0} ar líne ó {1}",
"UserPasswordChangedWithName": "Athraíodh pasfhocal don úsáideoir {0}",
- "UserPolicyUpdatedWithName": "Nuashonraíodh polasaí úsáideora le haghaidh {0}",
"UserStartedPlayingItemWithValues": "Tá {0} ag seinnt {1} ar {2}",
"UserStoppedPlayingItemWithValues": "Chríochnaigh {0} ag imirt {1} ar {2}",
- "ValueHasBeenAddedToLibrary": "Cuireadh {0} le do leabharlann meán",
- "ValueSpecialEpisodeName": "Speisialta - {0}",
"VersionNumber": "Leagan {0}",
"TasksMaintenanceCategory": "Cothabháil",
"TasksLibraryCategory": "Leabharlann",
diff --git a/Emby.Server.Implementations/Localization/Core/gl.json b/Emby.Server.Implementations/Localization/Core/gl.json
index fc5c3fd53d..d3740130ee 100644
--- a/Emby.Server.Implementations/Localization/Core/gl.json
+++ b/Emby.Server.Implementations/Localization/Core/gl.json
@@ -1,13 +1,9 @@
{
- "Albums": "Álbums",
"Collections": "Coleccións",
"ChapterNameValue": "Capítulo {0}",
- "Channels": "Canles",
- "CameraImageUploadedFrom": "Cargouse unha nova imaxe de cámara dende {0}",
"Books": "Libros",
"AuthenticationSucceededWithUserName": "{0} autenticouse correctamente",
"Artists": "Artistas",
- "Application": "Aplicación",
"NotificationOptionServerRestartRequired": "Necesario o reinicio do servidor",
"NotificationOptionPluginUpdateInstalled": "Actualización do plugin instalada",
"NotificationOptionPluginUninstalled": "Plugin desinstalado",
@@ -28,63 +24,41 @@
"Music": "Música",
"Movies": "Películas",
"MixedContent": "Contido mixto",
- "MessageServerConfigurationUpdated": "Actualizouse a configuración do servidor",
- "MessageNamedServerConfigurationUpdatedWithValue": "Actualizouse a sección de configuración {0} do servidor",
- "MessageApplicationUpdatedTo": "O servidor Jellyfin actualizouse a {0}",
- "MessageApplicationUpdated": "O servidor Jellyfin actualizouse",
"Latest": "Último",
"LabelRunningTimeValue": "Tempo en execución: {0}",
"LabelIpAddressValue": "Enderezo IP: {0}",
- "ItemRemovedWithName": "{0} eliminouse da biblioteca",
- "ItemAddedWithName": "{0} engadiuse á biblioteca",
"Inherit": "Herdar",
"HomeVideos": "Videos caseiros",
- "HeaderRecordingGroups": "Grupos de grabación",
"HeaderNextUp": "De seguido",
"HeaderLiveTV": "TV en directo",
- "HeaderFavoriteSongs": "Cancións favoritas",
"HeaderFavoriteShows": "Series de TV favoritas",
"HeaderFavoriteEpisodes": "Episodios favoritos",
- "HeaderFavoriteArtists": "Artistas favoritos",
- "HeaderFavoriteAlbums": "Álbums favoritos",
"HeaderContinueWatching": "Seguir vendo",
- "HeaderAlbumArtists": "Artistas do álbum",
"Genres": "Xéneros",
"Forced": "Forzado",
"Folders": "Cartafoles",
"Favorites": "Favoritos",
"FailedLoginAttemptWithUserName": "Fallo de intento de inicio de sesión dende {0}",
- "DeviceOnlineWithName": "{0} conectouse",
- "DeviceOfflineWithName": "{0} desconectouse",
"Default": "Por defecto",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
"TaskCleanLogs": "Limpar directorio de rexistros",
"TaskCleanActivityLog": "Limpar rexistro de actividade",
"TasksChannelsCategory": "Canles da Internet",
"TaskUpdatePlugins": "Actualizar plugins",
- "User": "Usuario",
"Undefined": "Sen definir",
"TvShows": "Programas de TV",
- "System": "Sistema",
- "Sync": "Sincronizar",
"SubtitleDownloadFailureFromForItem": "Fallou a descarga de subtítulos para {1} dende {0}",
"StartupEmbyServerIsLoading": "O servidor Jellyfin está cargando. Por favor, ténteo axiña outra vez.",
- "Songs": "Cancións",
"Shows": "Programas",
- "ServerNameNeedsToBeRestarted": "{0} precisa ser reiniciado",
- "ScheduledTaskStartedWithName": "{0} comezou",
"ScheduledTaskFailedWithName": "{0} fallou",
- "ProviderValue": "Provedor: {0}",
"PluginUpdatedWithName": "{0} foi actualizado",
"PluginUninstalledWithName": "{0} foi desinstalado",
"PluginInstalledWithName": "{0} foi instalado",
- "Playlists": "Listas de reproducción",
"Photos": "Fotos",
"UserLockedOutWithName": "O usuario {0} foi bloqueado",
"UserDownloadingItemWithValues": "{0} está a ser transferido {1}",
"UserDeletedWithName": "O usuario {0} foi borrado",
"UserCreatedWithName": "O usuario {0} foi creado",
- "Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detida",
"NotificationOptionVideoPlayback": "Reproducción de vídeo iniciada",
"NotificationOptionUserLockedOut": "Usuario bloqueado",
@@ -109,12 +83,9 @@
"TaskCleanCache": "Limpar directorio de caché",
"TaskCleanActivityLogDescription": "Borra do rexistro de actividade as entradas anteriores á data configurada.",
"TasksApplicationCategory": "Aplicación",
- "ValueSpecialEpisodeName": "Especial - {0}",
- "ValueHasBeenAddedToLibrary": "{0} engadiuse á túa biblioteca de medios",
"TasksLibraryCategory": "Biblioteca",
"TasksMaintenanceCategory": "Mantemento",
"VersionNumber": "Versión {0}",
- "UserPolicyUpdatedWithName": "A política de usuario foi actualizada para {0}",
"UserPasswordChangedWithName": "Cambiouse o contrasinal para o usuario {0}",
"UserOnlineFromDevice": "{0} está en liña desde {1}",
"UserOfflineFromDevice": "{0} desconectouse dende {1}",
diff --git a/Emby.Server.Implementations/Localization/Core/gsw.json b/Emby.Server.Implementations/Localization/Core/gsw.json
index 9be6f05ee1..b95e5edecc 100644
--- a/Emby.Server.Implementations/Localization/Core/gsw.json
+++ b/Emby.Server.Implementations/Localization/Core/gsw.json
@@ -1,41 +1,24 @@
{
- "Albums": "Alben",
"AppDeviceValues": "App: {0}, Gerät: {1}",
- "Application": "Applikation",
"Artists": "Künstler",
"AuthenticationSucceededWithUserName": "{0} hat sich angemeldet",
"Books": "Bücher",
- "CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen",
- "Channels": "Kanäle",
"ChapterNameValue": "Kapitel {0}",
"Collections": "Sammlungen",
- "DeviceOfflineWithName": "{0} wurde getrennt",
- "DeviceOnlineWithName": "{0} ist verbunden",
"FailedLoginAttemptWithUserName": "Fählgschlagene Ameldeversuech vo {0}",
"Favorites": "Favorite",
"Folders": "Ordner",
"Genres": "Genre",
- "HeaderAlbumArtists": "Album-Künschtler",
"HeaderContinueWatching": "weiter schauen",
- "HeaderFavoriteAlbums": "Lieblingsalben",
- "HeaderFavoriteArtists": "Lieblings-Künstler",
"HeaderFavoriteEpisodes": "Lieblingsepisoden",
"HeaderFavoriteShows": "Lieblingsserien",
- "HeaderFavoriteSongs": "Lieblingslieder",
"HeaderLiveTV": "Live-Fernseh",
"HeaderNextUp": "Als Nächstes",
- "HeaderRecordingGroups": "Aufnahme-Gruppen",
"HomeVideos": "Heimvideos",
"Inherit": "Vererben",
- "ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
- "ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
"LabelIpAddressValue": "IP-Adresse: {0}",
"LabelRunningTimeValue": "Laufzeit: {0}",
"Latest": "Neueste",
- "MessageApplicationUpdated": "Jellyfin-Server wurde aktualisiert",
- "MessageApplicationUpdatedTo": "Jellyfin-Server wurde auf Version {0} aktualisiert",
- "MessageNamedServerConfigurationUpdatedWithValue": "Der Server-Einstellungsbereich {0} wurde aktualisiert",
- "MessageServerConfigurationUpdated": "Serveriistöuige send aktualisiert worde",
"MixedContent": "Gmeschti Inhäut",
"Movies": "Film",
"Music": "Musig",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Videowedergab gstartet",
"NotificationOptionVideoPlaybackStopped": "Videowedergab gstoppt",
"Photos": "Fotis",
- "Playlists": "Wedergabeliste",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} esch installiert worde",
"PluginUninstalledWithName": "{0} esch deinstalliert worde",
"PluginUpdatedWithName": "{0} esch updated worde",
- "ProviderValue": "Aabieter: {0}",
"ScheduledTaskFailedWithName": "{0} esch fäugschlage",
- "ScheduledTaskStartedWithName": "{0} het gstartet",
- "ServerNameNeedsToBeRestarted": "{0} mues nöi gstartet wärde",
"Shows": "Serie",
- "Songs": "Lieder",
"StartupEmbyServerIsLoading": "Jellyfin Server ladt. Bitte grad noeinisch probiere.",
"SubtitleDownloadFailureFromForItem": "Ondertetle vo {0} för {1} hend ned chönne abeglade wärde",
- "Sync": "Synchronisation",
- "System": "System",
"TvShows": "Färnsehserie",
- "User": "Benotzer",
"UserCreatedWithName": "Benotzer {0} esch erstöut worde",
"UserDeletedWithName": "Benotzer {0} esch glösche worde",
"UserDownloadingItemWithValues": "{0} ladt {1} abe",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} esch vo {1} trennt worde",
"UserOnlineFromDevice": "{0} esch online vo {1}",
"UserPasswordChangedWithName": "S'Passwort för Benotzer {0} esch gänderet worde",
- "UserPolicyUpdatedWithName": "Benotzerrechtlinie för {0} esch aktualisiert worde",
"UserStartedPlayingItemWithValues": "{0} hed d'Wedergab vo {1} of {2} gstartet",
"UserStoppedPlayingItemWithValues": "{0} het d'Wedergab vo {1} of {2} gstoppt",
- "ValueHasBeenAddedToLibrary": "{0} esch dinnere Biblithek hinzuegfüegt worde",
- "ValueSpecialEpisodeName": "Extra - {0}",
"VersionNumber": "Version {0}",
"TaskCleanLogs": "Lösche Log Pfad",
"TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.",
diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json
index 606f464503..af34bf092e 100644
--- a/Emby.Server.Implementations/Localization/Core/he.json
+++ b/Emby.Server.Implementations/Localization/Core/he.json
@@ -1,41 +1,24 @@
{
- "Albums": "אלבומים",
"AppDeviceValues": "יישום: {0}, מכשיר: {1}",
- "Application": "יישום",
"Artists": "אומנים",
"AuthenticationSucceededWithUserName": "{0} אומת בהצלחה",
"Books": "ספרים",
- "CameraImageUploadedFrom": "תמונת מצלמה חדשה הועלתה מתוך {0}",
- "Channels": "ערוצים",
"ChapterNameValue": "פרק {0}",
"Collections": "אוספים",
- "DeviceOfflineWithName": "{0} התנתק",
- "DeviceOnlineWithName": "{0} מחובר",
"FailedLoginAttemptWithUserName": "ניסיון כניסה שגוי דרך {0}",
"Favorites": "מועדפים",
"Folders": "תיקיות",
"Genres": "ז׳אנרים",
- "HeaderAlbumArtists": "אמני האלבום",
"HeaderContinueWatching": "המשך צפייה",
- "HeaderFavoriteAlbums": "אלבומים מועדפים",
- "HeaderFavoriteArtists": "אמנים מועדפים",
"HeaderFavoriteEpisodes": "פרקים מועדפים",
"HeaderFavoriteShows": "תוכניות מועדפות",
- "HeaderFavoriteSongs": "שירים מועדפים",
"HeaderLiveTV": "שידורים חיים",
"HeaderNextUp": "הבא בתור",
- "HeaderRecordingGroups": "קבוצות הקלטה",
"HomeVideos": "סרטונים בייתים",
"Inherit": "הורש",
- "ItemAddedWithName": "{0} נוסף לספרייה",
- "ItemRemovedWithName": "{0} נמחק מהספרייה",
"LabelIpAddressValue": "Ip כתובת: {0}",
"LabelRunningTimeValue": "משך צפייה: {0}",
"Latest": "אחרון",
- "MessageApplicationUpdated": "שרת Jellyfin עודכן",
- "MessageApplicationUpdatedTo": "שרת Jellyfin עודכן לגרסה {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "סעיף הגדרת השרת {0} עודכן",
- "MessageServerConfigurationUpdated": "תצורת השרת עודכנה",
"MixedContent": "תוכן מעורב",
"Movies": "סרטים",
"Music": "מוזיקה",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "ניגון וידאו החל",
"NotificationOptionVideoPlaybackStopped": "ניגון וידאו הופסק",
"Photos": "צילומים",
- "Playlists": "רשימות נגינה",
- "Plugin": "תוסף",
"PluginInstalledWithName": "{0} הותקן",
"PluginUninstalledWithName": "{0} הוסר",
"PluginUpdatedWithName": "{0} עודכן",
- "ProviderValue": "ספק: {0}",
"ScheduledTaskFailedWithName": "{0} נכשל",
- "ScheduledTaskStartedWithName": "{0} החל",
- "ServerNameNeedsToBeRestarted": "{0} דורש הפעלה מחדש",
"Shows": "סדרות",
- "Songs": "שירים",
"StartupEmbyServerIsLoading": "שרת Jellyfin בתהליך טעינה. נא לנסות שוב בקרוב.",
"SubtitleDownloadFailureFromForItem": "הורדת כתוביות מ־{0} עבור {1} נכשלה",
- "Sync": "סנכרון",
- "System": "מערכת",
"TvShows": "סדרות טלוויזיה",
- "User": "משתמש",
"UserCreatedWithName": "המשתמש {0} נוצר",
"UserDeletedWithName": "המשתמש {0} הוסר",
"UserDownloadingItemWithValues": "{0} מוריד את {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} התנתק מ־{1}",
"UserOnlineFromDevice": "{0} מחובר מ־{1}",
"UserPasswordChangedWithName": "הסיסמה שונתה עבור המשתמש {0}",
- "UserPolicyUpdatedWithName": "מדיניות המשתמש {0} עודכנה",
"UserStartedPlayingItemWithValues": "{0} מנגן את {1} על {2}",
"UserStoppedPlayingItemWithValues": "{0} סיים לנגן את {1} על {2}",
- "ValueHasBeenAddedToLibrary": "{0} התווסף לספריית המדיה שלך",
- "ValueSpecialEpisodeName": "מיוחד- {0}",
"VersionNumber": "גרסה {0}",
"TaskRefreshLibrary": "סרוק ספריית מדיה",
"TaskRefreshChapterImages": "חלץ תמונות פרקים",
diff --git a/Emby.Server.Implementations/Localization/Core/he_IL.json b/Emby.Server.Implementations/Localization/Core/he_IL.json
index e8812c8a1d..dedbc56a74 100644
--- a/Emby.Server.Implementations/Localization/Core/he_IL.json
+++ b/Emby.Server.Implementations/Localization/Core/he_IL.json
@@ -1,25 +1,18 @@
{
"Books": "ספרים",
"NameSeasonNumber": "עונה {0}",
- "Channels": "ערוצים",
"Movies": "סרטים",
"Music": "מוזיקה",
"Collections": "אוספים",
- "Albums": "אלבומים",
- "Application": "אפליקציה",
"Artists": "אמנים",
"ChapterNameValue": "פרק {0}",
"External": "חיצונית",
"Favorites": "מועדפים",
"Folders": "תיקיות",
"Genres": "ז'אנרים",
- "HeaderAlbumArtists": "אמני אלבומים",
"HeaderContinueWatching": "להמשיך לצפות",
- "HeaderFavoriteAlbums": "אלבומים אהובים",
- "HeaderFavoriteArtists": "אמנים אהובים",
"HeaderFavoriteEpisodes": "פרקים אהובים",
"HeaderFavoriteShows": "תוכניות אהובות",
- "HeaderFavoriteSongs": "שירים אהובים",
"HeaderLiveTV": "טלוויזיה בשידור חי",
"HeaderNextUp": "הבא",
"HearingImpaired": "ללקויי שמיעה",
diff --git a/Emby.Server.Implementations/Localization/Core/hi.json b/Emby.Server.Implementations/Localization/Core/hi.json
index 9968c56b21..e98a5fbac1 100644
--- a/Emby.Server.Implementations/Localization/Core/hi.json
+++ b/Emby.Server.Implementations/Localization/Core/hi.json
@@ -1,31 +1,20 @@
{
- "Albums": "एल्बम",
- "HeaderRecordingGroups": "रिकॉर्डिंग समूह",
"HeaderNextUp": "इसके बाद",
"HeaderLiveTV": "लाइव टीवी",
- "HeaderFavoriteSongs": "पसंदीदा गीत",
"HeaderFavoriteShows": "पसंदीदा शो",
"HeaderFavoriteEpisodes": "पसंदीदा प्रकरण",
- "HeaderFavoriteArtists": "पसंदीदा कलाकार",
- "HeaderFavoriteAlbums": "पसंदीदा एलबम्स",
"HeaderContinueWatching": "देखना जारी रखें",
- "HeaderAlbumArtists": "एल्बम कलाकार",
"Genres": "शैलियां",
"Forced": "बलपूर्वक",
"Folders": "फ़ोल्डर",
"Favorites": "पसंदीदा",
"FailedLoginAttemptWithUserName": "{0} से संप्रवेश असफल हुआ",
- "DeviceOnlineWithName": "{0} कनेक्ट हो गया है",
- "DeviceOfflineWithName": "{0} डिस्कनेक्ट हो गया है",
"Default": "प्राथमिक",
"Collections": "संग्रह",
"ChapterNameValue": "अध्याय {0}",
- "Channels": "चैनल",
- "CameraImageUploadedFrom": "{0} से एक नया कैमरा छवि अपलोड की गई है",
"Books": "पुस्तकें",
"AuthenticationSucceededWithUserName": "{0} सफलतापूर्वक प्रमाणित किया गया",
"Artists": "कलाकार",
- "Application": "एप्लिकेशन",
"AppDeviceValues": "एप: {0}, उपकरण: {1}",
"NotificationOptionPluginUninstalled": "प्लगइन अनइंस्टाल हो गया",
"NotificationOptionPluginInstalled": "प्लगइन इनस्टॉल हो गया",
@@ -44,13 +33,8 @@
"Music": "संगीत",
"Movies": "फ़िल्म",
"MixedContent": "मिला-जुला कंटेंट",
- "MessageServerConfigurationUpdated": "सर्वर कॉन्फ़िगरेशन अपडेट हो गया है",
- "MessageNamedServerConfigurationUpdatedWithValue": "सर्वर कॉन्फ़िगरेशन भाग {0} अपडेट हो गया है",
- "MessageApplicationUpdatedTo": "जैलीफिन सर्वर {0} में अपडेट हो गया है",
- "MessageApplicationUpdated": "जैलीफिन सर्वर अपडेट हो गया है",
"Latest": "सबसे नया",
"LabelIpAddressValue": "आई पी एड्रेस: {0}",
- "ItemRemovedWithName": "{0} लाइब्रेरी में से निकाल दिया है",
"HomeVideos": "होम चलचित्र",
"NotificationOptionVideoPlayback": "वीडियो प्लेबैक शुरू हुआ",
"NotificationOptionUserLockedOut": "उपयोगकर्ता लॉक हो गया",
@@ -59,22 +43,16 @@
"NotificationOptionPluginUpdateInstalled": "प्लगइन अद्यतन स्थापित",
"NotificationOptionNewLibraryContent": "नई सामग्री जोड़ी गई",
"LabelRunningTimeValue": "चलने का समय: {0}",
- "ItemAddedWithName": "{0} को लाइब्रेरी में जोड़ा गया",
"Inherit": "इनहेरिट",
"NotificationOptionVideoPlaybackStopped": "चलचित्र रुका हुआ",
"PluginUninstalledWithName": "{0} अनइंस्टॉल हुए",
"PluginInstalledWithName": "{0} इंस्टॉल हुए",
- "Plugin": "प्लग-इन",
- "Playlists": "प्लेलिस्ट",
"Photos": "तस्वीरें",
"External": "बाहरी",
"PluginUpdatedWithName": "{0} अपडेट हुए",
- "ScheduledTaskStartedWithName": "{0} शुरू हुए",
- "Songs": "गाने",
"UserStartedPlayingItemWithValues": "{0} {2} पर {1} खेल रहे हैं",
"UserStoppedPlayingItemWithValues": "{0} ने {2} पर {1} खेलना खत्म किया",
"StartupEmbyServerIsLoading": "जेलीफ़िन सर्वर लोड हो रहा है। कृपया शीघ्र ही पुन: प्रयास करें।",
- "ServerNameNeedsToBeRestarted": "{0} रीस्टार्ट करने की आवश्यकता है",
"UserCreatedWithName": "उपयोगकर्ता {0} बनाया गया",
"UserDownloadingItemWithValues": "{0} डाउनलोड हो रहा है",
"UserOfflineFromDevice": "{0} {1} से डिस्कनेक्ट हो गया है",
@@ -83,20 +61,13 @@
"Shows": "शो",
"UserPasswordChangedWithName": "उपयोगकर्ता {0} के लिए पासवर्ड बदल दिया गया है",
"UserDeletedWithName": "उपयोगकर्ता {0} हटा दिया गया",
- "UserPolicyUpdatedWithName": "{0} के लिए उपयोगकर्ता नीति अपडेट कर दी गई है",
- "User": "उपयोगकर्ता",
"SubtitleDownloadFailureFromForItem": "{1} के लिए {0} से उपशीर्षक डाउनलोड करने में विफल",
- "ProviderValue": "प्रदाता: {0}",
"ScheduledTaskFailedWithName": "{0}असफल",
"UserLockedOutWithName": "उपयोगकर्ता {0} को लॉक आउट कर दिया गया है",
- "System": "प्रणाली",
"TvShows": "टीवी शो",
"HearingImpaired": "मूक बधिर",
- "ValueSpecialEpisodeName": "विशेष - {0}",
"TasksMaintenanceCategory": "रखरखाव",
- "Sync": "समाकलयति",
"VersionNumber": "{0} पाठान्तर",
- "ValueHasBeenAddedToLibrary": "{0} आपके माध्यम ग्रन्थालय में उपजात हो गया हैं",
"TasksLibraryCategory": "संग्रहालय",
"TaskOptimizeDatabase": "जानकारी प्रवृद्धि",
"TaskDownloadMissingSubtitles": "लापता अनुलेख डाउनलोड करें",
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index 5800764587..8794339fb1 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumi",
"AppDeviceValues": "Aplikacija: {0}, Uređaj: {1}",
- "Application": "Aplikacija",
"Artists": "Izvođači",
"AuthenticationSucceededWithUserName": "{0} uspješno ovjerena",
"Books": "Knjige",
- "CameraImageUploadedFrom": "Nova fotografija sa kamere je učitana iz {0}",
- "Channels": "Kanali",
"ChapterNameValue": "Poglavlje {0}",
"Collections": "Zbirke",
- "DeviceOfflineWithName": "{0} je prekinuo vezu",
- "DeviceOnlineWithName": "{0} je povezan",
"FailedLoginAttemptWithUserName": "Neuspješan pokušaj prijave od {0}",
"Favorites": "Favoriti",
"Folders": "Mape",
"Genres": "Žanrovi",
- "HeaderAlbumArtists": "Izvođači albuma",
"HeaderContinueWatching": "Nastavi gledati",
- "HeaderFavoriteAlbums": "Omiljeni albumi",
- "HeaderFavoriteArtists": "Omiljeni izvođači",
"HeaderFavoriteEpisodes": "Omiljene epizode",
"HeaderFavoriteShows": "Omiljene serije",
- "HeaderFavoriteSongs": "Omiljene pjesme",
"HeaderLiveTV": "TV uživo",
"HeaderNextUp": "Sljedeće na redu",
- "HeaderRecordingGroups": "Grupa snimka",
"HomeVideos": "Kućni video",
"Inherit": "Naslijedi",
- "ItemAddedWithName": "{0} je dodano u biblioteku",
- "ItemRemovedWithName": "{0} je uklonjeno iz biblioteke",
"LabelIpAddressValue": "IP adresa: {0}",
"LabelRunningTimeValue": "Vrijeme rada: {0}",
"Latest": "Najnovije",
- "MessageApplicationUpdated": "Jellyfin server je ažuriran",
- "MessageApplicationUpdatedTo": "Jellyfin server je ažuriran na {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Dio konfiguracije servera {0} je ažuriran",
- "MessageServerConfigurationUpdated": "Konfiguracija servera je ažurirana",
"MixedContent": "Miješani sadržaj",
"Movies": "Filmovi",
"Music": "Glazba",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Reprodukcija videa započela",
"NotificationOptionVideoPlaybackStopped": "Reprodukcija videa zaustavljena",
"Photos": "Fotografije",
- "Playlists": "Popisi za reprodukciju",
- "Plugin": "Dodatak",
"PluginInstalledWithName": "{0} je instalirano",
"PluginUninstalledWithName": "{0} je deinstalirano",
"PluginUpdatedWithName": "{0} je ažurirano",
- "ProviderValue": "Pružatelj: {0}",
"ScheduledTaskFailedWithName": "{0} neuspjelo",
- "ScheduledTaskStartedWithName": "{0} pokrenuto",
- "ServerNameNeedsToBeRestarted": "{0} treba ponovno pokrenuti",
"Shows": "Emisije",
- "Songs": "Pjesme",
"StartupEmbyServerIsLoading": "Jellyfin server se učitava. Pokušajte ponovo uskoro.",
"SubtitleDownloadFailureFromForItem": "Titlovi nisu uspješno preuzeti od {0} za {1}",
- "Sync": "Sinkronizacija",
- "System": "Sustav",
"TvShows": "TV emisije",
- "User": "Korisnik",
"UserCreatedWithName": "Korisnik {0} je kreiran",
"UserDeletedWithName": "Korisnik {0} je obrisan",
"UserDownloadingItemWithValues": "{0} preuzima {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} prekinuo vezu od {1}",
"UserOnlineFromDevice": "{0} povezan od {1}",
"UserPasswordChangedWithName": "Lozinka je promijenjena za korisnika {0}",
- "UserPolicyUpdatedWithName": "Pravila za korisnika ažurirana su za {0}",
"UserStartedPlayingItemWithValues": "{0} je pokrenuo reprodukciju {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je završio reprodukciju {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} je dodano u biblioteku medija",
- "ValueSpecialEpisodeName": "Posebno – {0}",
"VersionNumber": "Verzija {0}",
"TaskRefreshLibraryDescription": "Skenira biblioteku medija radi novih datoteka i osvježava metapodatke.",
"TaskRefreshLibrary": "Skeniraj biblioteku medija",
diff --git a/Emby.Server.Implementations/Localization/Core/ht.json b/Emby.Server.Implementations/Localization/Core/ht.json
index f1ff775155..da90a92339 100644
--- a/Emby.Server.Implementations/Localization/Core/ht.json
+++ b/Emby.Server.Implementations/Localization/Core/ht.json
@@ -1,33 +1,22 @@
{
"Books": "Liv",
"TasksLibraryCategory": "Libreri",
- "Albums": "Albòm yo",
"Artists": "Atis yo",
- "Application": "Aplikasyon",
- "Channels": "Kanal yo",
"ChapterNameValue": "Chapit {0}",
"Default": "Defo",
- "DeviceOnlineWithName": "{0} konekte",
- "DeviceOfflineWithName": "{0} dekonekte",
"External": "Extèn",
"Collections": "Koleksyon yo",
"Favorites": "Pi Renmen",
"Folders": "Dosye",
"Genres": "Jan yo",
"Forced": "Fòse",
- "HeaderAlbumArtists": "Albòm Atis",
"HeaderContinueWatching": "Kontinye Kade",
- "HeaderFavoriteAlbums": "Albòm Pi Renmen",
- "HeaderFavoriteArtists": "Atis Pi Renmen",
"HeaderFavoriteEpisodes": "Epizòd Pi Renmen",
"HeaderFavoriteShows": "Emisyon Pi Renmen",
- "HeaderFavoriteSongs": "Mizik Pi Renmen",
"HeaderLiveTV": "Televizyon an Direk",
"HeaderNextUp": "Pwochen an",
"HomeVideos": "Videyo Lakay",
"Latest": "Pi Resan",
- "MessageApplicationUpdated": "Sèvè Jellyfin met a jou",
- "MessageApplicationUpdatedTo": "Sèvè Jellyfin met a jou sou {0}",
"Movies": "Fim",
"MixedContent": "Kontni Melanje",
"Music": "Mizik",
@@ -42,12 +31,8 @@
"PluginUninstalledWithName": "{0} te dezenstale",
"PluginUpdatedWithName": "{0} te mi a jou",
"ScheduledTaskFailedWithName": "{0} echwe",
- "ScheduledTaskStartedWithName": "{0} komanse",
- "Songs": "Mizik yo",
"Shows": "Emisyon yo",
- "System": "Sistèm",
"TvShows": "Emisyon Tele",
- "User": "Itilizatè",
"UserCreatedWithName": "Itilizatè {0} kreye",
"UserDeletedWithName": "Itilizatè {0} a efase",
"UserDownloadingItemWithValues": "{0} ap telechaje {1}",
@@ -55,13 +40,10 @@
"UserStartedPlayingItemWithValues": "{0} ap jwe {1} sou {2}",
"UserStoppedPlayingItemWithValues": "{0} fin jwe {1} sou {2}",
"UserPasswordChangedWithName": "Modpas la chanje pou Itilizatè {0}",
- "ValueSpecialEpisodeName": "Spesyal - {0}",
"VersionNumber": "Vesyon {0}",
"TasksApplicationCategory": "Aplikasyon",
"TasksMaintenanceCategory": "Antretyen",
"AppDeviceValues": "Aplikasyon: {0}, Aparèy: {1}",
"AuthenticationSucceededWithUserName": "{0} otantifye avèk siksè",
- "CameraImageUploadedFrom": "Une nouvelle image de la caméra a été téléchargée depuis {0}",
- "Original": "Original",
- "Playlists": "Pleliss"
+ "Original": "Original"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 31df91693c..e1c1ec109d 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumok",
"AppDeviceValues": "Program: {0}, Eszköz: {1}",
- "Application": "Alkalmazás",
"Artists": "Előadók",
"AuthenticationSucceededWithUserName": "{0} sikeresen hitelesítve",
"Books": "Könyvek",
- "CameraImageUploadedFrom": "Új kamerakép lett feltöltve innen: {0}",
- "Channels": "Csatornák",
"ChapterNameValue": "{0}. jelenet",
"Collections": "Gyűjtemények",
- "DeviceOfflineWithName": "{0} kijelentkezett",
- "DeviceOnlineWithName": "{0} belépett",
"FailedLoginAttemptWithUserName": "Sikertelen bejelentkezési kísérlet innen: {0}",
"Favorites": "Kedvencek",
"Folders": "Mappák",
"Genres": "Műfajok",
- "HeaderAlbumArtists": "Albumelőadók",
"HeaderContinueWatching": "Megtekintés folytatása",
- "HeaderFavoriteAlbums": "Kedvenc albumok",
- "HeaderFavoriteArtists": "Kedvenc előadók",
"HeaderFavoriteEpisodes": "Kedvenc epizódok",
"HeaderFavoriteShows": "Kedvenc sorozatok",
- "HeaderFavoriteSongs": "Kedvenc számok",
"HeaderLiveTV": "Élő TV",
"HeaderNextUp": "Következik",
- "HeaderRecordingGroups": "Felvételi csoportok",
"HomeVideos": "Otthoni videók",
"Inherit": "Öröklés",
- "ItemAddedWithName": "{0} hozzáadva a médiatárhoz",
- "ItemRemovedWithName": "{0} eltávolítva a médiatárból",
"LabelIpAddressValue": "IP-cím: {0}",
"LabelRunningTimeValue": "Lejátszási idő: {0}",
"Latest": "Legújabb",
- "MessageApplicationUpdated": "A Jellyfin kiszolgáló frissítve lett",
- "MessageApplicationUpdatedTo": "A Jellyfin kiszolgáló frissítve lett a következőre: {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "A kiszolgálókonfigurációs rész frissítve lett: {0}",
- "MessageServerConfigurationUpdated": "A kiszolgálókonfiguráció frissítve lett",
"MixedContent": "Vegyes tartalom",
"Movies": "Filmek",
"Music": "Zenék",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Videólejátszás elkezdve",
"NotificationOptionVideoPlaybackStopped": "Videólejátszás leállítva",
"Photos": "Fényképek",
- "Playlists": "Lejátszási listák",
- "Plugin": "Bővítmény",
"PluginInstalledWithName": "{0} telepítve",
"PluginUninstalledWithName": "{0} eltávolítva",
"PluginUpdatedWithName": "{0} frissítve",
- "ProviderValue": "Szolgáltató: {0}",
"ScheduledTaskFailedWithName": "{0} sikertelen",
- "ScheduledTaskStartedWithName": "{0} elkezdve",
- "ServerNameNeedsToBeRestarted": "A(z) {0} újraindítása szükséges",
"Shows": "Sorozatok",
- "Songs": "Számok",
"StartupEmbyServerIsLoading": "A Jellyfin kiszolgáló betöltődik. Próbálja újra hamarosan.",
"SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0}, ehhez: {1}",
- "Sync": "Szinkronizálás",
- "System": "Rendszer",
"TvShows": "TV műsorok",
- "User": "Felhasználó",
"UserCreatedWithName": "{0} felhasználó létrehozva",
"UserDeletedWithName": "{0} felhasználó törölve",
"UserDownloadingItemWithValues": "{0} letölti: {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
"UserOnlineFromDevice": "{0} online innen: {1}",
"UserPasswordChangedWithName": "{0} jelszava megváltozott",
- "UserPolicyUpdatedWithName": "{0} felhasználói házirendje frissült",
"UserStartedPlayingItemWithValues": "{0} elkezdte lejátszani a következőt: {1}, itt: {2}",
"UserStoppedPlayingItemWithValues": "{0} befejezte a következő lejátszását: {1}, itt: {2}",
- "ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
- "ValueSpecialEpisodeName": "Különkiadás – {0}",
"VersionNumber": "Verzió: {0}",
"TaskCleanTranscode": "Átkódolási könyvtár ürítése",
"TaskUpdatePluginsDescription": "Letölti és telepíti a frissítéseket azokhoz a bővítményekhez, amelyeknél az automatikus frissítés engedélyezve van.",
diff --git a/Emby.Server.Implementations/Localization/Core/hy.json b/Emby.Server.Implementations/Localization/Core/hy.json
index 563f842923..b79b540bf4 100644
--- a/Emby.Server.Implementations/Localization/Core/hy.json
+++ b/Emby.Server.Implementations/Localization/Core/hy.json
@@ -2,38 +2,27 @@
"TasksLibraryCategory": "Գրադարան",
"TasksApplicationCategory": "Հավելված",
"TaskCleanActivityLog": "Մաքրել ակտիվության մատյանը",
- "Application": "Հավելված",
"AuthenticationSucceededWithUserName": "{0} հաջողությամբ վավերականացվել են",
"Books": "Գրքեր",
- "CameraImageUploadedFrom": "Նոր լուսանկար է վերբեռնվել {0}-ի կողմից",
- "Channels": "Ալիքներ",
- "DeviceOfflineWithName": "{0}ը անջատվեց",
"External": "Արտաքին",
"FailedLoginAttemptWithUserName": "Ձախողված մուտքի փործ {0}-ի կողմից",
"Folders": "Պանակներ",
"HeaderContinueWatching": "Շարունակել դիտումը",
"Inherit": "Ժառանգել",
- "ItemAddedWithName": "{0}ը ավացված է գրադարանի մեջ",
- "ItemRemovedWithName": "{0}ը հեռացված է գրադարանից",
"LabelIpAddressValue": "IP հասցե` {0}",
"Movies": "Ֆիլմեր",
"Music": "Երաժշտություն",
"NameSeasonNumber": "Սեզոն {0}",
"Photos": "Լուսանկարներ",
"PluginInstalledWithName": "{0}ն տեղադրված է",
- "Songs": "Երգեր",
- "System": "Համակարգ",
"TvShows": "Հեռուստասերիալներ",
- "User": "Օգտատեր",
"VersionNumber": "Տարբերակ {0}",
"TasksMaintenanceCategory": "Սպասարկում",
"TasksChannelsCategory": "Ինտերնետային ալիքներ",
"TaskRefreshPeople": "Թարմացնել մարդկանց",
"TaskRefreshChannels": "Թարմացնել ալիքները",
"TaskDownloadMissingSubtitles": "Ներբեռնել պակասող ենթագրերը",
- "Albums": "Ալբոմներ",
"AppDeviceValues": "Հավելված` {0}, Սարք `{1}",
"ChapterNameValue": "Գլուխ {0}",
- "Collections": "Հավաքածուներ",
- "DeviceOnlineWithName": "{0}-ն միացված է"
+ "Collections": "Հավաքածուներ"
}
diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json
index fb228baf40..65c03e70f2 100644
--- a/Emby.Server.Implementations/Localization/Core/id.json
+++ b/Emby.Server.Implementations/Localization/Core/id.json
@@ -1,48 +1,31 @@
{
- "Albums": "Album",
"AuthenticationSucceededWithUserName": "{0} berhasil diautentikasi",
"AppDeviceValues": "Aplikasi : {0}, Perangkat : {1}",
"LabelRunningTimeValue": "Waktu berjalan: {0}",
- "MessageApplicationUpdatedTo": "Jellyfin Server sudah diperbarui ke {0}",
- "MessageApplicationUpdated": "Jellyfin Server sudah diperbarui",
"Latest": "Terbaru",
"LabelIpAddressValue": "Alamat IP: {0}",
- "ItemRemovedWithName": "{0} sudah dihapus dari pustaka",
- "ItemAddedWithName": "{0} telah dimasukkan ke dalam pustaka",
"Inherit": "Warisi",
"HomeVideos": "Video Rumahan",
- "HeaderRecordingGroups": "Grup Rekaman",
"HeaderNextUp": "Selanjutnya",
"HeaderLiveTV": "Siaran langsung",
- "HeaderFavoriteSongs": "Lagu Favorit",
"HeaderFavoriteShows": "Tayangan Favorit",
"HeaderFavoriteEpisodes": "Episode Favorit",
- "HeaderFavoriteArtists": "Artis Favorit",
- "HeaderFavoriteAlbums": "Album Favorit",
"HeaderContinueWatching": "Lanjut Menonton",
- "HeaderAlbumArtists": "Album Artis",
"Genres": "Aliran",
"Folders": "Folder",
"Favorites": "Favorit",
"Collections": "Koleksi",
"Books": "Buku",
"Artists": "Artis",
- "Application": "Aplikasi",
"ChapterNameValue": "Bagian {0}",
- "Channels": "Saluran",
"TvShows": "Seri TV",
"SubtitleDownloadFailureFromForItem": "Subtitel gagal diunduh dari {0} untuk {1}",
"StartupEmbyServerIsLoading": "Server Jellyfin sedang dimuat. Silakan coba lagi nanti.",
- "Songs": "Lagu",
- "Playlists": "Daftar putar",
"NotificationOptionPluginUninstalled": "Plugin dihapus",
"MusicVideos": "Video Musik",
"VersionNumber": "Versi {0}",
- "ValueSpecialEpisodeName": "Spesial - {0}",
- "ValueHasBeenAddedToLibrary": "{0} telah ditambahkan ke pustaka media Anda",
"UserStoppedPlayingItemWithValues": "{0} telah selesai memutar {1} pada {2}",
"UserStartedPlayingItemWithValues": "{0} sedang memutar {1} pada {2}",
- "UserPolicyUpdatedWithName": "Kebijakan pengguna telah diperbarui untuk {0}",
"UserPasswordChangedWithName": "Kata sandi telah diubah untuk pengguna {0}",
"UserOnlineFromDevice": "{0} sedang daring dari {1}",
"UserOfflineFromDevice": "{0} telah terputus dari {1}",
@@ -50,17 +33,10 @@
"UserDownloadingItemWithValues": "{0} sedang mengunduh {1}",
"UserDeletedWithName": "Pengguna {0} telah dihapus",
"UserCreatedWithName": "Pengguna {0} telah dibuat",
- "User": "Pengguna",
- "System": "Sistem",
- "Sync": "Sinkron",
"Shows": "Tayangan",
- "ServerNameNeedsToBeRestarted": "{0} perlu dimuat ulang",
- "ScheduledTaskStartedWithName": "{0} dimulai",
"ScheduledTaskFailedWithName": "{0} gagal",
- "ProviderValue": "Penyedia: {0}",
"PluginUpdatedWithName": "{0} telah diperbarui",
"PluginInstalledWithName": "{0} telah dipasang",
- "Plugin": "Plugin",
"Photos": "Foto",
"NotificationOptionUserLockedOut": "Pengguna terkunci",
"NotificationOptionTaskFailed": "Kegagalan tugas terjadwal",
@@ -79,12 +55,7 @@
"NameInstallFailed": "{0} penginstalan gagal",
"Music": "Musik",
"Movies": "Film",
- "MessageServerConfigurationUpdated": "Konfigurasi server telah diperbarui",
- "MessageNamedServerConfigurationUpdatedWithValue": "Bagian konfigurasi server {0} telah diperbarui",
"FailedLoginAttemptWithUserName": "Gagal upaya login dari {0}",
- "CameraImageUploadedFrom": "Sebuah gambar kamera baru telah diunggah dari {0}",
- "DeviceOfflineWithName": "{0} telah terputus",
- "DeviceOnlineWithName": "{0} telah terhubung",
"NotificationOptionVideoPlaybackStopped": "Pemutaran video berhenti",
"NotificationOptionVideoPlayback": "Pemutaran video dimulai",
"NotificationOptionAudioPlaybackStopped": "Pemutaran audio berhenti",
diff --git a/Emby.Server.Implementations/Localization/Core/is.json b/Emby.Server.Implementations/Localization/Core/is.json
index 900502ccdd..c9ca00afdf 100644
--- a/Emby.Server.Implementations/Localization/Core/is.json
+++ b/Emby.Server.Implementations/Localization/Core/is.json
@@ -1,36 +1,22 @@
{
"LabelIpAddressValue": "IP tala: {0}",
- "ItemRemovedWithName": "{0} var fjarlægt úr safninu",
- "ItemAddedWithName": "{0} var bætt í safnið",
"Inherit": "Erfa",
"HomeVideos": "Heimamyndbönd",
- "HeaderRecordingGroups": "Upptökuhópar",
"HeaderNextUp": "Næst á dagskrá",
"HeaderLiveTV": "Sjónvarp í beinni útsendingu",
- "HeaderFavoriteSongs": "Uppáhalds Lög",
"HeaderFavoriteShows": "Uppáhalds Sjónvarpsþættir",
"HeaderFavoriteEpisodes": "Uppáhalds Þættir",
- "HeaderFavoriteArtists": "Uppáhalds Listamenn",
- "HeaderFavoriteAlbums": "Uppáhalds Plötur",
"HeaderContinueWatching": "Halda áfram að horfa",
- "HeaderAlbumArtists": "Listamaður á umslagi",
"Genres": "Stefnur",
"Folders": "Möppur",
"Favorites": "Uppáhalds",
"FailedLoginAttemptWithUserName": "{0} mistókst að auðkenna sig",
- "DeviceOnlineWithName": "{0} hefur tengst",
- "DeviceOfflineWithName": "{0} hefur aftengst",
"Collections": "Söfn",
"ChapterNameValue": "Kafli {0}",
- "Channels": "Rásir",
- "CameraImageUploadedFrom": "{0} hefur hlaðið upp nýrri ljósmynd úr myndavél sinni",
"Books": "Bækur",
"AuthenticationSucceededWithUserName": "Auðkenning fyrir {0} tókst",
"Artists": "Listamenn",
- "Application": "Forrit",
"AppDeviceValues": "Snjallforrit: {0}, Tæki: {1}",
- "Albums": "Plötur",
- "Plugin": "Viðbótarvirkni",
"Photos": "Ljósmyndir",
"NotificationOptionVideoPlaybackStopped": "Myndbandsafspilun stöðvuð",
"NotificationOptionVideoPlayback": "Myndbandsafspilun hafin",
@@ -49,13 +35,8 @@
"NameSeasonUnknown": "Þáttaröð óþekkt",
"NameSeasonNumber": "Þáttaröð {0}",
"MixedContent": "Blandað efni",
- "MessageServerConfigurationUpdated": "Stillingar þjóns hafa verið uppfærðar",
- "MessageApplicationUpdatedTo": "Jellyfin þjónn hefur verið uppfærður í {0}",
- "MessageApplicationUpdated": "Jellyfin þjónn hefur verið uppfærður",
"Latest": "Nýjasta",
"LabelRunningTimeValue": "spilunartími: {0}",
- "User": "Notandi",
- "System": "Kerfi",
"NotificationOptionNewLibraryContent": "Nýju efni bætt við",
"NewVersionIsAvailable": "Ný útgáfa af Jellyfin þjón er tilbúin til niðurhals.",
"NameInstallFailed": "{0} uppsetning mistókst",
@@ -65,10 +46,6 @@
"UserDeletedWithName": "Notanda {0} hefur verið eytt",
"UserCreatedWithName": "Notandi {0} hefur verið stofnaður",
"TvShows": "Sjónvarpsþættir",
- "Sync": "Samstilla",
- "Songs": "Lög",
- "ServerNameNeedsToBeRestarted": "{0} þarf að vera endurræstur",
- "ScheduledTaskStartedWithName": "{0} hafin",
"ScheduledTaskFailedWithName": "{0} mistókst",
"PluginUpdatedWithName": "{0} var uppfært",
"PluginUninstalledWithName": "{0} var fjarlægt",
@@ -76,21 +53,15 @@
"NotificationOptionTaskFailed": "Tímasett verkefni mistókst",
"StartupEmbyServerIsLoading": "Jellyfin netþjónnin er að ræsa sig upp. Vinsamlegast reyndu aftur fljótlega.",
"VersionNumber": "Útgáfa {0}",
- "ValueHasBeenAddedToLibrary": "{0} hefur verið bætt við í gagnasafnið þitt",
"UserStoppedPlayingItemWithValues": "{0} hefur lokið spilunar af {1} á {2}",
"UserStartedPlayingItemWithValues": "{0} er að spila {1} á {2}",
- "UserPolicyUpdatedWithName": "Notandaregla hefur verið uppfærð fyrir {0}",
"UserPasswordChangedWithName": "Lykilorði fyrir notandann {0} hefur verið breytt",
"UserOnlineFromDevice": "{0} hefur verið virkur síðan {1}",
"UserOfflineFromDevice": "{0} hefur aftengst frá {1}",
"UserLockedOutWithName": "Notandi {0} hefur verið læstur úti",
"UserDownloadingItemWithValues": "{0} hleður niður {1}",
"SubtitleDownloadFailureFromForItem": "Tókst ekki að hala niður skjátextum frá {0} til {1}",
- "ProviderValue": "Efnisveita: {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Stilling {0} hefur verið uppfærð á netþjón",
- "ValueSpecialEpisodeName": "Sérstaktur - {0}",
"Shows": "Þættir",
- "Playlists": "Efnisskrár",
"TaskRefreshChannelsDescription": "Endurhlaða upplýsingum netrása.",
"TaskRefreshChannels": "Endurhlaða Rásir",
"TaskCleanTranscodeDescription": "Eyða umkóðuðum skrám sem eru meira en einum degi eldri.",
diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json
index 41d97442ed..6053aec896 100644
--- a/Emby.Server.Implementations/Localization/Core/it.json
+++ b/Emby.Server.Implementations/Localization/Core/it.json
@@ -1,41 +1,24 @@
{
- "Albums": "Album",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
- "Application": "Applicazione",
"Artists": "Artisti",
"AuthenticationSucceededWithUserName": "{0} autenticato correttamente",
"Books": "Libri",
- "CameraImageUploadedFrom": "È stata caricata una nuova fotografia da {0}",
- "Channels": "Canali",
"ChapterNameValue": "Capitolo {0}",
"Collections": "Collezioni",
- "DeviceOfflineWithName": "{0} si è disconnesso",
- "DeviceOnlineWithName": "{0} è connesso",
"FailedLoginAttemptWithUserName": "Tentativo di accesso non riuscito da {0}",
"Favorites": "Preferiti",
"Folders": "Cartelle",
"Genres": "Generi",
- "HeaderAlbumArtists": "Artisti dell'album",
"HeaderContinueWatching": "Continua a guardare",
- "HeaderFavoriteAlbums": "Album preferiti",
- "HeaderFavoriteArtists": "Artisti preferiti",
"HeaderFavoriteEpisodes": "Episodi preferiti",
"HeaderFavoriteShows": "Serie TV preferite",
- "HeaderFavoriteSongs": "Brani preferiti",
"HeaderLiveTV": "Diretta TV",
"HeaderNextUp": "Prossimo",
- "HeaderRecordingGroups": "Gruppi di registrazione",
"HomeVideos": "Video personali",
"Inherit": "Eredita",
- "ItemAddedWithName": "{0} è stato aggiunto alla libreria",
- "ItemRemovedWithName": "{0} è stato rimosso dalla libreria",
"LabelIpAddressValue": "Indirizzo IP: {0}",
"LabelRunningTimeValue": "Durata: {0}",
"Latest": "Novità",
- "MessageApplicationUpdated": "Jellyfin Server è stato aggiornato",
- "MessageApplicationUpdatedTo": "Jellyfin Server è stato aggiornato a {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "La sezione {0} della configurazione server è stata aggiornata",
- "MessageServerConfigurationUpdated": "La configurazione del server è stata aggiornata",
"MixedContent": "Contenuto misto",
"Movies": "Film",
"Music": "Musica",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Riproduzione video iniziata",
"NotificationOptionVideoPlaybackStopped": "Riproduzione video interrotta",
"Photos": "Foto",
- "Playlists": "Scalette",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} è stato installato",
"PluginUninstalledWithName": "{0} è stato disinstallato",
"PluginUpdatedWithName": "{0} è stato aggiornato",
- "ProviderValue": "Provider: {0}",
"ScheduledTaskFailedWithName": "{0} non riuscito",
- "ScheduledTaskStartedWithName": "{0} avviato",
- "ServerNameNeedsToBeRestarted": "{0} deve essere riavviato",
"Shows": "Serie TV",
- "Songs": "Brani",
"StartupEmbyServerIsLoading": "Jellyfin Server si sta avviando. Riprova più tardi.",
"SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}",
- "Sync": "Sincronizza",
- "System": "Sistema",
"TvShows": "Serie TV",
- "User": "Utente",
"UserCreatedWithName": "L'utente {0} è stato creato",
"UserDeletedWithName": "L'utente {0} è stato eliminato",
"UserDownloadingItemWithValues": "{0} sta scaricando {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} si è disconnesso da {1}",
"UserOnlineFromDevice": "{0} è online su {1}",
"UserPasswordChangedWithName": "La password è stata cambiata per l'utente {0}",
- "UserPolicyUpdatedWithName": "La policy dell'utente è stata aggiornata per {0}",
"UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di {1} su {2}",
"UserStoppedPlayingItemWithValues": "{0} ha interrotto la riproduzione di {1} su {2}",
- "ValueHasBeenAddedToLibrary": "{0} è stato aggiunto alla tua libreria multimediale",
- "ValueSpecialEpisodeName": "Speciale - {0}",
"VersionNumber": "Versione {0}",
"TaskRefreshChannelsDescription": "Aggiorna le informazioni dei canali internet.",
"TaskDownloadMissingSubtitlesDescription": "Cerca su internet i sottotitoli mancanti basandosi sulle configurazioni dei metadati.",
diff --git a/Emby.Server.Implementations/Localization/Core/ja.json b/Emby.Server.Implementations/Localization/Core/ja.json
index 7b0bdb296f..39e5af717c 100644
--- a/Emby.Server.Implementations/Localization/Core/ja.json
+++ b/Emby.Server.Implementations/Localization/Core/ja.json
@@ -1,41 +1,24 @@
{
- "Albums": "アルバム",
"AppDeviceValues": "アプリ: {0}, デバイス: {1}",
- "Application": "アプリケーション",
"Artists": "アーティスト",
"AuthenticationSucceededWithUserName": "{0} 認証に成功しました",
"Books": "ブック",
- "CameraImageUploadedFrom": "新しいカメライメージが {0}からアップロードされました",
- "Channels": "チャンネル",
"ChapterNameValue": "チャプター {0}",
"Collections": "コレクション",
- "DeviceOfflineWithName": "{0} が切断しました",
- "DeviceOnlineWithName": "{0} が接続しました",
"FailedLoginAttemptWithUserName": "{0} からのログインに失敗しました",
"Favorites": "お気に入り",
"Folders": "フォルダー",
"Genres": "ジャンル",
- "HeaderAlbumArtists": "アルバムアーティスト",
"HeaderContinueWatching": "再生を続ける",
- "HeaderFavoriteAlbums": "お気に入りのアルバム",
- "HeaderFavoriteArtists": "お気に入りのアーティスト",
"HeaderFavoriteEpisodes": "お気に入りのエピソード",
"HeaderFavoriteShows": "お気に入りの番組",
- "HeaderFavoriteSongs": "お気に入りの曲",
"HeaderLiveTV": "ライブTV",
"HeaderNextUp": "次",
- "HeaderRecordingGroups": "レコーディンググループ",
"HomeVideos": "ホームビデオ",
"Inherit": "継承",
- "ItemAddedWithName": "{0} をライブラリーに追加しました",
- "ItemRemovedWithName": "{0} をライブラリーから削除しました",
"LabelIpAddressValue": "IPアドレス: {0}",
"LabelRunningTimeValue": "時間: {0}",
"Latest": "最新",
- "MessageApplicationUpdated": "Jellyfin Server を更新しました",
- "MessageApplicationUpdatedTo": "Jellyfin Server を {0}に更新しました",
- "MessageNamedServerConfigurationUpdatedWithValue": "サーバー設定項目の {0} を更新しました",
- "MessageServerConfigurationUpdated": "サーバー設定を更新しました",
"MixedContent": "ミックスコンテンツ",
"Movies": "映画",
"Music": "音楽",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "ビデオの再生を開始",
"NotificationOptionVideoPlaybackStopped": "ビデオの再生を停止",
"Photos": "フォト",
- "Playlists": "プレイリスト",
- "Plugin": "プラグイン",
"PluginInstalledWithName": "{0} をインストールしました",
"PluginUninstalledWithName": "{0} をアンインストールしました",
"PluginUpdatedWithName": "{0} を更新しました",
- "ProviderValue": "プロバイダ: {0}",
"ScheduledTaskFailedWithName": "{0} が失敗しました",
- "ScheduledTaskStartedWithName": "{0} を開始",
- "ServerNameNeedsToBeRestarted": "{0} を再起動してください",
"Shows": "番組",
- "Songs": "曲",
"StartupEmbyServerIsLoading": "Jellyfin Server は現在読み込み中です。しばらくしてからもう一度お試しください。",
"SubtitleDownloadFailureFromForItem": "{0} から {1}の字幕のダウンロードに失敗しました",
- "Sync": "同期",
- "System": "システム",
"TvShows": "テレビ番組",
- "User": "ユーザー",
"UserCreatedWithName": "ユーザー {0} が作成されました",
"UserDeletedWithName": "User {0} を削除しました",
"UserDownloadingItemWithValues": "{0} が {1} をダウンロードしています",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} は {1} から切断しました",
"UserOnlineFromDevice": "{0} は {1} からオンラインになりました",
"UserPasswordChangedWithName": "ユーザー {0} のパスワードは変更されました",
- "UserPolicyUpdatedWithName": "ユーザーポリシーが{0}に更新されました",
"UserStartedPlayingItemWithValues": "{0} は {2}で{1} を再生しています",
"UserStoppedPlayingItemWithValues": "{0} は{2}で{1} の再生が終わりました",
- "ValueHasBeenAddedToLibrary": "{0} をメディアライブラリーに追加しました",
- "ValueSpecialEpisodeName": "スペシャル - {0}",
"VersionNumber": "バージョン {0}",
"TaskCleanLogsDescription": "{0} 日以上前のログを消去します。",
"TaskCleanLogs": "ログの掃除",
diff --git a/Emby.Server.Implementations/Localization/Core/jbo.json b/Emby.Server.Implementations/Localization/Core/jbo.json
index 1b47bb2f23..50d6d49601 100644
--- a/Emby.Server.Implementations/Localization/Core/jbo.json
+++ b/Emby.Server.Implementations/Localization/Core/jbo.json
@@ -1,7 +1,4 @@
{
- "Albums": "lo albuma",
"Artists": "lo larpra",
- "Books": "lo cukta",
- "HeaderAlbumArtists": "lo albuma larpra",
- "Playlists": "lo zgipor"
+ "Books": "lo cukta"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ka.json b/Emby.Server.Implementations/Localization/Core/ka.json
index 4f291e466b..c0b7a196f7 100644
--- a/Emby.Server.Implementations/Localization/Core/ka.json
+++ b/Emby.Server.Implementations/Localization/Core/ka.json
@@ -1,11 +1,7 @@
{
"Genres": "ჟანრები",
- "HeaderAlbumArtists": "ალბომის შემსრულებლები",
- "HeaderFavoriteAlbums": "რჩეული ალბომები",
"TasksApplicationCategory": "აპლიკაცია",
- "Albums": "ალბომები",
"AppDeviceValues": "აპლიკაცია: {0}, მოწყობილობა: {1}",
- "Application": "აპლიკაცია",
"Artists": "არტისტი",
"AuthenticationSucceededWithUserName": "{0} -ის ავთენტიკაცია წარმატებულია",
"Books": "წიგნები",
@@ -15,28 +11,16 @@
"Movies": "ფილმები",
"Music": "მუსიკა",
"Photos": "ფოტოები",
- "Playlists": "დასაკრავი სიები",
- "Plugin": "მოდული",
"Shows": "სერიალები",
- "Songs": "სიმღერები",
- "Sync": "სინქრონიზაცია",
- "System": "სისტემა",
"Undefined": "განუსაზღვრელი",
- "User": "მომხმარებელი",
"TasksMaintenanceCategory": "რემონტი",
"TasksLibraryCategory": "ბიბლიოთეკა",
"ChapterNameValue": "თავი {0}",
"HeaderContinueWatching": "ყურების გაგრძელება",
- "HeaderFavoriteArtists": "რჩეული შემსრულებლები",
- "DeviceOfflineWithName": "{0} გამოეთიშა",
"External": "გარე",
"HeaderFavoriteEpisodes": "რჩეული ეპიზოდები",
- "HeaderFavoriteSongs": "რჩეული სიმღერები",
- "HeaderRecordingGroups": "ჩამწერი ჯგუფები",
"HearingImpaired": "სმენადაქვეითებული",
"LabelRunningTimeValue": "ხანგრძლივობა: {0}",
- "MessageApplicationUpdatedTo": "Jellyfin-ის სერვერი განახლდა {0}-ზე",
- "MessageNamedServerConfigurationUpdatedWithValue": "სერვერის კონფიგურაციის სექცია {0} განახლდა",
"MixedContent": "შერეული შემცველობა",
"MusicVideos": "მუსიკალური ვიდეოები",
"NotificationOptionInstallationFailed": "დაყენების შეცდომა",
@@ -45,12 +29,9 @@
"NotificationOptionCameraImageUploaded": "კამერის გამოსახულება ატვირთულია",
"NotificationOptionVideoPlaybackStopped": "ვიდეოს დაკვრა გაჩერებულია",
"PluginUninstalledWithName": "{0} წაიშალა",
- "ScheduledTaskStartedWithName": "{0} დაიწყო",
"VersionNumber": "ვერსია {0}",
"TasksChannelsCategory": "ინტერნეტ-არხები",
- "ValueSpecialEpisodeName": "დამატებითი - {0}",
"TaskRefreshChannelsDescription": "ინტერნეტ-არხის ინფორმაციის განახლება.",
- "Channels": "არხები",
"Collections": "კოლექციები",
"Default": "ნაგულისხმები",
"Favorites": "რჩეულები",
@@ -64,7 +45,6 @@
"NotificationOptionPluginError": "მოდულის შეცდომა",
"NotificationOptionPluginInstalled": "მოდული დაყენებულია",
"NotificationOptionPluginUninstalled": "მოდული წაიშალა",
- "ProviderValue": "მომწოდებელი: {0}",
"ScheduledTaskFailedWithName": "{0} ვერ შესრულდა",
"TvShows": "სატელევიზიო სერიალები",
"TaskRefreshPeople": "ხალხის განახლება",
@@ -72,7 +52,6 @@
"TaskRefreshChannels": "არხების განახლება",
"TaskOptimizeDatabase": "მონაცემთა ბაზის ოპტიმიზაცია",
"TaskKeyframeExtractor": "საკვანძო კადრის გამომღები",
- "DeviceOnlineWithName": "{0} დაკავშირდა",
"LabelIpAddressValue": "IP მისამართი: {0}",
"NameInstallFailed": "{0}-ის დაყენების შეცდომა",
"NotificationOptionApplicationUpdateAvailable": "ხელმისაწვდომია აპლიკაციის განახლება",
@@ -94,27 +73,19 @@
"TaskDownloadMissingSubtitles": "მიუწვდომელი სუბტიტრების გადმოწერა",
"UserDownloadingItemWithValues": "{0} -ი {1}-ს იწერს",
"FailedLoginAttemptWithUserName": "შესვლის წარუმატებელი მცდელობა {0}-დან",
- "MessageApplicationUpdated": "Jellyfin-ის სერვერი განახლდა",
- "MessageServerConfigurationUpdated": "სერვერის კონფიგურაცია განახლდა",
- "ServerNameNeedsToBeRestarted": "საჭიროა {0}-ის გადატვირთვა",
"UserCreatedWithName": "მომხმარებელი {0} შეიქმნა",
"UserDeletedWithName": "მომხმარებელი {0} წაშლილია",
"UserOnlineFromDevice": "{0}-ი დაკავშირდა {1}-დან",
"UserOfflineFromDevice": "{0}-ი {1}-დან გაეთიშა",
- "ItemAddedWithName": "{0} ჩამატებულია ბიბლიოთეკაში",
- "ItemRemovedWithName": "{0} წაშლილია ბიბლიოთეკიდან",
"UserLockedOutWithName": "მომხმარებელი {0} დაბლოკილია",
"UserStartedPlayingItemWithValues": "{0} უყურებს {1}-ს {2}-ზე",
"UserPasswordChangedWithName": "მომხმარებელი {0}-სთვის პაროლი შეიცვალა",
- "UserPolicyUpdatedWithName": "{0}-ის მომხმარებლის პოლიტიკა განახლდა",
"UserStoppedPlayingItemWithValues": "{0}-მა დაასრულა {1}-ის ყურება {2}-ზე",
"TaskRefreshChapterImagesDescription": "თავების მქონე ვიდეოებისთვის მინიატურების შექმნა.",
"TaskKeyframeExtractorDescription": "უფრო ზუსტი HLS დასაკრავი სიებისითვის ვიდეოდან საკვანძო გადრების ამოღება. შეიძლება საკმაო დრო დასჭირდეს.",
"NewVersionIsAvailable": "გადმოსაწერად ხელმისაწვდომია Jellyfin -ის ახალი ვერსია.",
- "CameraImageUploadedFrom": "ახალი კამერის გამოსახულება ატვირთულია {0}-დან",
"StartupEmbyServerIsLoading": "Jellyfin სერვერი იტვირთება. მოგვიანებით სცადეთ.",
"SubtitleDownloadFailureFromForItem": "{0}-დან {1}-სთვის სუბტიტრების გადმოწერა ვერ შესრულდა",
- "ValueHasBeenAddedToLibrary": "{0} დაემატა თქვენს მედიის ბიბლიოთეკას",
"TaskCleanActivityLogDescription": "შლის მითითებულ ასაკზე ძველ ჟურნალის ჩანაწერებს.",
"TaskCleanCacheDescription": "შლის სისტემისთვის არასაჭირო ქეშის ფაილებს.",
"TaskRefreshLibraryDescription": "ეძებს ახალ ფაილებს თქვენს მედიის ბიბლიოთეკაში და ანახლებს მეტამონაცემებს.",
diff --git a/Emby.Server.Implementations/Localization/Core/kab.json b/Emby.Server.Implementations/Localization/Core/kab.json
index 9551f0e5c1..0d0932b585 100644
--- a/Emby.Server.Implementations/Localization/Core/kab.json
+++ b/Emby.Server.Implementations/Localization/Core/kab.json
@@ -1,14 +1,10 @@
{
"Music": "Aẓawan",
- "Sync": "Amtawi",
"Photos": "Tiwlafin",
"Movies": "Isura",
"External": "Azɣaray",
- "User": "Aseqdac",
"Folders": "Ikaramen",
"Favorites": "Ismenyifen",
"Default": "Lexṣas",
- "Collections": "Tigrummiwin",
- "Channels": "Ibuda",
- "Albums": "Iseɣraz"
+ "Collections": "Tigrummiwin"
}
diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json
index fc5fcf3c4d..ddcf60944d 100644
--- a/Emby.Server.Implementations/Localization/Core/kk.json
+++ b/Emby.Server.Implementations/Localization/Core/kk.json
@@ -1,41 +1,24 @@
{
- "Albums": "Älbomdar",
"AppDeviceValues": "Qoldanba: {0}, Qūrylğy: {1}",
- "Application": "Qoldanba",
"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": "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 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": "Ü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",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Beine oinatuy bastaldy",
"NotificationOptionVideoPlaybackStopped": "Beine oinatuy toqtatyldy",
"Photos": "Fotosuretter",
- "Playlists": "Oinatu tızımderı",
- "Plugin": "Plagin",
"PluginInstalledWithName": "{0} ornatyldy",
"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.",
"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",
@@ -85,11 +59,8 @@
"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",
diff --git a/Emby.Server.Implementations/Localization/Core/km.json b/Emby.Server.Implementations/Localization/Core/km.json
index c40b96cf24..b4057eb8eb 100644
--- a/Emby.Server.Implementations/Localization/Core/km.json
+++ b/Emby.Server.Implementations/Localization/Core/km.json
@@ -1,88 +1,62 @@
{
- "Albums": "អាលប៊ុម",
- "MessageApplicationUpdatedTo": "ម៉ាស៊ីនមេនៃJellyfinត្រូវបានអាប់ដេតទៅកាន់ {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "ការកំណត់ម៉ាស៊ីនមេ ផ្នែក {0} ត្រូវបានអាប់ដេត",
- "MessageServerConfigurationUpdated": "ការកំណត់ម៉ាស៊ីនមេត្រូវបានអាប់ដេត",
"AppDeviceValues": "កម្មវិធី: {0}, ឧបករណ៍: {1}",
"MixedContent": "មាតិកាចម្រុះ",
"UserLockedOutWithName": "អ្នកប្រើប្រាស់ {0} ត្រូវ​បាន​ផ្អាក",
- "Application": "កម្មវិធី",
"Artists": "សិល្បករ",
"AuthenticationSucceededWithUserName": "{0} បានផ្ទៀងផ្ទាត់ដោយជោគជ័យ",
"Books": "សៀវភៅ",
"NameSeasonNumber": "រដូវកាលទី {0}",
"NotificationOptionPluginInstalled": "Plugin បានដំឡើងរួច",
- "CameraImageUploadedFrom": "រូបភាពកាមេរ៉ាថ្មីត្រូវបានបង្ហោះពី {0}",
- "Channels": "ប៉ុស្ត៍",
"ChapterNameValue": "ជំពូក {0}",
"Collections": "បណ្តុំ",
"External": "ខាងក្រៅ",
"Default": "លំនាំដើម",
"NotificationOptionInstallationFailed": "ការដំឡើងមិនបានសម្រេច",
- "DeviceOfflineWithName": "{0} បានផ្តាច់",
"Folders": "ថតឯកសារ",
- "DeviceOnlineWithName": "{0} បានភ្ចាប់",
"HearingImpaired": "ខ្សោយការស្តាប់",
"HomeVideos": "វីឌីអូថតខ្លួនឯង",
"Favorites": "ចំណូលចិត្ត",
"HeaderFavoriteEpisodes": "ភាគដែលចូលចិត្ត",
"Forced": "បង្ខំ",
"Genres": "ប្រភេទ",
- "HeaderFavoriteArtists": "សិល្បករដែលចូលចិត្ត",
"NotificationOptionApplicationUpdateAvailable": "កម្មវិធី យើងអាចអាប់ដេតបាន",
"NotificationOptionApplicationUpdateInstalled": "កម្មវិធី ដែលបានដំឡើងរួច",
"NotificationOptionAudioPlaybackStopped": "ការ​ចាក់សម្លេងបានផ្អាក",
"HeaderContinueWatching": "បន្តមើល",
- "HeaderFavoriteAlbums": "អាល់ប៊ុមដែលចូលចិត្ត",
"HeaderFavoriteShows": "រឿងភាគដែលចូលចិត្ត",
"NewVersionIsAvailable": "មានជំនាន់ថ្មី ម៉ាស៊ីនមេJellyfin អាចទាញយកបាន.",
- "HeaderAlbumArtists": "សិល្បករអាល់ប៊ុម",
"NotificationOptionCameraImageUploaded": "រូបភាពពីកាំមេរ៉ាបានអាប់ឡូតរួច",
- "HeaderFavoriteSongs": "ចម្រៀងដែលចូលចិត្ត",
"HeaderNextUp": "បន្ទាប់",
"HeaderLiveTV": "ទូរទស្សន៍ផ្សាយផ្ទាល់",
"Movies": "រឿង",
- "HeaderRecordingGroups": "ក្រុមនៃការថត",
"Music": "តន្ត្រី",
"Inherit": "មរតក",
"MusicVideos": "វីដេអូតន្ត្រី",
"NameInstallFailed": "{0} ការដំឡើងបានបរាជ័យ",
"NotificationOptionNewLibraryContent": "មាតិកាថ្មីៗត្រូវបានបន្ថែម",
- "ItemAddedWithName": "{0} ត្រូវបានបន្ថែមទៅបណ្ណាល័យ",
"NameSeasonUnknown": "រដូវកាលមិនច្បាស់លាស់",
- "ItemRemovedWithName": "{0} ត្រូវបានដកចេញពីបណ្ណាល័យ",
"LabelIpAddressValue": "លេខ IP: {0}",
"LabelRunningTimeValue": "ពេលវេលាកំពុងដំណើរការ: {0}",
"Latest": "ចុងក្រោយ",
"NotificationOptionAudioPlayback": "ការ​ចាក់​សំឡេង​បាន​ចាប់ផ្ដើម",
"NotificationOptionPluginError": "Plugin មិនដំណើរការ",
"NotificationOptionPluginUninstalled": "Plugin បានលុបចេញរួច",
- "MessageApplicationUpdated": "ម៉ាស៊ីនមេនៃJellyfinត្រូវបានអាប់ដេត",
"NotificationOptionPluginUpdateInstalled": "Plugin អាប់ដេតបានដំឡើងរួច",
"NotificationOptionUserLockedOut": "អ្នកប្រើប្រាស់ត្រូវបានជាប់គាំង",
"NotificationOptionServerRestartRequired": "តម្រូវឱ្យចាប់ផ្ដើមម៉ាស៊ីនមេឡើងវិញ",
"Photos": "រូបថត",
- "Playlists": "បញ្ជីចាក់",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} ត្រូវបានដំឡើង",
"NotificationOptionTaskFailed": "កិច្ចការដែលបានគ្រោងទុកបានបរាជ័យ",
"PluginUpdatedWithName": "{0} ត្រូវបានអាប់ដេត",
"NotificationOptionVideoPlayback": "ការចាក់វីដេអូបានចាប់ផ្តើម",
- "Songs": "ចម្រៀង",
- "ScheduledTaskStartedWithName": "{0} បានចាប់ផ្តើម",
"NotificationOptionVideoPlaybackStopped": "ការ​ចាក់​វីដេអូ​បាន​បញ្ឈប់",
"PluginUninstalledWithName": "{0} ត្រូវបានលុបចេញ",
"Shows": "រឿងភាគ",
- "ProviderValue": "អ្នកផ្តល់សេវា: {0}",
"SubtitleDownloadFailureFromForItem": "សាប់ថាយថលបានបរាជ័យក្នុងការទាញយកពី {0} នៃ {1}",
- "Sync": "ធ្វើអោយដំណាលគ្នា",
- "System": "ប្រព័ន្ធ",
"TvShows": "កម្មវិធីទូរទស្សន៍",
"ScheduledTaskFailedWithName": "{0} បានបរាជ័យ",
"Undefined": "មិនបានកំណត់",
- "User": "អ្នកប្រើប្រាស់",
"UserCreatedWithName": "អ្នកប្រើប្រាស់ {0} ត្រូវបានបង្កើតឡើង",
- "ServerNameNeedsToBeRestarted": "{0} ចាំបាច់ត្រូវចាប់ផ្តើមឡើងវិញ",
"StartupEmbyServerIsLoading": "ម៉ាស៊ីនមេJellyfin កំពុងដំណើរការ. សូមព្យាយាមម្តងទៀតក្នុងពេលឆាប់ៗនេះ.",
"UserDeletedWithName": "អ្នកប្រើប្រាស់ {0} ត្រូវបានលុបចេញ",
"UserOnlineFromDevice": "{0} បានឃើញអនឡានពី {1}",
@@ -98,10 +72,7 @@
"UserPasswordChangedWithName": "ពាក្យសម្ងាត់ត្រូវបានផ្លាស់ប្តូរសម្រាប់អ្នកប្រើប្រាស់ {0}",
"TaskCleanCache": "សម្អាតបញ្ជីឃ្លាំងសម្ងាត់",
"TaskRefreshChapterImages": "ដកស្រង់រូបភាពតាមជំពូក",
- "UserPolicyUpdatedWithName": "គោលការណ៍អ្នកប្រើប្រាស់ត្រូវបានធ្វើបច្ចុប្បន្នភាពសម្រាប់ {0}",
"UserStoppedPlayingItemWithValues": "{0} បានបញ្ចប់ការចាក់ {1} នៅលើ {2}",
- "ValueHasBeenAddedToLibrary": "{0} ត្រូវបានបញ្ចូលទៅក្នុងបណ្ណាល័យរឿងរបស់អ្នក",
- "ValueSpecialEpisodeName": "ពិសេស - {0}",
"TasksChannelsCategory": "ប៉ុស្តតាមអ៊ីនធឺណិត",
"TaskAudioNormalization": "ធ្វើឱ្យមានតន្ត្រីមានសម្លេងស្មើគ្នា",
"TaskCleanActivityLogDescription": "លុបកំណត់ហេតុសកម្មភាពចាស់ជាងអាយុដែលបានកំណត់រចនាសម្ព័ន្ធ.",
diff --git a/Emby.Server.Implementations/Localization/Core/kn.json b/Emby.Server.Implementations/Localization/Core/kn.json
index 0850600588..f053619a7a 100644
--- a/Emby.Server.Implementations/Localization/Core/kn.json
+++ b/Emby.Server.Implementations/Localization/Core/kn.json
@@ -4,8 +4,6 @@
"TaskOptimizeDatabaseDescription": "ಡೇಟಾಬೇಸ್ ಅನ್ನು ಕಾಂಪ್ಯಾಕ್ಟ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಮುಕ್ತ ಜಾಗವನ್ನು ಮೊಟಕುಗೊಳಿಸುತ್ತದೆ. ಲೈಬ್ರರಿಯನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿದ ನಂತರ ಈ ಕಾರ್ಯವನ್ನು ನಡೆಸುವುದು ಅಥವಾ ಡೇಟಾಬೇಸ್ ಮಾರ್ಪಾಡುಗಳನ್ನು ಸೂಚಿಸುವ ಇತರ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡುವುದರಿಂದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸಬಹುದು.",
"TaskKeyframeExtractor": "ಕೀಫ್ರೇಮ್ ಎಕ್ಸ್‌ಟ್ರಾಕ್ಟರ್",
"TaskKeyframeExtractorDescription": "ಹೆಚ್ಚು ನಿಖರವಾದ HLS ಪ್ಲೇಪಟ್ಟಿಗಳನ್ನು ರಚಿಸಲು ವೀಡಿಯೊ ಫೈಲ್‌ಗಳಿಂದ ಕೀಫ್ರೇಮ್‌ಗಳನ್ನು ಹೊರತೆಗೆಯುತ್ತದೆ. ಈ ಕಾರ್ಯವು ದೀರ್ಘಕಾಲದವರೆಗೆ ನಡೆಯಬಹುದು.",
- "ValueHasBeenAddedToLibrary": "{0} ಅನ್ನು ನಿಮ್ಮ ಮಾಧ್ಯಮ ಲೈಬ್ರರಿಗೆ ಸೇರಿಸಲಾಗಿದೆ",
- "ValueSpecialEpisodeName": "ವಿಶೇಷ - {0}",
"TasksLibraryCategory": "ಸಮೊಹ",
"TasksApplicationCategory": "ಅಪ್ಲಿಕೇಶನ್",
"TasksChannelsCategory": "ಇಂಟರ್ನೆಟ್ ಚಾನೆಲ್ಗಳು",
@@ -13,8 +11,6 @@
"TaskCleanCacheDescription": "ಸಿಸ್ಟಮ್‌ಗೆ ಇನ್ನು ಮುಂದೆ ಅಗತ್ಯವಿಲ್ಲದ ಸಂಗ್ರಹ ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುತ್ತದೆ.",
"TaskRefreshLibrary": "ಸ್ಕ್ಯಾನ್ ಮೀಡಿಯಾ ಲೈಬ್ರರಿ",
"UserOfflineFromDevice": "{1} ನಿಂದ {0} ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ",
- "Albums": "ಸಂಪುಟ",
- "Application": "ಅಪ್ಲಿಕೇಶನ್",
"AppDeviceValues": "ಅಪ್ಲಿಕೇಶನ್: {0}, ಸಾಧನ: {1}",
"Artists": "ಕಲಾವಿದರು",
"AuthenticationSucceededWithUserName": "{0} ಯಶಸ್ವಿಯಾಗಿ ದೃಢೀಕರಿಸಲಾಗಿದೆ",
@@ -22,8 +18,6 @@
"ChapterNameValue": "ಅಧ್ಯಾಯ {0}",
"Collections": "ಸಂಗ್ರಹಣೆಗಳು",
"Default": "ಪೂರ್ವನಿಯೋಜಿತ",
- "DeviceOfflineWithName": "{0} ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ",
- "DeviceOnlineWithName": "{0} ಸಂಪರ್ಕಗೊಂಡಿದೆ",
"External": "ಹೊರಗಿನ",
"FailedLoginAttemptWithUserName": "ವಿಫಲ ಲಾಗಿನ್ ಪ್ರಯತ್ನ ಸಂಖ್ಯೆ {0}",
"Favorites": "ಮೆಚ್ಚಿನವುಗಳು",
@@ -31,22 +25,11 @@
"Forced": "ಬಲವಂತವಾಗಿ",
"Genres": "ಪ್ರಕಾರಗಳು",
"HeaderContinueWatching": "ನೋಡುವುದನ್ನು ಮುಂದುವರಿಸಿ",
- "HeaderFavoriteAlbums": "ಮೆಚ್ಚಿನ ಸಂಪುಟಗಳು",
- "HeaderFavoriteArtists": "ಮೆಚ್ಚಿನ ಕಲಾವಿದರು",
"HeaderFavoriteShows": "ಮೆಚ್ಚಿನ ಪ್ರದರ್ಶನಗಳು",
- "HeaderFavoriteSongs": "ಮೆಚ್ಚಿನ ಹಾಡುಗಳು",
"HeaderLiveTV": "ನೇರ ದೂರದರ್ಶನ",
"HeaderNextUp": "ಮುಂದೆ",
- "HeaderRecordingGroups": "ರೆಕಾರ್ಡಿಂಗ್ ಗುಂಪುಗಳು",
- "MessageApplicationUpdated": "ಜೆಲ್ಲಿಫಿನ್ ಸರ್ವರ್ ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ",
- "CameraImageUploadedFrom": "ಹೊಸ ಕ್ಯಾಮರಾ ಚಿತ್ರವನ್ನು {0} ನಿಂದ ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗಿದೆ",
- "Channels": "ಮೂಲಗಳು",
- "HeaderAlbumArtists": "ಸಂಪುಟ ಕಲಾವಿದರು",
"HeaderFavoriteEpisodes": "ಮೆಚ್ಚಿನ ಸಂಚಿಕೆಗಳು",
"HearingImpaired": "ಮೂಗ",
- "ItemAddedWithName": "{0} ಅನ್ನು ಸಂಕಲನಕ್ಕೆ ಸೇರಿಸಲಾಗಿದೆ",
- "MessageApplicationUpdatedTo": "ಜೆಲ್ಲಿಫಿನ್ ಸರ್ವರ್ ಅನ್ನು {0} ಗೆ ನವೀಕರಿಸಲಾಗಿದೆ",
- "MessageNamedServerConfigurationUpdatedWithValue": "ಸರ್ವರ್ ಕಾನ್ಫಿಗರೇಶನ್ ವಿಭಾಗ {0} ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ",
"NewVersionIsAvailable": "ಜೆಲ್ಲಿಫಿನ್ ಸರ್ವರ್‌ನ ಹೊಸ ಆವೃತ್ತಿಯು ಡೌನ್‌ಲೋಡ್‌ಗೆ ಲಭ್ಯವಿದೆ.",
"NotificationOptionAudioPlayback": "ಆಡಿಯೋ ಪ್ಲೇಬ್ಯಾಕ್ ಪ್ರಾರಂಭವಾಗಿದೆ",
"NotificationOptionCameraImageUploaded": "ಕ್ಯಾಮರಾ ಚಿತ್ರವನ್ನು ಅಪ್ಲೋಡ್ ಮಾಡಲಾಗಿದೆ",
@@ -55,13 +38,10 @@
"NotificationOptionVideoPlaybackStopped": "ವೀಡಿಯೊ ಪ್ಲೇಬ್ಯಾಕ್ ನಿಲ್ಲಿಸಲಾಗಿದೆ",
"PluginUninstalledWithName": "{0} ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ",
"ScheduledTaskFailedWithName": "{0} ವಿಫಲವಾಗಿದೆ",
- "ScheduledTaskStartedWithName": "{0} ಪ್ರಾರಂಭವಾಯಿತು",
- "ServerNameNeedsToBeRestarted": "{0} ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಬೇಕಾಗಿದೆ",
"UserCreatedWithName": "ಬಳಕೆದಾರ {0} ಅನ್ನು ರಚಿಸಲಾಗಿದೆ",
"UserLockedOutWithName": "ಬಳಕೆದಾರ {0} ಅನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ",
"UserOnlineFromDevice": "{1} ನಿಂದ {0} ಆನ್‌ಲೈನ್‌ನಲ್ಲಿದೆ",
"UserPasswordChangedWithName": "{0} ಬಳಕೆದಾರರಿಗಾಗಿ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ",
- "UserPolicyUpdatedWithName": "ಬಳಕೆದಾರರ ನೀತಿಯನ್ನು {0} ಗೆ ನವೀಕರಿಸಲಾಗಿದೆ",
"UserStartedPlayingItemWithValues": "{2} ರಂದು {0} ಆಡುತ್ತಿದೆ {1}",
"UserStoppedPlayingItemWithValues": "{0} ಅವರು {1} ಅನ್ನು {2} ನಲ್ಲಿ ಆಡುವುದನ್ನು ಮುಗಿಸಿದ್ದಾರೆ",
"VersionNumber": "ಆವೃತ್ತಿ {0}",
@@ -76,23 +56,17 @@
"TaskCleanTranscodeDescription": "ಒಂದು ದಿನಕ್ಕಿಂತ ಹಳೆಯದಾದ ಟ್ರಾನ್ಸ್‌ಕೋಡ್ ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುತ್ತದೆ.",
"TaskDownloadMissingSubtitles": "ಕಾಣೆಯಾದ ಉಪಶೀರ್ಷಿಕೆಗಳನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ",
"Shows": "ಧಾರವಾಹಿಗಳು",
- "Songs": "ಹಾಡುಗಳು",
"StartupEmbyServerIsLoading": "ಜೆಲ್ಲಿಫಿನ್ ಸರ್ವರ್ ಲೋಡ್ ಆಗುತ್ತಿದೆ. ದಯವಿಟ್ಟು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.",
"UserDeletedWithName": "ಬಳಕೆದಾರ {0} ಅನ್ನು ಅಳಿಸಲಾಗಿದೆ",
"UserDownloadingItemWithValues": "{0} ಡೌನ್‌ಲೋಡ್ ಆಗುತ್ತಿದೆ {1}",
"SubtitleDownloadFailureFromForItem": "ಉಪಶೀರ್ಷಿಕೆಗಳು {0} ನಿಂದ {1} ಗಾಗಿ ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ವಿಫಲವಾಗಿವೆ",
- "Sync": "ಹೊಂದಿಕೆ",
- "System": "ವ್ಯವಸ್ಥೆ",
"TvShows": "ದೂರದರ್ಶನ ಕಾರ್ಯಕ್ರಮಗಳು",
"Undefined": "ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿಲ್ಲ",
- "User": "ಬಳಕೆದಾರ",
"HomeVideos": "ಮುಖಪುಟ ವೀಡಿಯೊಗಳು",
"Inherit": "ಪಾರಂಪರ್ಯವಾಗಿ",
- "ItemRemovedWithName": "{0} ಅನ್ನು ಸಂಕಲನದಿಂದ ತೆಗೆದುಹಾಕಲಾಗಿದೆ",
"LabelIpAddressValue": "IP ವಿಳಾಸ: {0}",
"LabelRunningTimeValue": "ಅವಧಿ: {0}",
"Latest": "ಹೊಸದಾದ",
- "MessageServerConfigurationUpdated": "ಸರ್ವರ್ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ",
"MixedContent": "ಮಿಶ್ರ ವಿಷಯ",
"Movies": "ಚಲನಚಿತ್ರಗಳು",
"Music": "ಸಂಗೀತ",
@@ -112,11 +86,8 @@
"NotificationOptionTaskFailed": "ನಿಗದಿತ ಕಾರ್ಯ ವೈಫಲ್ಯ",
"NotificationOptionVideoPlayback": "ವೀಡಿಯೊ ಪ್ಲೇಬ್ಯಾಕ್ ಪ್ರಾರಂಭವಾಗಿದೆ",
"Photos": "ಚಿತ್ರಗಳು",
- "Playlists": "ಪ್ಲೇಪಟ್ಟಿಗಳು",
- "Plugin": "ಪ್ಲಗಿನ್",
"PluginInstalledWithName": "{0} ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ",
"PluginUpdatedWithName": "{0} ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ",
- "ProviderValue": "ಒದಗಿಸುವವರು: {0}",
"TaskCleanLogs": "ಕ್ಲೀನ್ ಲಾಗ್ ಡೈರೆಕ್ಟರಿ",
"TaskRefreshPeople": "ಜನರನ್ನು ರಿಫ್ರೆಶ್ ಮಾಡಿ",
"TaskRefreshPeopleDescription": "ನಿಮ್ಮ ಮಾಧ್ಯಮ ಲೈಬ್ರರಿಯಲ್ಲಿ ನಟರು ಮತ್ತು ನಿರ್ದೇಶಕರಿಗಾಗಿ ಮೆಟಾಡೇಟಾವನ್ನು ನವೀಕರಿಸಿ.",
diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json
index 0451dcc9f0..5d64405d19 100644
--- a/Emby.Server.Implementations/Localization/Core/ko.json
+++ b/Emby.Server.Implementations/Localization/Core/ko.json
@@ -1,41 +1,24 @@
{
- "Albums": "앨범",
"AppDeviceValues": "앱: {0}, 장치: {1}",
- "Application": "애플리케이션",
"Artists": "아티스트",
"AuthenticationSucceededWithUserName": "{0} 사용자가 성공적으로 인증됨",
"Books": "도서",
- "CameraImageUploadedFrom": "{0}에서 새로운 카메라 이미지가 업로드됨",
- "Channels": "채널",
"ChapterNameValue": "챕터 {0}",
"Collections": "컬렉션",
- "DeviceOfflineWithName": "{0}의 연결 끊김",
- "DeviceOnlineWithName": "{0}이(가) 연결됨",
"FailedLoginAttemptWithUserName": "{0}에서 로그인 실패",
"Favorites": "즐겨찾기",
"Folders": "폴더",
"Genres": "장르",
- "HeaderAlbumArtists": "앨범 음악가",
"HeaderContinueWatching": "계속 시청하기",
- "HeaderFavoriteAlbums": "즐겨찾는 앨범",
- "HeaderFavoriteArtists": "즐겨찾는 아티스트",
"HeaderFavoriteEpisodes": "즐겨찾는 에피소드",
"HeaderFavoriteShows": "즐겨찾는 쇼",
- "HeaderFavoriteSongs": "즐겨찾는 노래",
"HeaderLiveTV": "실시간 TV",
"HeaderNextUp": "다음으로",
- "HeaderRecordingGroups": "녹화 그룹",
"HomeVideos": "홈 비디오",
"Inherit": "상속",
- "ItemAddedWithName": "{0}가 라이브러리에 추가되었습니다",
- "ItemRemovedWithName": "{0}가 라이브러리에서 제거됨",
"LabelIpAddressValue": "IP 주소: {0}",
"LabelRunningTimeValue": "상영 시간: {0}",
"Latest": "최근",
- "MessageApplicationUpdated": "Jellyfin 서버가 업데이트되었습니다",
- "MessageApplicationUpdatedTo": "Jellyfin 서버가 {0}로 업데이트되었습니다",
- "MessageNamedServerConfigurationUpdatedWithValue": "서버 환경 설정 {0} 섹션이 업데이트되었습니다",
- "MessageServerConfigurationUpdated": "서버 환경 설정이 업데이트되었습니다",
"MixedContent": "혼합 콘텐츠",
"Movies": "영화",
"Music": "음악",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "비디오 재생 시작됨",
"NotificationOptionVideoPlaybackStopped": "비디오 재생 중지됨",
"Photos": "사진",
- "Playlists": "재생목록",
- "Plugin": "플러그인",
"PluginInstalledWithName": "{0} 설치됨",
"PluginUninstalledWithName": "{0} 제거됨",
"PluginUpdatedWithName": "{0} 업데이트됨",
- "ProviderValue": "제공자: {0}",
"ScheduledTaskFailedWithName": "{0} 실패",
- "ScheduledTaskStartedWithName": "{0} 시작",
- "ServerNameNeedsToBeRestarted": "{0}를 재시작해야합니다",
"Shows": "시리즈",
- "Songs": "노래",
"StartupEmbyServerIsLoading": "Jellyfin 서버를 불러오고 있습니다. 잠시 후에 다시 시도하십시오.",
"SubtitleDownloadFailureFromForItem": "{0}에서 {1} 자막 다운로드에 실패했습니다",
- "Sync": "동기화",
- "System": "시스템",
"TvShows": "TV 쇼",
- "User": "사용자",
"UserCreatedWithName": "사용자 {0} 생성됨",
"UserDeletedWithName": "사용자 {0} 삭제됨",
"UserDownloadingItemWithValues": "{0} 사용자가 {1} 다운로드 중",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} 사용자의 {1}에서 연결이 끊김",
"UserOnlineFromDevice": "{0} 사용자가 {1}에서 접속함",
"UserPasswordChangedWithName": "{0} 사용자 비밀번호 변경됨",
- "UserPolicyUpdatedWithName": "{0} 사용자 정책 업데이트됨",
"UserStartedPlayingItemWithValues": "{0} 사용자의 {2}에서 {1} 재생 중",
"UserStoppedPlayingItemWithValues": "{0} 사용자의 {2}에서 {1} 재생을 마침",
- "ValueHasBeenAddedToLibrary": "{0}가 미디어 라이브러리에 추가되었습니다",
- "ValueSpecialEpisodeName": "스페셜 - {0}",
"VersionNumber": "버전 {0}",
"TasksApplicationCategory": "어플리케이션",
"TasksMaintenanceCategory": "유지 보수",
diff --git a/Emby.Server.Implementations/Localization/Core/kw.json b/Emby.Server.Implementations/Localization/Core/kw.json
index 613d531103..fc2e189e7f 100644
--- a/Emby.Server.Implementations/Localization/Core/kw.json
+++ b/Emby.Server.Implementations/Localization/Core/kw.json
@@ -1,21 +1,13 @@
{
"Collections": "Kuntellow",
- "DeviceOfflineWithName": "{0} re anjunyas",
"External": "A-ves",
"Folders": "Plegellow",
- "HeaderFavoriteAlbums": "Albomow Drudh",
- "HeaderFavoriteArtists": "Artydhyon Drudh",
"HeaderFavoriteEpisodes": "Towlennow Drudh",
- "HeaderFavoriteSongs": "Kanow Drudh",
- "HeaderRecordingGroups": "Bagasow Rekordya",
"HearingImpaired": "Klewans Aperys",
"HomeVideos": "Gwydhyow Tre",
"Inherit": "Herya",
"LabelRunningTimeValue": "Prys ow ponya: {0}",
"Latest": "Diwettha",
- "MessageApplicationUpdated": "Servell Jellyfin re beu nowedhys",
- "MessageApplicationUpdatedTo": "Servell Jellyfin re beu nowedhys dhe {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Rann dewisyans servell {0} re beu nowedhys",
"MixedContent": "Dalgh kemmyskys",
"Movies": "Fylmow",
"MusicVideos": "Gwydhyow Ilow",
@@ -25,23 +17,16 @@
"NotificationOptionPluginError": "Defowt ystynnans",
"NotificationOptionPluginUninstalled": "Ystynnans anynstallys",
"NotificationOptionPluginUpdateInstalled": "Nowedheans ystynnans ynstallys",
- "Application": "Gweythres",
"Favorites": "Moyha Kerys",
"Forced": "Konstrynys",
- "Albums": "Albomow",
"Books": "Lyvrow",
- "Channels": "Kanolyow",
"AppDeviceValues": "App: {0}, Devis: {1}",
"Artists": "Artyhdyon",
- "HeaderAlbumArtists": "Albom artydhyon",
"HeaderNextUp": "Nessa",
- "CameraImageUploadedFrom": "Skeusen kamera nowydh re beu ughkargys a-dhyworth {0}",
"ChapterNameValue": "Chaptra {0}",
"FailedLoginAttemptWithUserName": "Assay omgelm fyllys a-dhyworth {0}",
"AuthenticationSucceededWithUserName": "{0} omgelmys yn sewen",
"Default": "Defowt",
- "DeviceOnlineWithName": "{0} yw junys",
- "ItemRemovedWithName": "{0} a veu dileys a-dhyworth an lyverva",
"LabelIpAddressValue": "Trigva PK: {)}",
"Music": "Ilow",
"HeaderContinueWatching": "Pesya Ow Kweles",
@@ -50,8 +35,6 @@
"NotificationOptionCameraImageUploaded": "Skeusen kamera ughkargys",
"HeaderFavoriteShows": "Diskwedhyansow Drudh",
"HeaderLiveTV": "PW Yn Fyw",
- "MessageServerConfigurationUpdated": "Dewisyans servell re beu nowedhys",
- "ItemAddedWithName": "{0} a veu keworrys dhe'n lyverva",
"NameInstallFailed": "{0} ynstallyans fyllys",
"NotificationOptionNewLibraryContent": "Dalgh nowydh keworrys",
"NewVersionIsAvailable": "Yma versyon nowydh a Servell Jellyfin neb yw kavadow rag iskarga.",
@@ -62,8 +45,6 @@
"NotificationOptionServerRestartRequired": "Dastalleth servell yw res",
"StartupEmbyServerIsLoading": "Yma Servell Jellyfin ow kargya. Assay arta yn berr mar pleg.",
"SubtitleDownloadFailureFromForItem": "Istitlow a fyllis iskarga a-dhyworth {0] rag {1}",
- "System": "Kevreyth",
- "User": "Devnydhyer",
"UserDeletedWithName": "Devnydhyer {0} re beu dileys",
"UserLockedOutWithName": "Devnydhyer {0} re beu alhwedhys yn-mes",
"UserStoppedPlayingItemWithValues": "{0} re worfennas gwari {1} war {2}",
@@ -71,21 +52,15 @@
"UserOnlineFromDevice": "{0} yw warlinen a-dhyworth {1}",
"NotificationOptionUserLockedOut": "Devnydhyer yw alhwedhys yn-mes",
"Photos": "Skeusennow",
- "Playlists": "Rolyow-gwari",
- "Plugin": "Ystynnans",
"PluginInstalledWithName": "{0} a veu ynstallys",
- "UserPolicyUpdatedWithName": "Polici devnydhyer re beu nowedhys rag {0}",
"PluginUpdatedWithName": "{0} a veu nowedhys",
"ScheduledTaskFailedWithName": "{0} a fyllis",
- "Songs": "Kanow",
- "Sync": "Kesseni",
"TvShows": "Towlennow PW",
"Undefined": "Anstyrys",
"UserCreatedWithName": "Devnydhyer {0} re beu gwruthys",
"UserDownloadingItemWithValues": "Yma {0} owth iskarga {1}",
"UserPasswordChangedWithName": "Ger-tremena re beu chanjys rag devnydhyer {0}",
"UserStartedPlayingItemWithValues": "Yma {0} ow kwari {1} war {2}",
- "ValueHasBeenAddedToLibrary": "{0} re beu keworrys dhe'th lyverva media",
"VersionNumber": "Versyon {0}",
"TasksLibraryCategory": "Lyverva",
"TaskCleanActivityLog": "Glanhe Kovlyver Gwrians",
@@ -96,10 +71,6 @@
"NotificationOptionVideoPlayback": "Gwareans gwydhyow yw dallethys",
"PluginUninstalledWithName": "{0} a veu anynstallys",
"NotificationOptionTaskFailed": "Defowt oberen towlennys",
- "ProviderValue": "Provier: {0}",
- "ScheduledTaskStartedWithName": "{0} a dhallathas",
- "ServerNameNeedsToBeRestarted": "Yma edhom dhe {0} a vos dastallathys",
- "ValueSpecialEpisodeName": "Arbennik - {0}",
"TasksMaintenanceCategory": "Mentons",
"TasksApplicationCategory": "Gweythres",
"TasksChannelsCategory": "Kanolyow Kesrosweyth",
diff --git a/Emby.Server.Implementations/Localization/Core/lb.json b/Emby.Server.Implementations/Localization/Core/lb.json
index 2afec05dbd..e94709b083 100644
--- a/Emby.Server.Implementations/Localization/Core/lb.json
+++ b/Emby.Server.Implementations/Localization/Core/lb.json
@@ -1,38 +1,24 @@
{
- "Albums": "Alben",
- "Application": "Applikatioun",
"Artists": "Kënschtler",
"Books": "Bicher",
- "Channels": "Kanäl",
"Collections": "Kollektiounen",
"Default": "Standard",
"ChapterNameValue": "Kapitel {0}",
- "DeviceOnlineWithName": "{0} ass Online",
- "DeviceOfflineWithName": "{0} ass Offline",
"External": "Extern",
"Favorites": "Favoritten",
"Folders": "Dossieren",
"Forced": "Forcéiert",
- "HeaderAlbumArtists": "Album Kënschtler",
- "HeaderFavoriteAlbums": "Léifsten Alben",
- "HeaderFavoriteArtists": "Léifsten Kënschtler",
"HeaderFavoriteEpisodes": "Léifsten Episoden",
"HeaderFavoriteShows": "Léifsten Shows",
- "HeaderFavoriteSongs": "Léifsten Lidder",
"Genres": "Generen",
"HeaderContinueWatching": "Weider kucken",
"Inherit": "Iwwerhuelen",
"HeaderNextUp": "Als Nächst",
- "HeaderRecordingGroups": "Opname Gruppen",
"HearingImpaired": "Daaf",
"HomeVideos": "Amateur Videoen",
- "ItemRemovedWithName": "Element ewech geholl: {0}",
"LabelIpAddressValue": "IP Adress: {0}",
"LabelRunningTimeValue": "Lafzäit: {0}",
"Latest": "Dat Aktuellst",
- "MessageApplicationUpdatedTo": "Jellyfin Server aktualiséiert op {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server Konfiguratiounssektioun {0} aktualiséiert",
- "MessageServerConfigurationUpdated": "Server Konfiguratioun aktualiséiert",
"Movies": "Filmer",
"Music": "Musek",
"NameInstallFailed": "{0} Installatioun net gelongen",
@@ -55,19 +41,11 @@
"NotificationOptionUserLockedOut": "Benotzer Gesperrt",
"NotificationOptionVideoPlaybackStopped": "Video ofspillen gestoppt",
"NotificationOptionVideoPlayback": "Video ofspillen gestartet",
- "Plugin": "Plugin",
"PluginUninstalledWithName": "{0} desinstalléiert",
"PluginUpdatedWithName": "{0} aktualiséiert",
- "ProviderValue": "Provider: {0}",
"ScheduledTaskFailedWithName": "Aufgab: {0} net gelongen",
- "Playlists": "Playlëschten",
"Shows": "Shows",
- "Songs": "Lidder",
- "ServerNameNeedsToBeRestarted": "{0} muss nei gestart ginn",
"StartupEmbyServerIsLoading": "Jellyfin Server luedt. Probéier méi spéit nach eng Kéier.",
- "Sync": "Synchroniséieren",
- "System": "System",
- "User": "Benotzer",
"TvShows": "TV Shows",
"Undefined": "Net definéiert",
"UserCreatedWithName": "Benotzer {0} erstellt",
@@ -76,13 +54,10 @@
"UserLockedOutWithName": "Benotzer {0} gesperrt",
"UserOnlineFromDevice": "{0} Benotzer Online um Gerät {1}",
"UserPasswordChangedWithName": "Benotzer Passwuert geännert fir {0}",
- "UserPolicyUpdatedWithName": "Benotzer Politik aktualiséiert fir: {0}",
"UserStartedPlayingItemWithValues": "{0} spillt {1} op {2} oof",
- "ValueHasBeenAddedToLibrary": "{0} der Bibliothéik bäigefüügt",
"VersionNumber": "Versioun {0}",
"TasksMaintenanceCategory": "Ënnerhalt",
"TasksLibraryCategory": "Bibliothéik",
- "ValueSpecialEpisodeName": "Spezial-Episodenumm",
"TasksChannelsCategory": "Internet Kanäl",
"TaskCleanActivityLog": "Aktivitéits Log botzen",
"TaskCleanActivityLogDescription": "Läscht Aktivitéitslogs méi al wéi konfiguréiert.",
@@ -106,18 +81,14 @@
"TaskKeyframeExtractor": "Schlësselbild Extrakter",
"TaskExtractMediaSegments": "Mediesegment-Scan",
"NewVersionIsAvailable": "Nei Versioun fir Jellyfin Server ass verfügbar.",
- "CameraImageUploadedFrom": "En neit Kamera Bild gouf vu {0} eropgelueden",
"PluginInstalledWithName": "{0} installéiert",
"TaskMoveTrickplayImagesDescription": "Verschëfft existent Trickplay-Dateien no de Bibliothéik-Astellungen.",
"AppDeviceValues": "App: {0}, Geräter: {1}",
"FailedLoginAttemptWithUserName": "Net Gelongen Umeldung {0}",
"HeaderLiveTV": "LiveTV",
- "ItemAddedWithName": "Element derbäi gesat: {0}",
"NotificationOptionServerRestartRequired": "Server Restart Erfuerderlech",
- "ScheduledTaskStartedWithName": "Aufgab: {0} gestart",
"AuthenticationSucceededWithUserName": "{0} Authentifikatioun gelongen",
"MixedContent": "Gemëschten Inhalt",
- "MessageApplicationUpdated": "Jellyfin Server Aktualiséiert",
"SubtitleDownloadFailureFromForItem": "Ënnertitel Download Feeler vun {0} fir {1}",
"TaskCleanLogsDescription": "Läscht Log-Dateien, déi méi al wéi {0} Deeg sinn.",
"TaskUpdatePlugins": "Plugins aktualiséieren",
diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json
index daff719ea7..ed26004a43 100644
--- a/Emby.Server.Implementations/Localization/Core/lt-LT.json
+++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumai",
"AppDeviceValues": "Programa: {0}, Įrenginys: {1}",
- "Application": "Programėlė",
"Artists": "Atlikėjai",
"AuthenticationSucceededWithUserName": "{0} sėkmingai autentifikuota",
"Books": "Knygos",
- "CameraImageUploadedFrom": "Nauja nuotrauka įkelta iš kameros {0}",
- "Channels": "Kanalai",
"ChapterNameValue": "Scena{0}",
"Collections": "Rinkiniai",
- "DeviceOfflineWithName": "{0} buvo atjungtas",
- "DeviceOnlineWithName": "{0} prisijungęs",
"FailedLoginAttemptWithUserName": "Nesėkmingas {0} bandymas prisijungti",
"Favorites": "Mėgstami",
"Folders": "Katalogai",
"Genres": "Žanrai",
- "HeaderAlbumArtists": "Albumo atlikėjai",
"HeaderContinueWatching": "Žiūrėti toliau",
- "HeaderFavoriteAlbums": "Mėgstami albumai",
- "HeaderFavoriteArtists": "Mėgstami atlikėjai",
"HeaderFavoriteEpisodes": "Mėgstamiausios serijos",
"HeaderFavoriteShows": "Mėgstamiausios TV Laidos",
- "HeaderFavoriteSongs": "Mėgstamos Dainos",
"HeaderLiveTV": "Tiesioginė TV",
"HeaderNextUp": "Toliau",
- "HeaderRecordingGroups": "Įrašų grupės",
"HomeVideos": "Namų vaizdo įrašai",
"Inherit": "Paveldėti",
- "ItemAddedWithName": "{0} - buvo įkeltas į biblioteką",
- "ItemRemovedWithName": "{0} - buvo pašalinta iš bibliotekos",
"LabelIpAddressValue": "IP adresas: {0}",
"LabelRunningTimeValue": "Trukmė: {0}",
"Latest": "Naujausi",
- "MessageApplicationUpdated": "\"Jellyfin Server\" atnaujintas",
- "MessageApplicationUpdatedTo": "\"Jellyfin Server\" buvo atnaujinta iki {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serverio nustatymai (skyrius {0}) buvo atnaujinti",
- "MessageServerConfigurationUpdated": "Serverio nustatymai buvo atnaujinti",
"MixedContent": "Mišrus turinys",
"Movies": "Filmai",
"Music": "Muzika",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Vaizdo įrašo atkūrimas pradėtas",
"NotificationOptionVideoPlaybackStopped": "Vaizdo įrašo atkūrimas sustabdytas",
"Photos": "Nuotraukos",
- "Playlists": "Grojaraščiai",
- "Plugin": "Įskiepis",
"PluginInstalledWithName": "{0} buvo įdiegtas",
"PluginUninstalledWithName": "{0} buvo pašalintas",
"PluginUpdatedWithName": "{0} buvo atnaujintas",
- "ProviderValue": "Paslaugos tiekėjas: {0}",
"ScheduledTaskFailedWithName": "{0} nepavyko",
- "ScheduledTaskStartedWithName": "{0} paleista",
- "ServerNameNeedsToBeRestarted": "{0} reikia iš naujo paleisti",
"Shows": "Laidos",
- "Songs": "Kūriniai",
"StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.",
"SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}",
- "Sync": "Sinchronizuoti",
- "System": "Sistema",
"TvShows": "TV laidos",
- "User": "Naudotojas",
"UserCreatedWithName": "Buvo sukurtas {0} naudotojas",
"UserDeletedWithName": "Naudotojas {0} ištrintas",
"UserDownloadingItemWithValues": "{0} siunčiasi {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} buvo atjungtas nuo {1}",
"UserOnlineFromDevice": "{0} prisijungęs iš {1}",
"UserPasswordChangedWithName": "Slaptažodis pakeistas naudotojui {0}",
- "UserPolicyUpdatedWithName": "Naudotojo {0} teisės buvo pakeistos",
"UserStartedPlayingItemWithValues": "{0} leidžia {1} į {2}",
"UserStoppedPlayingItemWithValues": "{0} baigė leisti {1} į {2}",
- "ValueHasBeenAddedToLibrary": "{0} pridėtas į mediateką",
- "ValueSpecialEpisodeName": "Ypatingų - {0}",
"VersionNumber": "Versija {0}",
"TaskUpdatePluginsDescription": "Atsisiunčia ir įdiegia įskiepių, kurie sukonfigūruoti atnaujinti automatiškai, naujinius.",
"TaskUpdatePlugins": "Atnaujinti įskieius",
diff --git a/Emby.Server.Implementations/Localization/Core/lv.json b/Emby.Server.Implementations/Localization/Core/lv.json
index 4bf6ed4752..4a1b248e76 100644
--- a/Emby.Server.Implementations/Localization/Core/lv.json
+++ b/Emby.Server.Implementations/Localization/Core/lv.json
@@ -1,15 +1,10 @@
{
- "ServerNameNeedsToBeRestarted": "{0} ir vajadzīgs restarts",
"NotificationOptionTaskFailed": "Plānota uzdevuma kļūme",
- "HeaderRecordingGroups": "Ierakstu grupas",
- "UserPolicyUpdatedWithName": "Lietotāju politika atjaunota priekš {0}",
"SubtitleDownloadFailureFromForItem": "Subtitru lejupielāde no {0} priekš {1} neizdevās",
"NotificationOptionVideoPlaybackStopped": "Video atskaņošana apturēta",
"NotificationOptionVideoPlayback": "Video atskaņošana sākta",
"NotificationOptionInstallationFailed": "Instalācija neizdevās",
"AuthenticationSucceededWithUserName": "{0} veiksmīgi autentificējies",
- "ValueSpecialEpisodeName": "Speciālais - {0}",
- "ScheduledTaskStartedWithName": "{0} iesākts",
"ScheduledTaskFailedWithName": "{0} neizdevās",
"Photos": "Attēli",
"NotificationOptionUserLockedOut": "Lietotājs bloķēts",
@@ -17,7 +12,6 @@
"Inherit": "Pārmantot",
"AppDeviceValues": "Lietotne: {0}, Ierīce: {1}",
"VersionNumber": "Versija {0}",
- "ValueHasBeenAddedToLibrary": "{0} tika pievienots jūsu multvides bibliotēkai",
"UserStoppedPlayingItemWithValues": "{0} ir beidzis atskaņot {1} uz {2}",
"UserStartedPlayingItemWithValues": "{0} atskaņo {1} uz {2}",
"UserPasswordChangedWithName": "Lietotāja {0} parole tika nomainīta",
@@ -27,23 +21,16 @@
"UserDownloadingItemWithValues": "{0} lejupielādē {1}",
"UserDeletedWithName": "Lietotājs {0} ir izdzēsts",
"UserCreatedWithName": "Lietotājs {0} ir ticis izveidots",
- "User": "Lietotājs",
"TvShows": "TV raidījumi",
- "Sync": "Sinhronizācija",
- "System": "Sistēma",
"StartupEmbyServerIsLoading": "Jellyfin Serveris lādējas. Lūdzu mēģiniet vēlreiz pēc brīža.",
- "Songs": "Dziesmas",
"Shows": "Šovi",
"PluginUpdatedWithName": "{0} tika atjaunots",
"PluginUninstalledWithName": "{0} tika noņemts",
"PluginInstalledWithName": "{0} tika uzstādīts",
- "Plugin": "Paplašinājums",
- "Playlists": "Atskaņošanas saraksti",
"MixedContent": "Jaukts saturs",
"HomeVideos": "Mājas video",
"HeaderNextUp": "Nākamais",
"ChapterNameValue": "{0}. nodaļa",
- "Application": "Lietotne",
"NotificationOptionServerRestartRequired": "Nepieciešams servera restarts",
"NotificationOptionPluginUpdateInstalled": "Paplašinājuma atjauninājums uzstādīts",
"NotificationOptionPluginUninstalled": "Paplašinājums noņemts",
@@ -62,35 +49,19 @@
"MusicVideos": "Mūzikas video",
"Music": "Mūzika",
"Movies": "Filmas",
- "MessageServerConfigurationUpdated": "Servera konfigurācija ir tikusi atjaunota",
- "MessageNamedServerConfigurationUpdatedWithValue": "Servera konfigurācijas sadaļa {0} tika atjaunota",
- "MessageApplicationUpdatedTo": "Jellyfin Server ir ticis atjaunots uz {0}",
- "MessageApplicationUpdated": "Jellyfin Server ir ticis atjaunots",
"Latest": "Jaunākais",
"LabelIpAddressValue": "IP adrese: {0}",
- "ItemRemovedWithName": "{0} tika noņemts no bibliotēkas",
- "ItemAddedWithName": "{0} tika pievienots bibliotēkai",
"HeaderLiveTV": "Tiešraides TV",
"HeaderContinueWatching": "Turpini skatīties",
- "HeaderAlbumArtists": "Albumu izpildītāji",
"Genres": "Žanri",
"Folders": "Mapes",
"Favorites": "Izlase",
"FailedLoginAttemptWithUserName": "Neizdevies ieiešanas mēģinājums no {0}",
- "DeviceOnlineWithName": "Savienojums ar {0} ir izveidots",
- "DeviceOfflineWithName": "Savienojums ar {0} ir pārtraukts",
"Collections": "Kolekcijas",
- "Channels": "Kanāli",
- "CameraImageUploadedFrom": "Jauns kameras attēls tika augšupielādēts no {0}",
"Books": "Grāmatas",
"Artists": "Izpildītāji",
- "Albums": "Albumi",
- "ProviderValue": "Provider: {0}",
- "HeaderFavoriteSongs": "Dziesmu izlase",
"HeaderFavoriteShows": "Raidījumu izlase",
"HeaderFavoriteEpisodes": "Sēriju izlase",
- "HeaderFavoriteArtists": "Izpildītāju izlase",
- "HeaderFavoriteAlbums": "Albumu izlase",
"TaskCleanCacheDescription": "Nodzēš kešatmiņas datnes, kas vairs nav sistēmai vajadzīgas.",
"TaskRefreshChapterImages": "Izvilkt nodaļu attēlus",
"TasksApplicationCategory": "Lietotne",
diff --git a/Emby.Server.Implementations/Localization/Core/lzh.json b/Emby.Server.Implementations/Localization/Core/lzh.json
index 9fb53e41d5..6b61755d12 100644
--- a/Emby.Server.Implementations/Localization/Core/lzh.json
+++ b/Emby.Server.Implementations/Localization/Core/lzh.json
@@ -1,10 +1,8 @@
{
- "Albums": "辑册",
"Artists": "艺人",
"AuthenticationSucceededWithUserName": "{0} 授之权矣",
"Books": "册",
"Genres": "类",
- "HeaderAlbumArtists": "辑者",
"Favorites": "至爱",
"Folders": "箧",
"HeaderContinueWatching": "接目未竟"
diff --git a/Emby.Server.Implementations/Localization/Core/mi.json b/Emby.Server.Implementations/Localization/Core/mi.json
index 3b20abb369..000e82ebdf 100644
--- a/Emby.Server.Implementations/Localization/Core/mi.json
+++ b/Emby.Server.Implementations/Localization/Core/mi.json
@@ -1,9 +1,6 @@
{
- "Albums": "Pukaemi",
"AppDeviceValues": "Taupānga: {0}, Pūrere: {1}",
- "Application": "Taupānga",
"Artists": "Kaiwaiata",
"AuthenticationSucceededWithUserName": "{0} has been successfully authenticated",
- "Books": "Ngā pukapuka",
- "CameraImageUploadedFrom": "Kua tuku ake he whakaahua kāmera hou mai i {0}"
+ "Books": "Ngā pukapuka"
}
diff --git a/Emby.Server.Implementations/Localization/Core/mk.json b/Emby.Server.Implementations/Localization/Core/mk.json
index efef194e14..daf8112eef 100644
--- a/Emby.Server.Implementations/Localization/Core/mk.json
+++ b/Emby.Server.Implementations/Localization/Core/mk.json
@@ -1,11 +1,8 @@
{
"ScheduledTaskFailedWithName": "{0} неуспешно",
- "ProviderValue": "Провајдер: {0}",
"PluginUpdatedWithName": "{0} беше надоградено",
"PluginUninstalledWithName": "{0} беше успешно деинсталирано",
"PluginInstalledWithName": "{0} беше успешно инсталирано",
- "Plugin": "Додатоци",
- "Playlists": "Плејлисти",
"Photos": "Слики",
"NotificationOptionVideoPlaybackStopped": "Видео стопирано",
"NotificationOptionVideoPlayback": "Видео пуштено",
@@ -31,49 +28,29 @@
"Music": "Музика",
"Movies": "Филмови",
"MixedContent": "Мешана содржина",
- "MessageServerConfigurationUpdated": "Серверската конфигурација беше надградена",
- "MessageNamedServerConfigurationUpdatedWithValue": "Секцијата на конфигурација на сервер {0} беше надоградена",
- "MessageApplicationUpdatedTo": "Jellyfin беше надограден до {0}",
- "MessageApplicationUpdated": "Jellyfin Серверот беше надограден",
"Latest": "Последно",
"LabelRunningTimeValue": "Време на работа: {0}",
"LabelIpAddressValue": "ИП Адреса: {0}",
- "ItemRemovedWithName": "{0} е избришано до Библиотеката",
- "ItemAddedWithName": "{0} беше додадено во Библиотеката",
"Inherit": "Следно",
"HomeVideos": "Домашни Видеа",
- "HeaderRecordingGroups": "Групи на снимање",
"HeaderNextUp": "Следно",
"HeaderLiveTV": "ТВ",
- "HeaderFavoriteSongs": "Омилени Песни",
"HeaderFavoriteShows": "Омилени Серии",
"HeaderFavoriteEpisodes": "Омилени Епизоди",
- "HeaderFavoriteArtists": "Омилени Изведувачи",
- "HeaderFavoriteAlbums": "Омилени Албуми",
"HeaderContinueWatching": "Продолжи со Гледање",
- "HeaderAlbumArtists": "Изведувачи од Албуми",
"Genres": "Жанрови",
"Folders": "Папки",
"Favorites": "Омилени",
"FailedLoginAttemptWithUserName": "Неуспешен обид за најавување од {0}",
- "DeviceOnlineWithName": "{0} е приклучен",
- "DeviceOfflineWithName": "{0} се исклучи",
"Collections": "Колекции",
"ChapterNameValue": "Дел {0}",
- "Channels": "Канали",
- "CameraImageUploadedFrom": "Нова слика од камера беше поставена од {0}",
"Books": "Книги",
"AuthenticationSucceededWithUserName": "{0} успешно поврзан",
"Artists": "Изведувачи",
- "Application": "Апликација",
"AppDeviceValues": "Апликација: {0}, Уред: {1}",
- "Albums": "Албуми",
"VersionNumber": "Верзија {0}",
- "ValueSpecialEpisodeName": "Специјално - {0}",
- "ValueHasBeenAddedToLibrary": "{0} е додадено во твојата библиотека",
"UserStoppedPlayingItemWithValues": "{0} заврши со репродукција {1} во {2}",
"UserStartedPlayingItemWithValues": "{0} пушти {1} на {2}",
- "UserPolicyUpdatedWithName": "Полисата на користење беше надоградена за {0}",
"UserPasswordChangedWithName": "Лозинката е сменета за корисникот {0}",
"UserOnlineFromDevice": "{0} е приклучен од {1}",
"UserOfflineFromDevice": "{0} е дисконектиран од {1}",
@@ -81,16 +58,10 @@
"UserDownloadingItemWithValues": "{0} се спушта {1}",
"UserDeletedWithName": "Корисникот {0} е избришан",
"UserCreatedWithName": "Корисникот {0} е креиран",
- "User": "Корисник",
"TvShows": "ТВ Серии",
- "System": "Систем",
- "Sync": "Синхронизација",
"SubtitleDownloadFailureFromForItem": "Преводот неуспешно се спушти од {0} за {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server се пушта. Ве молиме причекајте.",
- "Songs": "Песни",
"Shows": "Серии",
- "ServerNameNeedsToBeRestarted": "{0} треба да се рестартира",
- "ScheduledTaskStartedWithName": "{0} започна",
"TaskRefreshChapterImages": "Извези Слики од Поглавје",
"TaskCleanCacheDescription": "Ги брише кешираните фајлови што не се повеќе потребни од системот.",
"TaskCleanCache": "Исчисти Го Кешот",
diff --git a/Emby.Server.Implementations/Localization/Core/ml.json b/Emby.Server.Implementations/Localization/Core/ml.json
index 5f098bccac..c43a5a7431 100644
--- a/Emby.Server.Implementations/Localization/Core/ml.json
+++ b/Emby.Server.Implementations/Localization/Core/ml.json
@@ -1,32 +1,18 @@
{
"AppDeviceValues": "അപ്ലിക്കേഷൻ: {0}, ഉപകരണം: {1}",
- "Application": "അപ്ലിക്കേഷൻ",
"AuthenticationSucceededWithUserName": "{0} വിജയകരമായി പ്രാമാണീകരിച്ചു",
- "CameraImageUploadedFrom": "{0} എന്നതിൽ നിന്ന് ഒരു പുതിയ ക്യാമറ ചിത്രം അപ്‌ലോഡുചെയ്‌തു",
"ChapterNameValue": "അധ്യായം {0}",
- "DeviceOfflineWithName": "{0} വിച്ഛേദിച്ചു",
- "DeviceOnlineWithName": "{0} ബന്ധിപ്പിച്ചു",
"FailedLoginAttemptWithUserName": "{0}ൽ നിന്നുള്ള പ്രവേശന ശ്രമം പരാജയപ്പെട്ടു",
"Forced": "നിർബന്ധിതമായി",
- "HeaderFavoriteAlbums": "പ്രിയപ്പെട്ട ആൽബങ്ങൾ",
- "HeaderFavoriteArtists": "പ്രിയപ്പെട്ട കലാകാരന്മാർ",
"HeaderFavoriteEpisodes": "പ്രിയപ്പെട്ട എപ്പിസോഡുകൾ",
"HeaderFavoriteShows": "പ്രിയപ്പെട്ട ഷോകൾ",
- "HeaderFavoriteSongs": "പ്രിയപ്പെട്ട ഗാനങ്ങൾ",
"HeaderLiveTV": "തത്സമയ ടിവി",
"HeaderNextUp": "അടുത്തത്",
- "HeaderRecordingGroups": "ഗ്രൂപ്പുകൾ റെക്കോർഡുചെയ്യുന്നു",
"HomeVideos": "ഹോം വീഡിയോകൾ",
"Inherit": "അനന്തരാവകാശം",
- "ItemAddedWithName": "{0} ലൈബ്രറിയിൽ ചേർത്തു",
- "ItemRemovedWithName": "{0} ലൈബ്രറിയിൽ നിന്ന് നീക്കംചെയ്തു",
"LabelIpAddressValue": "IP വിലാസം: {0}",
"LabelRunningTimeValue": "പ്രവർത്തന സമയം: {0}",
"Latest": "ഏറ്റവും പുതിയ",
- "MessageApplicationUpdated": "ജെല്ലിഫിൻ സെർവർ അപ്‌ഡേറ്റുചെയ്‌തു",
- "MessageApplicationUpdatedTo": "ജെല്ലിഫിൻ സെർവർ {0 to ലേക്ക് അപ്‌ഡേറ്റുചെയ്‌തു",
- "MessageNamedServerConfigurationUpdatedWithValue": "സെർവർ കോൺഫിഗറേഷൻ വിഭാഗം {0 അപ്‌ഡേറ്റുചെയ്‌തു",
- "MessageServerConfigurationUpdated": "സെർവർ കോൺഫിഗറേഷൻ അപ്‌ഡേറ്റുചെയ്‌തു",
"MixedContent": "മിശ്രിത ഉള്ളടക്കം",
"Music": "സംഗീതം",
"MusicVideos": "സംഗീത വീഡിയോകൾ",
@@ -50,20 +36,14 @@
"NotificationOptionUserLockedOut": "ഉപയോക്താവ് ലോക്ക് out ട്ട് ചെയ്‌തു",
"NotificationOptionVideoPlayback": "വീഡിയോ പ്ലേബാക്ക് ആരംഭിച്ചു",
"NotificationOptionVideoPlaybackStopped": "വീഡിയോ പ്ലേബാക്ക് നിർത്തി",
- "Plugin": "പ്ലഗിൻ",
"PluginInstalledWithName": "{0} ഇൻസ്റ്റാളുചെയ്‌തു",
"PluginUninstalledWithName": "{0 un അൺഇൻസ്റ്റാൾ ചെയ്തു",
"PluginUpdatedWithName": "{0} അപ്‌ഡേറ്റുചെയ്‌തു",
- "ProviderValue": "ദാതാവ്: {0}",
"ScheduledTaskFailedWithName": "{0} പരാജയപ്പെട്ടു",
- "ScheduledTaskStartedWithName": "{0} ആരംഭിച്ചു",
- "ServerNameNeedsToBeRestarted": "{0} പുനരാരംഭിക്കേണ്ടതുണ്ട്",
"StartupEmbyServerIsLoading": "ജെല്ലിഫിൻ സെർവർ ലോഡുചെയ്യുന്നു. ഉടൻ തന്നെ വീണ്ടും ശ്രമിക്കുക.",
"SubtitleDownloadFailureFromForItem": "സബ്ടൈറ്റിലുകൾ {1} ന് {0 from ൽ നിന്ന് ഡ download ൺലോഡ് ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു",
- "System": "സിസ്റ്റം",
"TvShows": "ടിവി ഷോകൾ",
"Undefined": "നിർവചിച്ചിട്ടില്ല",
- "User": "ഉപയോക്താവ്",
"UserCreatedWithName": "ഉപയോക്താവ് {0 created സൃഷ്ടിച്ചു",
"UserDeletedWithName": "ഉപയോക്താവ് {0 deleted ഇല്ലാതാക്കി",
"UserDownloadingItemWithValues": "{0} ഡൗൺലോഡുചെയ്യുന്നു {1}",
@@ -71,10 +51,8 @@
"UserOfflineFromDevice": "{0} {1} ൽ നിന്ന് വിച്ഛേദിച്ചു",
"UserOnlineFromDevice": "{0} {1} മുതൽ ഓൺ‌ലൈനിലാണ്",
"UserPasswordChangedWithName": "{0} ഉപയോക്താവിനായി പാസ്‌വേഡ് മാറ്റി",
- "UserPolicyUpdatedWithName": "{0} എന്നതിനായി ഉപയോക്തൃ നയം അപ്‌ഡേറ്റുചെയ്‌തു",
"UserStartedPlayingItemWithValues": "{0} {2} ൽ {1} പ്ലേ ചെയ്യുന്നു",
"UserStoppedPlayingItemWithValues": "{0} {2} ൽ {1 play കളിക്കുന്നത് പൂർത്തിയാക്കി",
- "ValueHasBeenAddedToLibrary": "Media 0 your നിങ്ങളുടെ മീഡിയ ലൈബ്രറിയിലേക്ക് ചേർത്തു",
"VersionNumber": "പതിപ്പ് {0}",
"TasksMaintenanceCategory": "പരിപാലനം",
"TasksLibraryCategory": "പുസ്തകശാല",
@@ -100,16 +78,10 @@
"TaskRefreshChannelsDescription": "ഇന്റർനെറ്റ് ചാനൽ വിവരങ്ങൾ പുതുക്കുന്നു.",
"TaskDownloadMissingSubtitles": "നഷ്‌ടമായ സബ്‌ടൈറ്റിലുകൾ ഡൗൺലോഡുചെയ്യുക",
"TaskDownloadMissingSubtitlesDescription": "മെറ്റാഡാറ്റ കോൺഫിഗറേഷനെ അടിസ്ഥാനമാക്കി നഷ്‌ടമായ സബ്‌ടൈറ്റിലുകൾക്കായി ഇന്റർനെറ്റ് തിരയുന്നു.",
- "ValueSpecialEpisodeName": "പ്രത്യേക - {0}",
"Collections": "ശേഖരങ്ങൾ",
"Folders": "ഫോൾഡറുകൾ",
- "HeaderAlbumArtists": "കലാകാരന്റെ ആൽബം",
- "Sync": "സമന്വയിപ്പിക്കുക",
"Movies": "സിനിമകൾ",
"Photos": "ഫോട്ടോകൾ",
- "Albums": "ആൽബങ്ങൾ",
- "Playlists": "പ്ലേലിസ്റ്റുകൾ",
- "Songs": "ഗാനങ്ങൾ",
"HeaderContinueWatching": "കാണുന്നത് തുടരുക",
"Artists": "കലാകാരന്മാർ",
"Shows": "ഷോകൾ",
@@ -117,7 +89,6 @@
"Favorites": "പ്രിയപ്പെട്ടവ",
"Books": "പുസ്തകങ്ങൾ",
"Genres": "വിഭാഗങ്ങൾ",
- "Channels": "ചാനലുകൾ",
"TaskOptimizeDatabaseDescription": "ഡാറ്റാബേസ് ചുരുക്കുകയും സ്വതന്ത്ര ഇടം വെട്ടിച്ചുരുക്കുകയും ചെയ്യുന്നു. ലൈബ്രറി സ്‌കാൻ ചെയ്‌തതിനുശേഷം അല്ലെങ്കിൽ ഡാറ്റാബേസ് പരിഷ്‌ക്കരണങ്ങളെ സൂചിപ്പിക്കുന്ന മറ്റ് മാറ്റങ്ങൾ ചെയ്‌തതിന് ശേഷം ഈ ടാസ്‌ക് പ്രവർത്തിപ്പിക്കുന്നത് പ്രകടനം മെച്ചപ്പെടുത്തും.",
"TaskOptimizeDatabase": "ഡാറ്റാബേസ് ഒപ്റ്റിമൈസ് ചെയ്യുക",
"HearingImpaired": "കേൾവി തകരാറുകൾ",
diff --git a/Emby.Server.Implementations/Localization/Core/mn.json b/Emby.Server.Implementations/Localization/Core/mn.json
index 63f4d0cef3..83caaf346f 100644
--- a/Emby.Server.Implementations/Localization/Core/mn.json
+++ b/Emby.Server.Implementations/Localization/Core/mn.json
@@ -2,15 +2,12 @@
"Books": "Номнууд",
"HeaderNextUp": "Дараа нь",
"HeaderContinueWatching": "Үргэлжлүүлэн үзэх",
- "Songs": "Дуунууд",
- "Playlists": "Тоглуулах жагсаалтууд",
"Movies": "Кинонууд",
"Latest": "Сүүлийн үеийн",
"Genres": "Төрлүүд",
"Favorites": "Дуртай",
"Collections": "Цуглуулгууд",
"Artists": "Уран бүтээлчид",
- "Albums": "Дуут цомгууд",
"TaskExtractMediaSegments": "Медиа сегмент шалга",
"TaskExtractMediaSegmentsDescription": "MediaSegment идэвхжүүлсэн залгаасуудаас медиа сегментүүдийг задлах эсвэл олж авах.",
"TaskMoveTrickplayImages": "Трикплэй зургуудын байршлыг шилжүүлэх",
@@ -21,7 +18,6 @@
"TaskKeyframeExtractor": "Түлхүүр кадр гаргагч",
"TaskCleanCache": "Кэш санг цэвэрлэх",
"NewVersionIsAvailable": "Jellyfin Server-н шинэ хувилбар татаж авахад нээлттэй боллоо.",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server-н {0}-р хэсгийн тохиргоо шинэчлэгдлээ",
"NotificationOptionAudioPlaybackStopped": "Дууг зогсоов",
"NotificationOptionNewLibraryContent": "Шинэ агуулга орлоо",
"NotificationOptionServerRestartRequired": "Server-г дахин асаана уу",
@@ -33,7 +29,6 @@
"SubtitleDownloadFailureFromForItem": "{0}-г {1}-д зориулсан хадмал орчуулгыг татаж авч чадсангүй",
"TaskRefreshLibraryDescription": "Таны медиа санг шинэ файлуудын хувьд шалгаж, мета мэдээллийг шинэчилнэ.",
"UserOfflineFromDevice": "{0}-г {1}-с салгалаа",
- "ValueHasBeenAddedToLibrary": "{0}-г медиа сан руу нэмэгдлээ",
"TaskRefreshPeopleDescription": "Таны медиа санд байгаа жүжигчид болон найруулагчдын мета мэдээллийг шинэчилнэ.",
"TaskCleanTranscodeDescription": "Нэг өдрөөс илүү настай транскодлох файлуудыг устгана.",
"TaskRefreshChannelsDescription": "Интернет сувгуудын мэдээллийг шинэчлэх.",
@@ -51,36 +46,21 @@
"TaskRefreshChannels": "Сувгуудыг шинэчлэх",
"TaskDownloadMissingSubtitles": "Алга болсон хадмал орчуулгыг татах",
"External": "Гадны",
- "HeaderFavoriteArtists": "Дуртай уран бүтээлчид",
"HeaderFavoriteEpisodes": "Дуртай ангиуд",
"HeaderFavoriteShows": "Дуртай нэвтрүүлэг",
- "HeaderFavoriteSongs": "Дуртай дуу",
"AppDeviceValues": "Aпп: {0}, Төхөөрөмж: {1}",
- "Application": "Aпп",
"AuthenticationSucceededWithUserName": "{0} амжилттай нэвтэрлээ",
- "CameraImageUploadedFrom": "{0}-с шинэ зураг байршуулагдлаа",
- "Channels": "Сувгууд",
"ChapterNameValue": "{0}-р бүлэг",
"Default": "Анхдагч",
- "DeviceOfflineWithName": "{0}-н холболт саллаа",
- "DeviceOnlineWithName": "{0} холбогдлоо",
"FailedLoginAttemptWithUserName": "{0}-н нэвтрэх оролдлого амжилтгүй",
"Folders": "Хавтасууд",
"Forced": "Хүчээр",
- "HeaderAlbumArtists": "Цомгийн уран бүтээлчид",
- "HeaderFavoriteAlbums": "Дуртай цомгууд",
"HeaderLiveTV": "Шууд ТВ",
- "HeaderRecordingGroups": "Бичлэгийн бүлгүүд",
"HearingImpaired": "Сонсголын бэрхшээлтэй",
"HomeVideos": "Үндсэн дүрсүүд",
"Inherit": "Уламжлах",
- "ItemAddedWithName": "{0}-г санд нэмлээ",
- "ItemRemovedWithName": "{0}-с сангаас хаслаа",
"LabelIpAddressValue": "IP хаяг: {0}",
"LabelRunningTimeValue": "Үргэлжлэх хугацаа: {0}",
- "MessageApplicationUpdated": "Jellyfin Server шинэчлэгдлээ",
- "MessageApplicationUpdatedTo": "Jellyfin Server {0} болж шинэчлэгдлээ",
- "MessageServerConfigurationUpdated": "Server-н тохиргоо шинэчлэгдлээ",
"MixedContent": "Холимог агуулга",
"Music": "Хөгжим",
"MusicVideos": "Дууны клипүүд",
@@ -99,28 +79,19 @@
"NotificationOptionUserLockedOut": "Хэрэглэгчийг түгжив",
"NotificationOptionVideoPlayback": "Бичлэгийг тоглуулж эхлэв",
"Photos": "Зургууд",
- "Plugin": "Плагин",
"PluginInstalledWithName": "{0}-г суулгалаа",
"PluginUninstalledWithName": "{0}-г устгалаа",
"PluginUpdatedWithName": "{0}-г шинэчиллээ",
- "ProviderValue": "Нийлүүлэгч: {0}",
- "ScheduledTaskStartedWithName": "{0}-г эхлүүлэв",
- "ServerNameNeedsToBeRestarted": "{0}-г дахин асаана уу",
"Shows": "Шоу",
- "Sync": "Синхрончлох",
- "System": "Систем",
"TvShows": "ТВ нэвтрүүлгүүд",
"Undefined": "Танисангүй",
- "User": "Хэрэглэгч",
"UserCreatedWithName": "Хэрэглэгч {0}-г үүсгэлээ",
"UserDeletedWithName": "Хэрэглэгч {0}-г устгалаа",
"UserDownloadingItemWithValues": "{0} нь {1}-г татаж байна",
"UserLockedOutWithName": "Хэрэглэгч {0}-г түгжлээ",
"UserOnlineFromDevice": "{0} нь {1}-тэй холбоотой байна",
- "UserPolicyUpdatedWithName": "Хэрэглэгчийн журмыг {0}-д зориулан шинэчиллээ",
"UserStartedPlayingItemWithValues": "{0}-г {2} дээр {1}-г тоглуулж байна",
"UserStoppedPlayingItemWithValues": "{0}-г {2} дээр {1}-г тоглуулж дуусгалаа",
- "ValueSpecialEpisodeName": "Онцгой - {0}",
"VersionNumber": "Хувилбар {0}",
"TasksMaintenanceCategory": "Засвар",
"TasksLibraryCategory": "Сан",
diff --git a/Emby.Server.Implementations/Localization/Core/mr.json b/Emby.Server.Implementations/Localization/Core/mr.json
index 267222ecbe..f169d085d5 100644
--- a/Emby.Server.Implementations/Localization/Core/mr.json
+++ b/Emby.Server.Implementations/Localization/Core/mr.json
@@ -1,22 +1,13 @@
{
"Books": "पुस्तकं",
"Artists": "संगीतकार",
- "Albums": "अल्बम",
- "Playlists": "प्लेलिस्ट",
- "HeaderAlbumArtists": "अल्बम संगीतकार",
"Folders": "फोल्डर",
"HeaderFavoriteEpisodes": "आवडते भाग",
- "HeaderFavoriteSongs": "आवडती गाणी",
"Movies": "चित्रपट",
- "HeaderFavoriteArtists": "आवडते संगीतकार",
"Shows": "कार्यक्रम",
- "HeaderFavoriteAlbums": "आवडते अल्बम",
- "Channels": "वाहिन्या",
- "ValueSpecialEpisodeName": "विशेष - {0}",
"HeaderFavoriteShows": "आवडते कार्यक्रम",
"Favorites": "आवडीचे",
"HeaderNextUp": "यानंतर",
- "Songs": "गाणी",
"HeaderLiveTV": "लाइव्ह टीव्ही",
"Genres": "जाँनरे",
"Photos": "चित्र",
@@ -34,10 +25,8 @@
"UserOnlineFromDevice": "{0} हे {1} येथून ऑनलाइन आहेत",
"UserDeletedWithName": "प्रयोक्ता {0} काढून टाकण्यात आले आहे",
"UserCreatedWithName": "प्रयोक्ता {0} बनवण्यात आले आहे",
- "User": "प्रयोक्ता",
"TvShows": "टीव्ही कार्यक्रम",
"StartupEmbyServerIsLoading": "जेलिफिन सर्व्हर लोड होत आहे. कृपया थोड्या वेळात पुन्हा प्रयत्न करा.",
- "Plugin": "प्लगइन",
"NotificationOptionCameraImageUploaded": "कॅमेरा चित्र अपलोड केले आहे",
"NotificationOptionApplicationUpdateInstalled": "अ‍ॅप्लिकेशन अपडेट इन्स्टॉल केले आहे",
"NotificationOptionApplicationUpdateAvailable": "अ‍ॅप्लिकेशन अपडेट उपलब्ध आहे",
@@ -46,16 +35,9 @@
"NameSeasonNumber": "सीझन {0}",
"MusicVideos": "संगीत व्हिडीयो",
"Music": "संगीत",
- "MessageApplicationUpdatedTo": "जेलिफिन सर्व्हर अपडेट होऊन {0} आवृत्तीवर पोहोचला आहे",
- "MessageApplicationUpdated": "जेलिफिन सर्व्हर अपडेट केला गेला आहे",
"Latest": "नवीनतम",
"LabelIpAddressValue": "आयपी पत्ता: {0}",
- "ItemRemovedWithName": "{0} हे संग्रहालयातून काढून टाकण्यात आले",
- "ItemAddedWithName": "{0} हे संग्रहालयात जोडले गेले",
"HomeVideos": "घरचे व्हिडीयो",
- "HeaderRecordingGroups": "रेकॉर्डिंग गट",
- "CameraImageUploadedFrom": "एक नवीन कॅमेरा चित्र {0} येथून अपलोड केले आहे",
- "Application": "अ‍ॅप्लिकेशन",
"AppDeviceValues": "अ‍ॅप: {0}, यंत्र: {1}",
"Collections": "संग्रह",
"ChapterNameValue": "धडा {0}",
@@ -70,18 +52,12 @@
"TaskRefreshChapterImagesDescription": "अध्याय असलेल्या व्हिडियोंसाठी थंबनेल चित्र बनवतो.",
"TaskRefreshChapterImages": "अध्याय चित्र काढून घ्या",
"TasksMaintenanceCategory": "देखरेख",
- "ValueHasBeenAddedToLibrary": "{0} हे तुमच्या माध्यम संग्रहात जोडण्यात आले आहे",
"UserStoppedPlayingItemWithValues": "{0} यांचं {2} वर {1} पूर्णपणे प्ले करून झालं आहे",
"UserStartedPlayingItemWithValues": "{0} हे {2} वर {1} प्ले करत आहे",
"UserDownloadingItemWithValues": "{0} हे {1} डाउनलोड करत आहे",
- "System": "प्रणाली",
"Undefined": "अव्याख्यात",
- "Sync": "सिंक",
- "ServerNameNeedsToBeRestarted": "{0} याला बंद करून पुन्हा सुरू करायची गरज आहे",
"SubtitleDownloadFailureFromForItem": "{0} येथून {1} यासाठी उपशिर्षक डाउनलोड करण्यात अपयश",
- "ScheduledTaskStartedWithName": "{0} सुरू झाले",
"ScheduledTaskFailedWithName": "{0} अपयशी झाले",
- "ProviderValue": "पुरवणारा: {0}",
"PluginUpdatedWithName": "{0} अपडेट केले",
"PluginUninstalledWithName": "{0} अनिन्स्टॉल केले",
"PluginInstalledWithName": "{0} इन्स्टॉल केले",
@@ -109,19 +85,14 @@
"TaskCleanCacheDescription": "सिस्टमला यापुढे आवश्यक नसलेल्या कॅशे फाइल्स हटवा.",
"TaskCleanActivityLogDescription": "कॉन्फिगर केलेल्या वयापेक्षा जुन्या क्रियाकलाप लॉग एंट्री हटवा.",
"TaskCleanActivityLog": "क्रियाकलाप लॉग साफ करा",
- "UserPolicyUpdatedWithName": "{0} साठी वापरकर्ता धोरण अपडेट केले गेले आहे",
"UserOfflineFromDevice": "{0} {1} वरून डिस्कनेक्ट झाला आहे",
"UserLockedOutWithName": "वापरकर्ता {0} लॉक केले गेले आहे",
"NotificationOptionUserLockedOut": "वापरकर्ता लॉक आउट",
"NameInstallFailed": "{0} स्थापना अयशस्वी",
- "MessageServerConfigurationUpdated": "सर्व्हर कॉन्फिगरेशन अद्यतनित केले आहे",
- "MessageNamedServerConfigurationUpdatedWithValue": "सर्व्हर कॉन्फिगरेशन विभाग {0} अद्यतनित केला गेला आहे",
"Inherit": "वारसा",
"Forced": "सक्ती केली आहे",
"FailedLoginAttemptWithUserName": "{0} कडून लॉगिन करण्याचा प्रयत्न अयशस्वी झाला",
"External": "बाहेरचा",
- "DeviceOnlineWithName": "{0} कनेक्ट झाले",
- "DeviceOfflineWithName": "{0} डिस्कनेक्ट झाला आहे",
"AuthenticationSucceededWithUserName": "{0} यशस्वीरित्या प्रमाणीकृत",
"HearingImpaired": "कर्णबधीर",
"TaskRefreshTrickplayImages": "ट्रिकप्ले प्रतिमा तयार करा",
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index 743c14ac10..9fc61fadd5 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -1,41 +1,24 @@
{
- "Albums": "Album",
"AppDeviceValues": "Aplikasi: {0}, Peranti: {1}",
- "Application": "Aplikasi",
"Artists": "Artis",
"AuthenticationSucceededWithUserName": "{0} berjaya disahkan",
"Books": "Buku",
- "CameraImageUploadedFrom": "Gambar baharu telah dimuat naik melalui {0}",
- "Channels": "Saluran",
"ChapterNameValue": "Bab {0}",
"Collections": "Koleksi",
- "DeviceOfflineWithName": "{0} telah dinyahsambung",
- "DeviceOnlineWithName": "{0} telah disambung",
"FailedLoginAttemptWithUserName": "Percubaan gagal log masuk daripada {0}",
"Favorites": "Kegemaran",
"Folders": "Folder-folder",
"Genres": "Genre-genre",
- "HeaderAlbumArtists": "Album artis-artis",
"HeaderContinueWatching": "Teruskan Menonton",
- "HeaderFavoriteAlbums": "Album-album Kegemaran",
- "HeaderFavoriteArtists": "Artis-artis Kegemaran",
"HeaderFavoriteEpisodes": "Episod-episod Kegemaran",
"HeaderFavoriteShows": "Rancangan-rancangan Kegemaran",
- "HeaderFavoriteSongs": "Lagu-lagu Kegemaran",
"HeaderLiveTV": "TV Siaran Langsung",
"HeaderNextUp": "Seterusnya",
- "HeaderRecordingGroups": "Kumpulan-kumpulan Rakaman",
"HomeVideos": "Video Peribadi",
"Inherit": "Warisi",
- "ItemAddedWithName": "{0} telah ditambah ke dalam pustaka",
- "ItemRemovedWithName": "{0} telah dibuang daripada pustaka",
"LabelIpAddressValue": "Alamat IP: {0}",
"LabelRunningTimeValue": "Masa berjalan: {0}",
"Latest": "Terbaharu",
- "MessageApplicationUpdated": "Pelayan Jellyfin telah dikemas kini",
- "MessageApplicationUpdatedTo": "Pelayan Jellyfin telah dikemas kini ke {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan bahagian {0} telah dikemas kini",
- "MessageServerConfigurationUpdated": "Konfigurasi pelayan telah dikemas kini",
"MixedContent": "Kandungan campuran",
"Movies": "Filem-filem",
"Music": "Muzik",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Ulangmain video bermula",
"NotificationOptionVideoPlaybackStopped": "Ulangmain video dihentikan",
"Photos": "Gambar-gambar",
- "Playlists": "Senarai ulangmain",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} telah dipasang",
"PluginUninstalledWithName": "{0} telah dinyahpasang",
"PluginUpdatedWithName": "{0} telah dikemaskini",
- "ProviderValue": "Pembekal: {0}",
"ScheduledTaskFailedWithName": "{0} gagal",
- "ScheduledTaskStartedWithName": "{0} bermula",
- "ServerNameNeedsToBeRestarted": "{0} perlu di ulangmula",
"Shows": "Tayangan",
- "Songs": "Lagu-lagu",
"StartupEmbyServerIsLoading": "Pelayan Jellyfin sedang dimuatkan. Sila cuba sebentar lagi.",
"SubtitleDownloadFailureFromForItem": "Muat turun sarikata gagal dari {0} untuk {1}",
- "Sync": "Segerak",
- "System": "Sistem",
"TvShows": "Tayangan TV",
- "User": "Pengguna",
"UserCreatedWithName": "Pengguna {0} telah diwujudkan",
"UserDeletedWithName": "Pengguna {0} telah dipadamkan",
"UserDownloadingItemWithValues": "{0} sedang memuat turun {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} telah terputus dari {1}",
"UserOnlineFromDevice": "{0} berada dalam talian dari {1}",
"UserPasswordChangedWithName": "Kata laluan telah ditukar bagi pengguna {0}",
- "UserPolicyUpdatedWithName": "Dasar pengguna telah dikemas kini untuk {0}",
"UserStartedPlayingItemWithValues": "{0} sedang dimainkan {1} pada {2}",
"UserStoppedPlayingItemWithValues": "{0} telah tamat dimainkan {1} pada {2}",
- "ValueHasBeenAddedToLibrary": "{0} telah ditambah ke media library anda",
- "ValueSpecialEpisodeName": "Khas - {0}",
"VersionNumber": "Versi {0}",
"TaskCleanActivityLog": "Log Aktiviti Bersih",
"TasksChannelsCategory": "Saluran Internet",
diff --git a/Emby.Server.Implementations/Localization/Core/mt.json b/Emby.Server.Implementations/Localization/Core/mt.json
index aa3029a262..e237a80b70 100644
--- a/Emby.Server.Implementations/Localization/Core/mt.json
+++ b/Emby.Server.Implementations/Localization/Core/mt.json
@@ -1,28 +1,18 @@
{
- "Albums": "Albums",
"AppDeviceValues": "Applikazzjoni: {0}, Device: {1}",
- "Application": "Applikazzjoni",
"Artists": "Artisti",
"AuthenticationSucceededWithUserName": "{1} awtentikat b'suċċess",
"Books": "Kotba",
- "CameraImageUploadedFrom": "Ttella' ritratt ġdid tal-kamera minn {1}",
- "Channels": "Stazzjonijiet",
"ChapterNameValue": "Kapitlu {0}",
"Collections": "Kollezzjonijiet",
- "DeviceOfflineWithName": "{0} tneħħa",
- "DeviceOnlineWithName": "{0} tqabbad",
"External": "Estern",
"FailedLoginAttemptWithUserName": "Attentat fallut ta' login minn {0}",
"Favorites": "Favoriti",
"Forced": "Sfurzat",
"Genres": "Ġeneri",
- "HeaderAlbumArtists": "Artisti tal-album",
"HeaderContinueWatching": "Kompli Ara",
- "HeaderFavoriteAlbums": "Albums Favoriti",
- "HeaderFavoriteArtists": "Artisti Favoriti",
"HeaderFavoriteEpisodes": "Episodji Favoriti",
"HeaderFavoriteShows": "Programmi Favoriti",
- "HeaderFavoriteSongs": "Kanzunetti Favoriti",
"HeaderNextUp": "Li Jmiss",
"SubtitleDownloadFailureFromForItem": "Is-sottotitli ma setgħux jitniżżlu minn {0} għal {1}",
"UserPasswordChangedWithName": "Il-password għall-utent {0} inbidlet",
@@ -32,18 +22,11 @@
"Default": "Standard",
"Folders": "Folders",
"HeaderLiveTV": "TV Dirett",
- "HeaderRecordingGroups": "Gruppi ta' Rikordjar",
"HearingImpaired": "Nuqqas ta' Smigħ",
"HomeVideos": "Filmati Personali",
"Inherit": "Jiret",
- "ItemAddedWithName": "{0} żdied fil-librerija",
- "ItemRemovedWithName": "{0} tneħħa mil-librerija",
"LabelIpAddressValue": "Indirizz tal-IP: {0}",
"Latest": "Tal-Aħħar",
- "MessageApplicationUpdated": "Il-Jellyfin Server ġie aġġornat",
- "MessageApplicationUpdatedTo": "Il-JellyFin Server ġie aġġornat għal {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Is-sezzjoni {0} tal-konfigurazzjoni tas-server ġiet aġġornata",
- "MessageServerConfigurationUpdated": "Il-konfigurazzjoni tas-server ġiet aġġornata",
"MixedContent": "Kontenut imħallat",
"Movies": "Films",
"Music": "Mużika",
@@ -67,21 +50,12 @@
"NotificationOptionTaskFailed": "Falliment tat-task skedat",
"NotificationOptionUserLockedOut": "Utent imsakkar",
"Photos": "Ritratti",
- "Playlists": "Playlists",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} ġie installat",
"PluginUninstalledWithName": "{0} tneħħa",
"PluginUpdatedWithName": "{0} ġie aġġornat",
- "ProviderValue": "Fornitur: {0}",
"ScheduledTaskFailedWithName": "{0} falla",
- "ScheduledTaskStartedWithName": "{0} beda",
- "ServerNameNeedsToBeRestarted": "{0} jeħtieġ restart",
- "Songs": "Kanzunetti",
"StartupEmbyServerIsLoading": "Jellyfin Server qed jillowdja. Jekk jogħġbok erġa' pprova ftit tal-ħin oħra.",
- "Sync": "Sinkronizza",
- "System": "Sistema",
"Undefined": "Bla Definizzjoni",
- "User": "Utent",
"UserCreatedWithName": "L-utent {0} inħoloq",
"UserDeletedWithName": "L-utent {0} tħassar",
"UserDownloadingItemWithValues": "{0} qed iniżżel {1}",
@@ -93,11 +67,8 @@
"NotificationOptionVideoPlaybackStopped": "Il-playback tal-filmat twaqqaf",
"Shows": "Serje",
"TvShows": "Serje Televiżivi",
- "UserPolicyUpdatedWithName": "Il-politka tal-utent ġiet aġġornata għal {0}",
"UserStartedPlayingItemWithValues": "{0} qed jara {1} fuq {2}",
"UserStoppedPlayingItemWithValues": "{0} waqaf jara {1} fuq {2}",
- "ValueHasBeenAddedToLibrary": "{0} ġie miżjud mal-librerija tal-midja tiegħek",
- "ValueSpecialEpisodeName": "Speċjali - {0}",
"VersionNumber": "Verżjoni {0}",
"TasksMaintenanceCategory": "Manutenzjoni",
"TasksLibraryCategory": "Librerija",
diff --git a/Emby.Server.Implementations/Localization/Core/my.json b/Emby.Server.Implementations/Localization/Core/my.json
index f2cd501076..47728adfc5 100644
--- a/Emby.Server.Implementations/Localization/Core/my.json
+++ b/Emby.Server.Implementations/Localization/Core/my.json
@@ -1,10 +1,8 @@
{
"Default": "ပုံသေ",
"Collections": "စုစည်းမှုများ",
- "Channels": "တီဗွီလိုင်းများ",
"Books": "စာအုပ်များ",
"Artists": "အနုပညာရှင်များ",
- "Albums": "သီချင်းအခွေများ",
"TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.",
"TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ",
"TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။",
@@ -32,11 +30,8 @@
"TasksLibraryCategory": "မီဒီယာတိုက်",
"TasksMaintenanceCategory": "ပြုပြင် ထိန်းသိမ်းခြင်း",
"VersionNumber": "ဗားရှင်း {0}",
- "ValueSpecialEpisodeName": "အထူး- {0}",
- "ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ",
"UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ",
"UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်",
- "UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်",
"UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်",
"UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်",
@@ -44,24 +39,15 @@
"UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်",
"UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ",
"UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ",
- "User": "အသုံးပြုသူ",
"Undefined": "သတ်မှတ်မထားသော",
"TvShows": "တီဗီ ဇာတ်လမ်းတွဲများ",
- "System": "စနစ်",
- "Sync": "ချိန်ကိုက်မည်",
"SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ",
"StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို အသင့်ပြင်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။",
- "Songs": "သီချင်းများ",
"Shows": "ဇာတ်လမ်းတွဲများ",
- "ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်",
- "ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်",
"ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ",
- "ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}",
"PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်",
"PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ",
"PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်",
- "Plugin": "ပလပ်အင်",
- "Playlists": "အစီအစဉ်များ",
"Photos": "ဓာတ်ပုံများ",
"NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ",
@@ -87,38 +73,23 @@
"Music": "တေးဂီတ",
"Movies": "ရုပ်ရှင်များ",
"MixedContent": "ရောနှောပါဝင်မှု",
- "MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
- "MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
- "MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်",
- "MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"Latest": "နောက်ဆုံး",
"LabelRunningTimeValue": "ကြာချိန် - {0}",
"LabelIpAddressValue": "IP လိပ်စာ- {0}",
- "ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်",
- "ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်",
"Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်",
"HomeVideos": "ကိုယ်တိုင်ရိုက် ဗီဒီယိုများ",
- "HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ",
"HeaderNextUp": "နောက်ထပ်",
"HeaderLiveTV": "တီဗွီတိုက်ရိုက်",
- "HeaderFavoriteSongs": "အကြိုက်ဆုံးသီချင်းများ",
"HeaderFavoriteShows": "အကြိုက်ဆုံး ဇာတ်လမ်းတွဲများ",
"HeaderFavoriteEpisodes": "အကြိုက်ဆုံး ဇာတ်လမ်းအပိုင်းများ",
- "HeaderFavoriteArtists": "အကြိုက်ဆုံး အနုပညာရှင်များ",
- "HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ",
"HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ",
- "HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ",
"Genres": "အမျိုးအစားများ",
"Forced": "အတင်းအကြပ်",
"Folders": "ဖိုလ်ဒါများ",
"Favorites": "အကြိုက်ဆုံးများ",
"FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ",
- "DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်",
- "DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ",
"ChapterNameValue": "အခန်း {0}",
- "CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်",
"AuthenticationSucceededWithUserName": "{0} အောင်မြင်စွာ စစ်မှန်ကြောင်း အတည်ပြုပြီးပါပြီ",
- "Application": "အပလီကေးရှင်း",
"AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}",
"External": "ပြင်ပ",
"TaskKeyframeExtractorDescription": "ပိုမိုတိကျသည့် အိတ်ချ်အယ်လ်အက်စ် အစဉ်လိုက်ပြသမှုများ ဖန်တီးနိုင်ရန်အတွက် ဗီဒီယိုဖိုင်များမှ ကီးဖရိန်များကို ထုတ်နှုတ်ယူမည် ဖြစ်သည်။ ဤလုပ်ဆောင်မှုသည် အချိန်ကြာရှည်နိုင်သည်။",
diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json
index 351b238f9d..752b74ec1c 100644
--- a/Emby.Server.Implementations/Localization/Core/nb.json
+++ b/Emby.Server.Implementations/Localization/Core/nb.json
@@ -1,41 +1,24 @@
{
- "Albums": "Album",
"AppDeviceValues": "App: {0}, Enhet: {1}",
- "Application": "Program",
"Artists": "Artister",
"AuthenticationSucceededWithUserName": "{0} har logget inn",
"Books": "Bøker",
- "CameraImageUploadedFrom": "Et nytt kamerabilde har blitt lastet opp fra {0}",
- "Channels": "Kanaler",
"ChapterNameValue": "Kapittel {0}",
"Collections": "Samlinger",
- "DeviceOfflineWithName": "{0} har koblet fra",
- "DeviceOnlineWithName": "{0} er tilkoblet",
"FailedLoginAttemptWithUserName": "Mislykket påloggingsforsøk fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
"Genres": "Sjangre",
- "HeaderAlbumArtists": "Albumartister",
"HeaderContinueWatching": "Fortsett å se",
- "HeaderFavoriteAlbums": "Favorittalbum",
- "HeaderFavoriteArtists": "Favorittartister",
"HeaderFavoriteEpisodes": "Favorittepisoder",
"HeaderFavoriteShows": "Favorittserier",
- "HeaderFavoriteSongs": "Favorittsanger",
"HeaderLiveTV": "Direkte-TV",
"HeaderNextUp": "Neste",
- "HeaderRecordingGroups": "Opptaksgrupper",
"HomeVideos": "Hjemmelagde filmer",
"Inherit": "Arve",
- "ItemAddedWithName": "{0} ble lagt til i biblioteket",
- "ItemRemovedWithName": "{0} ble fjernet fra biblioteket",
"LabelIpAddressValue": "IP-adresse: {0}",
"LabelRunningTimeValue": "Spilletid: {0}",
"Latest": "Siste",
- "MessageApplicationUpdated": "Jellyfin-serveren har blitt oppdatert",
- "MessageApplicationUpdatedTo": "Jellyfin-serveren ble oppdatert til {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfigurasjonsseksjon {0} har blitt oppdatert",
- "MessageServerConfigurationUpdated": "Serverkonfigurasjon har blitt oppdatert",
"MixedContent": "Blandet innhold",
"Movies": "Filmer",
"Music": "Musikk",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Videoavspilling startet",
"NotificationOptionVideoPlaybackStopped": "Videoavspilling stoppet",
"Photos": "Bilder",
- "Playlists": "Spillelister",
- "Plugin": "Programvareutvidelse",
"PluginInstalledWithName": "{0} ble installert",
"PluginUninstalledWithName": "{0} ble avinstallert",
"PluginUpdatedWithName": "{0} ble oppdatert",
- "ProviderValue": "Leverandør: {0}",
"ScheduledTaskFailedWithName": "{0} mislykkes",
- "ScheduledTaskStartedWithName": "{0} startet",
- "ServerNameNeedsToBeRestarted": "{0} må startes på nytt",
"Shows": "Serier",
- "Songs": "Sanger",
"StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
"SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
- "Sync": "Synkroniser",
- "System": "System",
"TvShows": "TV-serier",
- "User": "Bruker",
"UserCreatedWithName": "Bruker {0} er opprettet",
"UserDeletedWithName": "Bruker {0} har blitt slettet",
"UserDownloadingItemWithValues": "{0} laster ned {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} har koblet fra {1}",
"UserOnlineFromDevice": "{0} er tilkoblet fra {1}",
"UserPasswordChangedWithName": "Passordet for {0} er oppdatert",
- "UserPolicyUpdatedWithName": "Brukerretningslinjene har blitt oppdatert for {0}",
"UserStartedPlayingItemWithValues": "{0} har startet avspilling {1} på {2}",
"UserStoppedPlayingItemWithValues": "{0} har stoppet avspilling {1}",
- "ValueHasBeenAddedToLibrary": "{0} har blitt lagt til i mediebiblioteket ditt",
- "ValueSpecialEpisodeName": "Spesialepisode - {0}",
"VersionNumber": "Versjon {0}",
"TasksChannelsCategory": "Internettkanaler",
"TasksApplicationCategory": "Applikasjon",
diff --git a/Emby.Server.Implementations/Localization/Core/ne.json b/Emby.Server.Implementations/Localization/Core/ne.json
index 0e52e32c1b..ad6070c4c3 100644
--- a/Emby.Server.Implementations/Localization/Core/ne.json
+++ b/Emby.Server.Implementations/Localization/Core/ne.json
@@ -21,64 +21,39 @@
"Music": "संगीत",
"Movies": "चलचित्रहरू",
"MixedContent": "मिश्रित सामग्री",
- "MessageServerConfigurationUpdated": "सर्भर कन्फिगरेसन अद्यावधिक गरिएको छ",
- "MessageNamedServerConfigurationUpdatedWithValue": "सर्भर कन्फिगरेसन विभाग {0} अद्यावधिक गरिएको छ",
- "MessageApplicationUpdatedTo": "जेलीफिन सर्भर {0} मा अद्यावधिक गरिएको छ",
- "MessageApplicationUpdated": "जेलीफिन सर्भर अपडेट गरिएको छ",
"Latest": "नविनतम",
"LabelRunningTimeValue": "कुल समय: {0}",
"LabelIpAddressValue": "आईपी ठेगाना: {0}",
- "ItemRemovedWithName": "{0}लाई पुस्तकालयबाट हटाईयो",
- "ItemAddedWithName": "{0} लाईब्रेरीमा थपियो",
"Inherit": "उत्तराधिकार",
"HomeVideos": "घरेलु भिडियोहरू",
- "HeaderRecordingGroups": "रेकर्ड समूहहरू",
"HeaderNextUp": "आगामी",
"HeaderLiveTV": "प्रत्यक्ष टिभी",
- "HeaderFavoriteSongs": "मनपर्ने गीतहरू",
"HeaderFavoriteShows": "मनपर्ने कार्यक्रमहरू",
"HeaderFavoriteEpisodes": "मनपर्ने एपिसोडहरू",
- "HeaderFavoriteArtists": "मनपर्ने कलाकारहरू",
- "HeaderFavoriteAlbums": "मनपर्ने एल्बमहरू",
"HeaderContinueWatching": "हेर्न जारी राख्नुहोस्",
- "HeaderAlbumArtists": "एल्बमका कलाकारहरू",
"Genres": "विधाहरू",
"Folders": "फोल्डरहरू",
"Favorites": "मनपर्ने",
"FailedLoginAttemptWithUserName": "असफल लग इन प्रयास {0} देखि",
- "DeviceOnlineWithName": "{0}को साथ जडित",
- "DeviceOfflineWithName": "{0}बाट विच्छेदन भयो",
"Collections": "संग्रह",
"ChapterNameValue": "अध्याय {0}",
- "Channels": "च्यानलहरू",
"AppDeviceValues": "अनुप्रयोग: {0}, उपकरण: {1}",
"AuthenticationSucceededWithUserName": "{0} सफलतापूर्वक प्रमाणीकरण गरियो",
- "CameraImageUploadedFrom": "{0}बाट नयाँ क्यामेरा छवि अपलोड गरिएको छ",
"Books": "पुस्तकहरु",
"Artists": "कलाकारहरू",
- "Application": "अनुप्रयोगहरू",
- "Albums": "एल्बमहरू",
"TasksLibraryCategory": "पुस्तकालय",
"TasksApplicationCategory": "अनुप्रयोग",
"TasksMaintenanceCategory": "मर्मत",
- "UserPolicyUpdatedWithName": "प्रयोगकर्ता नीति को लागी अद्यावधिक गरिएको छ {0}",
"UserPasswordChangedWithName": "पासवर्ड प्रयोगकर्ताका लागि परिवर्तन गरिएको छ {0}",
"UserOnlineFromDevice": "{0} बाट अनलाइन छ {1}",
"UserOfflineFromDevice": "{0} बाट विच्छेदन भएको छ {1}",
"UserLockedOutWithName": "प्रयोगकर्ता {0} लक गरिएको छ",
"UserDeletedWithName": "प्रयोगकर्ता {0} हटाइएको छ",
"UserCreatedWithName": "प्रयोगकर्ता {0} सिर्जना गरिएको छ",
- "User": "प्रयोगकर्ता",
"PluginInstalledWithName": "{0} सभएको थियो",
"StartupEmbyServerIsLoading": "Jellyfin सर्भर लोड हुँदैछ। कृपया छिट्टै फेरि प्रयास गर्नुहोस्।",
- "Songs": "गीतहरू",
"Shows": "शोहरू",
- "ServerNameNeedsToBeRestarted": "{0} लाई पुन: सुरु गर्नु पर्छ",
- "ScheduledTaskStartedWithName": "{0} सुरु भयो",
"ScheduledTaskFailedWithName": "{0} असफल",
- "ProviderValue": "प्रदायक: {0}",
- "Plugin": "प्लगइनहरू",
- "Playlists": "प्लेलिस्टहरू",
"Photos": "तस्बिरहरु",
"NotificationOptionVideoPlaybackStopped": "भिडियो प्लेब्याक रोकियो",
"NotificationOptionVideoPlayback": "भिडियो प्लेब्याक सुरु भयो",
@@ -98,15 +73,11 @@
"TaskCleanActivityLog": "गतिविधि लग सफा गर्नुहोस्",
"TasksChannelsCategory": "इन्टरनेट च्यानलहरू",
"VersionNumber": "संस्करण {0}",
- "ValueSpecialEpisodeName": "विशेष - {0}",
- "ValueHasBeenAddedToLibrary": "{0} तपाईंको मिडिया लाइब्रेरीमा थपिएको छ",
"UserStoppedPlayingItemWithValues": "{2} मा {0} हेरिसकेको छ{1}",
"UserStartedPlayingItemWithValues": "{0} हेर्दै {1} मा {2}",
"UserDownloadingItemWithValues": "{0} डाउनलोड गर्दै छ {1}",
"Undefined": "अपरिभाषित",
"TvShows": "टेलिभिजन कार्यक्रमहरू",
- "System": "प्रणाली",
- "Sync": "समकालीन",
"SubtitleDownloadFailureFromForItem": "उपशीर्षकहरू {0} बाट {1} को लागि डाउनलोड गर्न असफल",
"PluginUpdatedWithName": "{0} अद्यावधिक गरिएको थियो",
"PluginUninstalledWithName": "{0} को स्थापना रद्द गरिएको थियो",
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index de4c277ce7..898f5892c9 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -1,39 +1,23 @@
{
"AppDeviceValues": "App: {0}, Apparaat: {1}",
- "Application": "Applicatie",
"Artists": "Artiesten",
"AuthenticationSucceededWithUserName": "{0} is succesvol geauthenticeerd",
"Books": "Boeken",
- "CameraImageUploadedFrom": "Nieuwe camera-afbeelding toegevoegd vanaf {0}",
- "Channels": "Kanalen",
"ChapterNameValue": "Hoofdstuk {0}",
"Collections": "Collecties",
- "DeviceOfflineWithName": "Verbinding met {0} is verbroken",
- "DeviceOnlineWithName": "{0} is verbonden",
"FailedLoginAttemptWithUserName": "Mislukte aanmeldpoging van {0}",
"Favorites": "Favorieten",
"Folders": "Mappen",
- "HeaderAlbumArtists": "Albumartiesten",
- "HeaderContinueWatching": "Verderkijken",
- "HeaderFavoriteAlbums": "Favoriete albums",
- "HeaderFavoriteArtists": "Favoriete artiesten",
+ "HeaderContinueWatching": "Verder kijken",
"HeaderFavoriteEpisodes": "Favoriete afleveringen",
"HeaderFavoriteShows": "Favoriete series",
- "HeaderFavoriteSongs": "Favoriete nummers",
"HeaderLiveTV": "Live-tv",
"HeaderNextUp": "Volgende",
- "HeaderRecordingGroups": "Opnamegroepen",
"HomeVideos": "Homevideo's",
"Inherit": "Overnemen",
- "ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
- "ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
"LabelIpAddressValue": "IP-adres: {0}",
"LabelRunningTimeValue": "Looptijd: {0}",
"Latest": "Nieuwste",
- "MessageApplicationUpdated": "Jellyfin Server is bijgewerkt",
- "MessageApplicationUpdatedTo": "Jellyfin Server is bijgewerkt naar {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Sectie {0} van de serverconfiguratie is bijgewerkt",
- "MessageServerConfigurationUpdated": "Serverconfiguratie is bijgewerkt",
"MixedContent": "Gemengde inhoud",
"Movies": "Films",
"Music": "Muziek",
@@ -59,23 +43,14 @@
"NotificationOptionVideoPlayback": "Afspelen van video gestart",
"NotificationOptionVideoPlaybackStopped": "Afspelen van video gestopt",
"Photos": "Foto's",
- "Playlists": "Afspeellijsten",
- "Plugin": "Plug-in",
"PluginInstalledWithName": "{0} is geïnstalleerd",
"PluginUninstalledWithName": "{0} is verwijderd",
"PluginUpdatedWithName": "{0} is bijgewerkt",
- "ProviderValue": "Aanbieder: {0}",
"ScheduledTaskFailedWithName": "{0} is mislukt",
- "ScheduledTaskStartedWithName": "{0} is gestart",
- "ServerNameNeedsToBeRestarted": "{0} moet herstart worden",
"Shows": "Series",
- "Songs": "Nummers",
"StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden. Probeer het later opnieuw.",
"SubtitleDownloadFailureFromForItem": "Ondertiteling kon niet gedownload worden van {0} voor {1}",
- "Sync": "Synchronisatie",
- "System": "Systeem",
"TvShows": "Tv-series",
- "User": "Gebruiker",
"UserCreatedWithName": "Gebruiker {0} is aangemaakt",
"UserDeletedWithName": "Gebruiker {0} is verwijderd",
"UserDownloadingItemWithValues": "{0} downloadt {1}",
@@ -83,11 +58,8 @@
"UserOfflineFromDevice": "Verbinding van {0} via {1} is verbroken",
"UserOnlineFromDevice": "{0} is verbonden via {1}",
"UserPasswordChangedWithName": "Wachtwoord voor {0} is gewijzigd",
- "UserPolicyUpdatedWithName": "Gebruikersbeleid gewijzigd voor {0}",
"UserStartedPlayingItemWithValues": "{0} speelt {1} af op {2}",
"UserStoppedPlayingItemWithValues": "{0} heeft afspelen van {1} gestopt op {2}",
- "ValueHasBeenAddedToLibrary": "{0} is toegevoegd aan je mediabibliotheek",
- "ValueSpecialEpisodeName": "Special - {0}",
"VersionNumber": "Versie {0}",
"TaskDownloadMissingSubtitlesDescription": "Zoekt op het internet naar ontbrekende ondertiteling gebaseerd op metadataconfiguratie.",
"TaskDownloadMissingSubtitles": "Ontbrekende ondertiteling downloaden",
@@ -134,7 +106,7 @@
"TaskExtractMediaSegments": "Scannen op mediasegmenten",
"CleanupUserDataTaskDescription": "Wist alle gebruikersgegevens (kijkstatus, favorieten, etc.) van media die al minstens 90 dagen niet meer aanwezig zijn.",
"CleanupUserDataTask": "Opruimtaak gebruikersdata",
- "Albums": "Albums",
"Genres": "Genres",
- "Original": "Oorspronkelijk"
+ "Original": "Oorspronkelijk",
+ "LyricDownloadFailureFromForItem": "Downloaden van liedteksten voor {1} van {0} mislukt"
}
diff --git a/Emby.Server.Implementations/Localization/Core/nn.json b/Emby.Server.Implementations/Localization/Core/nn.json
index feb5fe2154..8c5da8c1de 100644
--- a/Emby.Server.Implementations/Localization/Core/nn.json
+++ b/Emby.Server.Implementations/Localization/Core/nn.json
@@ -1,41 +1,24 @@
{
- "MessageServerConfigurationUpdated": "Tenarkonfigurasjonen har blitt oppdatert",
- "MessageNamedServerConfigurationUpdatedWithValue": "Tenar konfigurasjon seksjon {0} har blitt oppdatert",
- "MessageApplicationUpdatedTo": "Jellyfin-tenaren har blitt oppdatert til {0}",
- "MessageApplicationUpdated": "Jellyfin-tenaren har blitt oppdatert",
"Latest": "Nyaste",
"LabelRunningTimeValue": "Speletid: {0}",
"LabelIpAddressValue": "IP-adresse: {0}",
- "ItemRemovedWithName": "{0} vart fjerna frå biblioteket",
- "ItemAddedWithName": "{0} vart lagt til i biblioteket",
"Inherit": "Arve",
"HomeVideos": "Heimevideoar",
- "HeaderRecordingGroups": "Innspelingsgrupper",
"HeaderNextUp": "Neste",
"HeaderLiveTV": "Direkte TV",
- "HeaderFavoriteSongs": "Favorittsongar",
"HeaderFavoriteShows": "Favorittseriar",
"HeaderFavoriteEpisodes": "Favorittepisodar",
- "HeaderFavoriteArtists": "Favorittartistar",
- "HeaderFavoriteAlbums": "Favorittalbum",
"HeaderContinueWatching": "Fortsett å sjå",
- "HeaderAlbumArtists": "Albumartist",
"Genres": "Sjangrar",
"Folders": "Mapper",
"Favorites": "Favorittar",
"FailedLoginAttemptWithUserName": "Mislukka påloggingsforsøk frå {0}",
- "DeviceOnlineWithName": "{0} er tilkopla",
- "DeviceOfflineWithName": "{0} har kopla frå",
"Collections": "Samlingar",
"ChapterNameValue": "Kapittel {0}",
- "Channels": "Kanalar",
- "CameraImageUploadedFrom": "Eit nytt kamerabilete har blitt lasta opp frå {0}",
"Books": "Bøker",
"AuthenticationSucceededWithUserName": "{0} har logga inn",
"Artists": "Artistar",
- "Application": "Program",
"AppDeviceValues": "App: {0}, Eining: {1}",
- "Albums": "Album",
"NotificationOptionServerRestartRequired": "Tenaren krev omstart",
"NotificationOptionPluginUpdateInstalled": "Programvaretilleggoppdatering vart installert",
"NotificationOptionPluginUninstalled": "Programvaretillegg avinstallert",
@@ -56,7 +39,6 @@
"Music": "Musikk",
"Movies": "Filmar",
"MixedContent": "Blanda innhald",
- "Sync": "Synkroniser",
"TaskDownloadMissingSubtitlesDescription": "Søk Internettet for manglande undertekstar basert på metadatainnstillingar.",
"TaskDownloadMissingSubtitles": "Last ned manglande undertekstar",
"TaskRefreshChannelsDescription": "Oppdater internettkanalinformasjon.",
@@ -80,11 +62,8 @@
"TasksLibraryCategory": "Bibliotek",
"TasksMaintenanceCategory": "Vedlikehald",
"VersionNumber": "Versjon {0}",
- "ValueSpecialEpisodeName": "Spesialepisode - {0}",
- "ValueHasBeenAddedToLibrary": "{0} har blitt lagt til i mediebiblioteket ditt",
"UserStoppedPlayingItemWithValues": "{0} har fullført avspeling {1} på {2}",
"UserStartedPlayingItemWithValues": "{0} spelar {1} på {2}",
- "UserPolicyUpdatedWithName": "Brukarreglar har blitt oppdatert for {0}",
"UserPasswordChangedWithName": "Passordet for {0} er oppdatert",
"UserOnlineFromDevice": "{0} er direktekopla frå {1}",
"UserOfflineFromDevice": "{0} har kopla frå {1}",
@@ -92,22 +71,14 @@
"UserDownloadingItemWithValues": "{0} lastar ned {1}",
"UserDeletedWithName": "Brukar {0} er sletta",
"UserCreatedWithName": "Brukar {0} er oppretta",
- "User": "Brukar",
"TvShows": "TV-seriar",
- "System": "System",
"SubtitleDownloadFailureFromForItem": "Feila å laste ned undertekstar frå {0} for {1}",
"StartupEmbyServerIsLoading": "Jellyfin-tenaren laster. Prøv igjen seinare.",
- "Songs": "Sangar",
"Shows": "Seriar",
- "ServerNameNeedsToBeRestarted": "{0} må omstartast",
- "ScheduledTaskStartedWithName": "{0} starta",
"ScheduledTaskFailedWithName": "{0} feila",
- "ProviderValue": "Leverandør: {0}",
"PluginUpdatedWithName": "{0} blei oppdatert",
"PluginUninstalledWithName": "{0} blei avinstallert",
"PluginInstalledWithName": "{0} blei installert",
- "Plugin": "Programvaretillegg",
- "Playlists": "Spelelister",
"Photos": "Bilete",
"NotificationOptionVideoPlaybackStopped": "Videoavspeling stoppa",
"NotificationOptionVideoPlayback": "Videoavspeling starta",
diff --git a/Emby.Server.Implementations/Localization/Core/or.json b/Emby.Server.Implementations/Localization/Core/or.json
index 8251c12907..febc98d1a4 100644
--- a/Emby.Server.Implementations/Localization/Core/or.json
+++ b/Emby.Server.Implementations/Localization/Core/or.json
@@ -1,11 +1,8 @@
{
"External": "ବହିଃସ୍ଥ",
"Genres": "ଧରଣ",
- "Albums": "ଆଲବମଗୁଡ଼ିକ",
"Artists": "କଳାକାରଗୁଡ଼ିକ",
- "Application": "ଆପ୍ଲିକେସନ",
"Books": "ବହିଗୁଡ଼ିକ",
- "Channels": "ଚ୍ୟାନେଲଗୁଡ଼ିକ",
"ChapterNameValue": "ବିଭାଗ {0}",
"Collections": "ସଂଗ୍ରହଗୁଡ଼ିକ",
"Folders": "ଫୋଲ୍ଡରଗୁଡ଼ିକ"
diff --git a/Emby.Server.Implementations/Localization/Core/pa.json b/Emby.Server.Implementations/Localization/Core/pa.json
index b00291ccb4..e609ad52c8 100644
--- a/Emby.Server.Implementations/Localization/Core/pa.json
+++ b/Emby.Server.Implementations/Localization/Core/pa.json
@@ -24,11 +24,8 @@
"TasksLibraryCategory": "ਲਾਇਬ੍ਰੇਰੀ",
"TasksMaintenanceCategory": "ਰੱਖ-ਰਖਾਅ",
"VersionNumber": "ਵਰਜਨ {0}",
- "ValueSpecialEpisodeName": "ਖਾਸ - {0}",
- "ValueHasBeenAddedToLibrary": "{0} ਤੁਹਾਡੀ ਮੀਡੀਆ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ",
"UserStoppedPlayingItemWithValues": "{0} ਨੇ {2} 'ਤੇ {1} ਖੇਡਣਾ ਪੂਰਾ ਕਰ ਲਿਆ ਹੈ",
"UserStartedPlayingItemWithValues": "{0} {2} 'ਤੇ {1} ਖੇਡ ਰਿਹਾ ਹੈ",
- "UserPolicyUpdatedWithName": "ਵਰਤੋਂਕਾਰ ਨੀਤੀ ਨੂੰ {0} ਲਈ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ ਹੈ",
"UserPasswordChangedWithName": "{0} ਵਰਤੋਂਕਾਰ ਲਈ ਪਾਸਵਰਡ ਬਦਲਿਆ ਗਿਆ ਸੀ",
"UserOnlineFromDevice": "{0} ਨੂੰ {1} ਤੋਂ ਆਨਲਾਈਨ ਹੈ",
"UserOfflineFromDevice": "{0} ਤੋਂ ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ ਹੈ {1}",
@@ -36,24 +33,15 @@
"UserDownloadingItemWithValues": "{0} {1} ਨੂੰ ਡਾਊਨਲੋਡ ਕਰ ਰਿਹਾ ਹੈ",
"UserDeletedWithName": "ਵਰਤੋਂਕਾਰ {0} ਨੂੰ ਹਟਾਇਆ ਗਿਆ",
"UserCreatedWithName": "ਵਰਤੋਂਕਾਰ {0} ਬਣਾਇਆ ਗਿਆ ਹੈ",
- "User": "ਵਰਤੋਂਕਾਰ",
"Undefined": "ਪਰਿਭਾਸ਼ਤ",
"TvShows": "ਟੀਵੀ ਸ਼ੋਅ",
- "System": "ਸਿਸਟਮ",
- "Sync": "ਸਿੰਕ",
"SubtitleDownloadFailureFromForItem": "ਉਪਸਿਰਲੇਖ {1} ਲਈ {0} ਤੋਂ ਡਾਊਨਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ",
"StartupEmbyServerIsLoading": "Jellyfin ਸਰਵਰ ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ। ਛੇਤੀ ਹੀ ਫ਼ੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
- "Songs": "ਗਾਣੇ",
"Shows": "ਸ਼ੋਅ",
- "ServerNameNeedsToBeRestarted": "{0} ਮੁੜ ਚਾਲੂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ",
- "ScheduledTaskStartedWithName": "{0} ਸ਼ੁਰੂ ਹੋਇਆ",
"ScheduledTaskFailedWithName": "{0} ਅਸਫਲ",
- "ProviderValue": "ਦੇਣ ਵਾਲੇ: {0}",
"PluginUpdatedWithName": "{0} ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ ਸੀ",
"PluginUninstalledWithName": "{0} ਅਣਇੰਸਟੌਲ ਕੀਤਾ ਗਿਆ ਸੀ",
"PluginInstalledWithName": "{0} ਲਗਾਇਆ ਗਿਆ ਸੀ",
- "Plugin": "ਪਲੱਗਇਨ",
- "Playlists": "ਪਲੇਸੂਚੀਆਂ",
"Photos": "ਫੋਟੋਆਂ",
"NotificationOptionVideoPlaybackStopped": "ਵੀਡੀਓ ਪਲੇਬੈਕ ਰੋਕਿਆ ਗਿਆ",
"NotificationOptionVideoPlayback": "ਵੀਡੀਓ ਪਲੇਬੈਕ ਸ਼ੁਰੂ ਹੋਇਆ",
@@ -79,45 +67,28 @@
"Music": "ਸੰਗੀਤ",
"Movies": "ਫਿਲਮਾਂ",
"MixedContent": "ਮਿਸ਼ਰਤ ਸਮੱਗਰੀ",
- "MessageServerConfigurationUpdated": "ਸਰਵਰ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨੂੰ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ ਹੈ",
- "MessageNamedServerConfigurationUpdatedWithValue": "ਸਰਵਰ ਕੌਂਫਿਗਰੇਸ਼ਨ ਸੈਕਸ਼ਨ {0} ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ ਹੈ",
- "MessageApplicationUpdatedTo": "ਜੈਲੀਫਿਨ ਸਰਵਰ ਨੂੰ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ ਹੈ {0}",
- "MessageApplicationUpdated": "ਜੈਲੀਫਿਨ ਸਰਵਰ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ ਹੈ",
"Latest": "ਤਾਜ਼ਾ",
"LabelRunningTimeValue": "ਚੱਲਦਾ ਸਮਾਂ: {0}",
"LabelIpAddressValue": "IP ਪਤਾ: {0}",
- "ItemRemovedWithName": "{0} ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਸੀ",
- "ItemAddedWithName": "{0} ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਸੀ",
"Inherit": "ਵਿਰਾਸਤ",
"HomeVideos": "ਘਰੇਲੂ ਵੀਡੀਓ",
- "HeaderRecordingGroups": "ਰਿਕਾਰਡਿੰਗ ਸਮੂਹ",
"HeaderNextUp": "ਅੱਗੇ",
"HeaderLiveTV": "ਲਾਈਵ ਟੀਵੀ",
- "HeaderFavoriteSongs": "ਮਨਪਸੰਦ ਗਾਣੇ",
"HeaderFavoriteShows": "ਮਨਪਸੰਦ ਸ਼ੋਅ",
"HeaderFavoriteEpisodes": "ਮਨਪਸੰਦ ਐਪੀਸੋਡ",
- "HeaderFavoriteArtists": "ਮਨਪਸੰਦ ਕਲਾਕਾਰ",
- "HeaderFavoriteAlbums": "ਮਨਪਸੰਦ ਐਲਬਮ",
"HeaderContinueWatching": "ਵੇਖਣਾ ਜਾਰੀ ਰੱਖੋ",
- "HeaderAlbumArtists": "ਐਲਬਮ ਕਲਾਕਾਰ",
"Genres": "ਸ਼ੈਲੀਆਂ",
"Forced": "ਮਜਬੂਰ",
"Folders": "ਫੋਲਡਰ",
"Favorites": "ਮਨਪਸੰਦ",
"FailedLoginAttemptWithUserName": "{0} ਤੋਂ ਲਾਗਇਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਫੇਲ ਹੋਈ",
- "DeviceOnlineWithName": "{0} ਜੁੜਿਆ ਹੋਇਆ ਹੈ",
- "DeviceOfflineWithName": "{0} ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ ਹੈ",
"Default": "ਡਿਫੌਲਟ",
"Collections": "ਸੰਗ੍ਰਹਿਣ",
"ChapterNameValue": "ਚੈਪਟਰ {0}",
- "Channels": "ਚੈਨਲ",
- "CameraImageUploadedFrom": "{0} ਤੋਂ ਇੱਕ ਨਵਾਂ ਕੈਮਰਾ ਚਿੱਤਰ ਅਪਲੋਡ ਕੀਤਾ ਗਿਆ ਹੈ",
"Books": "ਕਿਤਾਬਾਂ",
"AuthenticationSucceededWithUserName": "{0} ਸਫਲਤਾਪੂਰਕ ਪ੍ਰਮਾਣਿਤ",
"Artists": "ਕਲਾਕਾਰ",
- "Application": "ਐਪਲੀਕੇਸ਼ਨ",
"AppDeviceValues": "ਐਪ: {0}, ਜੰਤਰ: {1}",
- "Albums": "ਐਲਬਮਾਂ",
"TaskOptimizeDatabase": "ਡਾਟਾਬੇਸ ਅਨੁਕੂਲ ਬਣਾਓ",
"External": "ਬਾਹਰੀ",
"HearingImpaired": "ਸੁਨਣ ਵਿਚ ਕਮਜ਼ੋਰ",
diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json
index e5af2c7801..c4657bdd6e 100644
--- a/Emby.Server.Implementations/Localization/Core/pl.json
+++ b/Emby.Server.Implementations/Localization/Core/pl.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumy",
"AppDeviceValues": "Aplikacja: {0}, Urządzenie: {1}",
- "Application": "Aplikacja",
"Artists": "Wykonawcy",
"AuthenticationSucceededWithUserName": "{0} został pomyślnie uwierzytelniony",
"Books": "Książki",
- "CameraImageUploadedFrom": "Nowy obraz został przekazany z {0}",
- "Channels": "Kanały",
"ChapterNameValue": "Rozdział {0}",
"Collections": "Kolekcje",
- "DeviceOfflineWithName": "{0} został rozłączony",
- "DeviceOnlineWithName": "{0} połączył się",
"FailedLoginAttemptWithUserName": "Nieudana próba logowania przez {0}",
"Favorites": "Ulubione",
"Folders": "Foldery",
"Genres": "Gatunki",
- "HeaderAlbumArtists": "Wykonawcy albumów",
"HeaderContinueWatching": "Kontynuuj odtwarzanie",
- "HeaderFavoriteAlbums": "Ulubione albumy",
- "HeaderFavoriteArtists": "Ulubieni wykonawcy",
"HeaderFavoriteEpisodes": "Ulubione odcinki",
"HeaderFavoriteShows": "Ulubione seriale",
- "HeaderFavoriteSongs": "Ulubione utwory",
"HeaderLiveTV": "Telewizja",
"HeaderNextUp": "Do obejrzenia",
- "HeaderRecordingGroups": "Grupy nagrań",
"HomeVideos": "Nagrania domowe",
"Inherit": "Dziedzicz",
- "ItemAddedWithName": "{0} zostało dodane do biblioteki",
- "ItemRemovedWithName": "{0} zostało usunięte z biblioteki",
"LabelIpAddressValue": "Adres IP: {0}",
"LabelRunningTimeValue": "Czas trwania: {0}",
"Latest": "Ostatnio dodane",
- "MessageApplicationUpdated": "Serwer Jellyfin został zaktualizowany",
- "MessageApplicationUpdatedTo": "Serwer Jellyfin został zaktualizowany do wersji {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Sekcja {0} konfiguracji serwera została zaktualizowana",
- "MessageServerConfigurationUpdated": "Konfiguracja serwera została zaktualizowana",
"MixedContent": "Zawartość mieszana",
"Movies": "Filmy",
"Music": "Muzyka",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Rozpoczęto odtwarzanie wideo",
"NotificationOptionVideoPlaybackStopped": "Zatrzymano odtwarzanie wideo",
"Photos": "Zdjęcia",
- "Playlists": "Listy odtwarzania",
- "Plugin": "Wtyczka",
"PluginInstalledWithName": "{0} zostało zainstalowane",
"PluginUninstalledWithName": "{0} odinstalowane",
"PluginUpdatedWithName": "{0} zaktualizowane",
- "ProviderValue": "Dostawca: {0}",
"ScheduledTaskFailedWithName": "Nieudane {0}",
- "ScheduledTaskStartedWithName": "Rozpoczęto {0}",
- "ServerNameNeedsToBeRestarted": "{0} wymaga ponownego uruchomienia",
"Shows": "Seriale",
- "Songs": "Utwory",
"StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
"SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
- "Sync": "Synchronizacja",
- "System": "System",
"TvShows": "Seriale",
- "User": "Użytkownik",
"UserCreatedWithName": "Użytkownik {0} został utworzony",
"UserDeletedWithName": "Użytkownik {0} został usunięty",
"UserDownloadingItemWithValues": "{0} pobiera {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} z {1} został rozłączony",
"UserOnlineFromDevice": "{0} połączył się z {1}",
"UserPasswordChangedWithName": "Hasło użytkownika {0} zostało zmienione",
- "UserPolicyUpdatedWithName": "Zmieniono zasady użytkowania dla {0}",
"UserStartedPlayingItemWithValues": "{0} odtwarza {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} zakończył odtwarzanie {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} został dodany do biblioteki mediów",
- "ValueSpecialEpisodeName": "Specjalne - {0}",
"VersionNumber": "Wersja {0}",
"TaskDownloadMissingSubtitlesDescription": "Przeszukuje internet w poszukiwaniu brakujących napisów w oparciu o konfigurację metadanych.",
"TaskDownloadMissingSubtitles": "Pobierz brakujące napisy",
@@ -136,5 +107,6 @@
"TaskMoveTrickplayImagesDescription": "Przenosi istniejące pliki Trickplay zgodnie z ustawieniami biblioteki.",
"CleanupUserDataTaskDescription": "Usuwa wszystkie dane użytkownika (stan oglądanych, status ulubionych itp.) z mediów, które nie są dostępne od co najmniej 90 dni.",
"CleanupUserDataTask": "Zadanie czyszczenia danych użytkownika",
- "Original": "Oryginalny"
+ "Original": "Oryginalny",
+ "LyricDownloadFailureFromForItem": "Błąd podczas pobierania tekstu piosenki z {0} dla {1}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/pr.json b/Emby.Server.Implementations/Localization/Core/pr.json
index fee7e65f1d..912f5c876a 100644
--- a/Emby.Server.Implementations/Localization/Core/pr.json
+++ b/Emby.Server.Implementations/Localization/Core/pr.json
@@ -2,48 +2,31 @@
"Books": "Scrolls",
"AuthenticationSucceededWithUserName": "{0} passed yer trial",
"Artists": "Artistas",
- "Songs": "Shantees",
- "Albums": "Tomes",
"Photos": "Paintings",
"NotificationOptionUserLockedOut": "Crewmate sent to the brig",
"HeaderContinueWatching": "Continue Yer Journey",
"Folders": "Chests",
- "Application": "Captain",
- "DeviceOnlineWithName": "{0} joined yer crew",
- "DeviceOfflineWithName": "{0} abandoned ship",
"AppDeviceValues": "Captain: {0}, Ship: {1}",
- "CameraImageUploadedFrom": "Yer looking glass has glimpsed another painting from {0}",
"Collections": "Barrels",
- "ItemAddedWithName": "{0} is now with yer treasure",
"Default": "Normal-like",
"FailedLoginAttemptWithUserName": "Ye failed to enter from {0}",
"Favorites": "Finest Loot",
- "ItemRemovedWithName": "{0} was taken from yer treasure",
"LabelIpAddressValue": "Ship's coordinates: {0}",
"Genres": "types o' booty",
"TaskDownloadMissingSubtitlesDescription": "Scours the seven seas o' the internet for subtitles that be missin' based on the captain's map o' metadata.",
- "HeaderAlbumArtists": "Buccaneers o' the musical arts",
- "HeaderFavoriteAlbums": "Beloved booty o' musical adventures",
- "HeaderFavoriteArtists": "Treasured scallywags o' the creative seas",
- "Channels": "Channels",
"Forced": "Pressed",
"External": "Outboard",
"HeaderFavoriteEpisodes": "Treasured Tales",
"HeaderFavoriteShows": "Treasured Tales",
"ChapterNameValue": "Piece {0}",
- "HeaderFavoriteSongs": "Treasured Chimes",
"HeaderNextUp": "Incoming",
"HeaderLiveTV": "Scrying Glass",
"HearingImpaired": "Hard o' Hearing",
"LabelRunningTimeValue": "Journey duration: {0}",
- "MessageApplicationUpdated": "Yer Map of the Seas has been scribbled",
"HomeVideos": "Yer Onboard Booty",
"MixedContent": "Jumbled loot",
"Music": "Tunes",
"NameInstallFailed": "Ye couldn't bring {0} aboard yer ship",
- "MessageApplicationUpdatedTo": "Yer Map of the Seas has been scribbled with {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Yer Map Drawer has been rescribbled to {0}",
- "MessageServerConfigurationUpdated": "Yer Map drawer has been rescribbled",
"Inherit": "Carry on what be passed along",
"Latest": "Newfangled",
"Movies": "Moving pictures",
@@ -55,17 +38,13 @@
"UserOfflineFromDevice": "{0} severed ties with {1}",
"UserDownloadingItemWithValues": "{0} be haulin’ in {1}",
"UserStartedPlayingItemWithValues": "{0} be playin’ {1} aboard {2}",
- "ValueHasBeenAddedToLibrary": "{0} be stashed in yer treasure trove",
"TaskCleanCacheDescription": "Wipes away cache cargo no longer called fer.",
"TaskCleanLogsDescription": "Clears the logbook o’ entries older than {0} days.",
"TaskRefreshPeopleDescription": "Refreshes the charts fer actors an’ directors in yer Treasure Trove.",
"UserLockedOutWithName": "Matey {0} be denied boarding",
"TaskAudioNormalization": "Steadyin’ the shanties",
"TaskAudioNormalizationDescription": "Scans files fer shanty steadiyin’ data.",
- "HeaderRecordingGroups": "Loggin' Groups",
"MusicVideos": "Shanty films",
- "Playlists": "Lists o’ plunder",
- "Plugin": "Extra sail",
"NotificationOptionVideoPlaybackStopped": "Video playback dropped anchor",
"NameSeasonNumber": "Saga {0}",
"NameSeasonUnknown": "Saga be Lost",
@@ -87,23 +66,15 @@
"TaskRefreshPeople": "Freshen the Mateys",
"PluginUninstalledWithName": "{0} sent t’ Davy Jones",
"PluginUpdatedWithName": "{0} patched ‘n ready",
- "ProviderValue": "Supplier o’ goods: {0}",
- "ScheduledTaskStartedWithName": "{0} set sail",
- "ServerNameNeedsToBeRestarted": "{0} be cravin’ a restart",
"Shows": "Sagas",
"SubtitleDownloadFailureFromForItem": "Subtitles be sunk fetchin’ from {0} fer {1}",
- "Sync": "Match the tides",
- "System": "The ship’s works",
"TvShows": "TV Sagas",
"Undefined": "Uncharted",
- "User": "Matey",
"UserCreatedWithName": "Matey {0} joined the crew",
"UserDeletedWithName": "Matey {0} cast overboard",
"UserOnlineFromDevice": "{0} be aboard ship from {1}",
"UserPasswordChangedWithName": "New passphrase set fer Matey {0}",
- "UserPolicyUpdatedWithName": "Ship rules be changed fer {0}",
"UserStoppedPlayingItemWithValues": "{0} be done playin’ {1} on {2",
- "ValueSpecialEpisodeName": "Special Tale – {0}",
"VersionNumber": "Edition {0}",
"TasksMaintenanceCategory": "Hull patchin’",
"TasksLibraryCategory": "Treasure Trove",
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index 99f76c953f..9b2ef063a6 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -1,41 +1,24 @@
{
- "Albums": "Álbuns",
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
- "Application": "Aplicativo",
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
"Books": "Livros",
- "CameraImageUploadedFrom": "Uma nova imagem da câmera foi enviada de {0}",
- "Channels": "Canais",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Coleções",
- "DeviceOfflineWithName": "{0} se desconectou",
- "DeviceOnlineWithName": "{0} se conectou",
"FailedLoginAttemptWithUserName": "Falha na tentativa de login de {0}",
"Favorites": "Favoritos",
"Folders": "Pastas",
"Genres": "Gêneros",
- "HeaderAlbumArtists": "Artistas do Álbum",
"HeaderContinueWatching": "Continuar assistindo",
- "HeaderFavoriteAlbums": "Álbuns Favoritos",
- "HeaderFavoriteArtists": "Artistas favoritos",
"HeaderFavoriteEpisodes": "Episódios favoritos",
"HeaderFavoriteShows": "Séries favoritas",
- "HeaderFavoriteSongs": "Músicas favoritas",
"HeaderLiveTV": "TV ao Vivo",
"HeaderNextUp": "A Seguir",
- "HeaderRecordingGroups": "Grupos de Gravação",
"HomeVideos": "Vídeos caseiros",
"Inherit": "Herdar",
- "ItemAddedWithName": "{0} foi adicionado à biblioteca",
- "ItemRemovedWithName": "{0} foi removido da biblioteca",
"LabelIpAddressValue": "Endereço IP: {0}",
"LabelRunningTimeValue": "Tempo de execução: {0}",
"Latest": "Recentes",
- "MessageApplicationUpdated": "Servidor Jellyfin atualizado",
- "MessageApplicationUpdatedTo": "Servidor Jellyfin atualizado para {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "A seção {0} da configuração do servidor foi atualizada",
- "MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada",
"MixedContent": "Conteúdo misto",
"Movies": "Filmes",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada",
"NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada",
"Photos": "Fotos",
- "Playlists": "Listas de Reprodução",
- "Plugin": "Plugin",
"PluginInstalledWithName": "{0} foi instalado",
"PluginUninstalledWithName": "{0} foi desinstalado",
"PluginUpdatedWithName": "{0} foi atualizado",
- "ProviderValue": "Provedor: {0}",
"ScheduledTaskFailedWithName": "{0} falhou",
- "ScheduledTaskStartedWithName": "{0} iniciada",
- "ServerNameNeedsToBeRestarted": "O servidor {0} precisa ser reiniciado",
"Shows": "Séries",
- "Songs": "Músicas",
"StartupEmbyServerIsLoading": "O Servidor Jellyfin está carregando. Por favor, tente novamente mais tarde.",
"SubtitleDownloadFailureFromForItem": "Houve um problema ao baixar as legendas de {0} para {1}",
- "Sync": "Sincronizar",
- "System": "Sistema",
"TvShows": "Séries",
- "User": "Usuário",
"UserCreatedWithName": "O usuário {0} foi criado",
"UserDeletedWithName": "O usuário {0} foi excluído",
"UserDownloadingItemWithValues": "{0} está baixando {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} se desconectou de {1}",
"UserOnlineFromDevice": "{0} está online em {1}",
"UserPasswordChangedWithName": "A senha foi alterada para o usuário {0}",
- "UserPolicyUpdatedWithName": "A política de usuário foi atualizada para {0}",
"UserStartedPlayingItemWithValues": "{0} está reproduzindo {1} em {2}",
"UserStoppedPlayingItemWithValues": "{0} parou de reproduzir {1} em {2}",
- "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca de mídia",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versão {0}",
"TaskDownloadMissingSubtitlesDescription": "Procurar na internet por legendas faltando baseado na configuração de metadados.",
"TaskDownloadMissingSubtitles": "Baixar legendas que estão faltando",
diff --git a/Emby.Server.Implementations/Localization/Core/pt-PT.json b/Emby.Server.Implementations/Localization/Core/pt-PT.json
index 93dfa7e7f5..dd482d1e9b 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-PT.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-PT.json
@@ -1,41 +1,24 @@
{
- "Albums": "Álbuns",
"AppDeviceValues": "Aplicação: {0}, Dispositivo: {1}",
- "Application": "Aplicação",
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
"Books": "Livros",
- "CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
- "Channels": "Canais",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Coleções",
- "DeviceOfflineWithName": "{0} desligou-se",
- "DeviceOnlineWithName": "{0} ligou-se",
"FailedLoginAttemptWithUserName": "Tentativa de login falhada a partir de {0}",
"Favorites": "Favoritos",
"Folders": "Pastas",
"Genres": "Géneros",
- "HeaderAlbumArtists": "Artistas do álbum",
"HeaderContinueWatching": "Continuar a ver",
- "HeaderFavoriteAlbums": "Álbuns Favoritos",
- "HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",
"HeaderFavoriteShows": "Séries Favoritas",
- "HeaderFavoriteSongs": "Músicas Favoritas",
"HeaderLiveTV": "TV em Direto",
"HeaderNextUp": "A Seguir",
- "HeaderRecordingGroups": "Grupos de Gravação",
"HomeVideos": "Vídeos Caseiros",
"Inherit": "Herdar",
- "ItemAddedWithName": "{0} foi adicionado à mediateca",
- "ItemRemovedWithName": "{0} foi removido da mediateca",
"LabelIpAddressValue": "Endereço IP: {0}",
"LabelRunningTimeValue": "Duração: {0}",
"Latest": "Mais Recente",
- "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado",
- "MessageApplicationUpdatedTo": "O servidor Jellyfin foi atualizado para a versão {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Configurações de servidor na secção {0} foram atualizadas",
- "MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada",
"MixedContent": "Conteúdo Misto",
"Movies": "Filmes",
"Music": "Música",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Reprodução do vídeo iniciada",
"NotificationOptionVideoPlaybackStopped": "Reprodução do vídeo parada",
"Photos": "Fotografias",
- "Playlists": "Playlists",
- "Plugin": "Extensão",
"PluginInstalledWithName": "{0} foi instalado",
"PluginUninstalledWithName": "{0} foi desinstalado",
"PluginUpdatedWithName": "{0} foi atualizado",
- "ProviderValue": "Provider: {0}",
"ScheduledTaskFailedWithName": "{0} falhou",
- "ScheduledTaskStartedWithName": "{0} iniciou",
- "ServerNameNeedsToBeRestarted": "{0} necessita de ser reiniciado",
"Shows": "Séries",
- "Songs": "Músicas",
"StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente mais tarde.",
"SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas a partir de {0} para {1}",
- "Sync": "Sincronização",
- "System": "Sistema",
"TvShows": "Séries",
- "User": "Utilizador",
"UserCreatedWithName": "Utilizador {0} criado",
"UserDeletedWithName": "Utilizador {0} apagado",
"UserDownloadingItemWithValues": "{0} está a transferir {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} desligou-se a partir de {1}",
"UserOnlineFromDevice": "{0} ligou-se a partir de {1}",
"UserPasswordChangedWithName": "Palavra-passe alterada para o utilizador {0}",
- "UserPolicyUpdatedWithName": "Política de utilizador alterada para {0}",
"UserStartedPlayingItemWithValues": "{0} está a reproduzir {1} em {2}",
"UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}",
- "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua mediateca",
- "ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versão {0}",
"TaskDownloadMissingSubtitlesDescription": "Procurar na internet por legendas em falta baseado na configuração de metadados.",
"TaskDownloadMissingSubtitles": "Transferir legendas em falta",
diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json
index ce288223bb..15b1543d8e 100644
--- a/Emby.Server.Implementations/Localization/Core/pt.json
+++ b/Emby.Server.Implementations/Localization/Core/pt.json
@@ -3,44 +3,30 @@
"Collections": "Coleções",
"Books": "Livros",
"Artists": "Artistas",
- "Albums": "Álbuns",
"HeaderNextUp": "A Seguir",
- "HeaderFavoriteSongs": "Músicas Favoritas",
- "HeaderFavoriteArtists": "Artistas Favoritos",
- "HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",
"HeaderFavoriteShows": "Séries Favoritas",
"HeaderContinueWatching": "Continuar a ver",
- "HeaderAlbumArtists": "Artistas do Álbum",
"Genres": "Géneros",
"Folders": "Pastas",
"Favorites": "Favoritos",
- "Channels": "Canais",
"UserDownloadingItemWithValues": "{0} está sendo baixado {1}",
"VersionNumber": "Versão {0}",
- "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua mediateca",
"UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}",
"UserStartedPlayingItemWithValues": "{0} está reproduzindo {1} em {2}",
- "UserPolicyUpdatedWithName": "A política do usuário {0} foi alterada",
"UserPasswordChangedWithName": "A senha do usuário {0} foi alterada",
"UserOnlineFromDevice": "{0} está online a partir de {1}",
"UserOfflineFromDevice": "{0} desconectou-se a partir de {1}",
"UserLockedOutWithName": "O usuário {0} foi bloqueado",
"UserDeletedWithName": "O usuário {0} foi removido",
"UserCreatedWithName": "O usuário {0} foi criado",
- "User": "Usuário",
"TvShows": "Séries",
- "System": "Sistema",
"SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}",
"StartupEmbyServerIsLoading": "O servidor Jellyfin está iniciando. Tente novamente dentro de momentos.",
- "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado",
- "ScheduledTaskStartedWithName": "{0} iniciou",
"ScheduledTaskFailedWithName": "{0} falhou",
- "ProviderValue": "Fornecedor: {0}",
"PluginUpdatedWithName": "{0} foi atualizado",
"PluginUninstalledWithName": "{0} foi desinstalado",
"PluginInstalledWithName": "{0} foi instalado",
- "Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada",
"NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada",
"NotificationOptionUserLockedOut": "Usuário bloqueado",
@@ -64,32 +50,17 @@
"MusicVideos": "Videoclipes",
"Music": "Música",
"MixedContent": "Conteúdo diverso",
- "MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada",
- "MessageNamedServerConfigurationUpdatedWithValue": "As configurações do servidor na seção {0} foram atualizadas",
- "MessageApplicationUpdatedTo": "O servidor Jellyfin foi atualizado para a versão {0}",
- "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado",
"Latest": "Mais Recente",
"LabelRunningTimeValue": "Duração: {0}",
"LabelIpAddressValue": "Endereço de IP: {0}",
- "ItemRemovedWithName": "{0} foi removido da mediateca",
- "ItemAddedWithName": "{0} foi adicionado à mediateca",
"Inherit": "Herdar",
"HomeVideos": "Vídeos Caseiros",
- "HeaderRecordingGroups": "Grupos de Gravação",
- "ValueSpecialEpisodeName": "Especial - {0}",
- "Sync": "Sincronização",
- "Songs": "Músicas",
"Shows": "Séries",
- "Playlists": "Playlists",
"Photos": "Fotografias",
"Movies": "Filmes",
"FailedLoginAttemptWithUserName": "Tentativa de início de sessão falhada a partir de {0}",
- "DeviceOnlineWithName": "{0} está ligado",
- "DeviceOfflineWithName": "{0} desligou-se",
"ChapterNameValue": "Capítulo {0}",
- "CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
- "Application": "Aplicação",
"AppDeviceValues": "Aplicação: {0}, Dispositivo: {1}",
"TaskCleanCache": "Limpar Diretório de Cache",
"TasksApplicationCategory": "Aplicação",
diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json
index 30214218f8..ea83b88951 100644
--- a/Emby.Server.Implementations/Localization/Core/ro.json
+++ b/Emby.Server.Implementations/Localization/Core/ro.json
@@ -1,11 +1,8 @@
{
"HeaderNextUp": "Urmează",
"VersionNumber": "Versiunea {0}",
- "ValueSpecialEpisodeName": "Special - {0}",
- "ValueHasBeenAddedToLibrary": "{0} a fost adăugat la biblioteca multimedia",
"UserStoppedPlayingItemWithValues": "{0} a terminat rularea {1} pe {2}",
"UserStartedPlayingItemWithValues": "{0} ruleaza {1} pe {2}",
- "UserPolicyUpdatedWithName": "Politica utilizatorului {0} a fost actualizată",
"UserPasswordChangedWithName": "Parola utilizatorului {0} a fost schimbată",
"UserOnlineFromDevice": "{0} este conectat de la {1}",
"UserOfflineFromDevice": "{0} s-a deconectat de la {1}",
@@ -13,23 +10,14 @@
"UserDownloadingItemWithValues": "{0} descarcă {1}",
"UserDeletedWithName": "Utilizatorul {0} a fost șters",
"UserCreatedWithName": "Utilizatorul {0} a fost creat",
- "User": "Utilizator",
"TvShows": "Seriale TV",
- "System": "Sistem",
- "Sync": "Sincronizare",
"SubtitleDownloadFailureFromForItem": "Subtitrările nu au putut fi descărcate de la {0} pentru {1}",
"StartupEmbyServerIsLoading": "Se încarcă serverul Jellyfin. Încercați din nou în scurt timp.",
- "Songs": "Melodii",
"Shows": "Seriale",
- "ServerNameNeedsToBeRestarted": "{0} trebuie să fie repornit",
- "ScheduledTaskStartedWithName": "{0} pornit/ă",
"ScheduledTaskFailedWithName": "{0} eșuat/ă",
- "ProviderValue": "Furnizor: {0}",
"PluginUpdatedWithName": "{0} a fost actualizat/ă",
"PluginUninstalledWithName": "{0} a fost dezinstalat",
"PluginInstalledWithName": "{0} a fost instalat",
- "Plugin": "Extensie",
- "Playlists": "Liste de redare",
"Photos": "Fotografii",
"NotificationOptionVideoPlaybackStopped": "Redarea video oprită",
"NotificationOptionVideoPlayback": "Redare video începută",
@@ -55,42 +43,25 @@
"Music": "Muzică",
"Movies": "Filme",
"MixedContent": "Conținut amestecat",
- "MessageServerConfigurationUpdated": "Configurarea serverului a fost actualizată",
- "MessageNamedServerConfigurationUpdatedWithValue": "Secțiunea de configurare a serverului {0} a fost acualizata",
- "MessageApplicationUpdatedTo": "Jellyfin Server a fost actualizat la {0}",
- "MessageApplicationUpdated": "Jellyfin Server a fost actualizat",
"Latest": "Cele mai recente",
"LabelRunningTimeValue": "Durată: {0}",
"LabelIpAddressValue": "Adresa IP: {0}",
- "ItemRemovedWithName": "{0} a fost eliminat din bibliotecă",
- "ItemAddedWithName": "{0} a fost adăugat în bibliotecă",
"Inherit": "Moștenit",
"HomeVideos": "Filme personale",
- "HeaderRecordingGroups": "Grupuri de înregistrare",
"HeaderLiveTV": "TV în Direct",
- "HeaderFavoriteSongs": "Melodii Favorite",
"HeaderFavoriteShows": "Seriale TV Favorite",
"HeaderFavoriteEpisodes": "Episoade Favorite",
- "HeaderFavoriteArtists": "Artiști Favoriți",
- "HeaderFavoriteAlbums": "Albume Favorite",
"HeaderContinueWatching": "Vizionează în continuare",
- "HeaderAlbumArtists": "Artiști album",
"Genres": "Genuri",
"Folders": "Dosare",
"Favorites": "Preferate",
"FailedLoginAttemptWithUserName": "Încercare de conectare eșuată pentru {0}",
- "DeviceOnlineWithName": "{0} este conectat",
- "DeviceOfflineWithName": "{0} s-a deconectat",
"Collections": "Colecții",
"ChapterNameValue": "Capitolul {0}",
- "Channels": "Canale",
- "CameraImageUploadedFrom": "O nouă fotografie a fost încărcată din {0}",
"Books": "Cărți",
"AuthenticationSucceededWithUserName": "{0} autentificare reușită",
"Artists": "Artiști",
- "Application": "Aplicație",
"AppDeviceValues": "Aplicație: {0}, Dispozitiv: {1}",
- "Albums": "Albume",
"TaskDownloadMissingSubtitlesDescription": "Caută pe internet subtitrările lipsă pe baza configurației metadatelor.",
"TaskDownloadMissingSubtitles": "Descarcă subtitrările lipsă",
"TaskRefreshChannelsDescription": "Actualizează informațiile despre canalul de internet.",
@@ -135,5 +106,7 @@
"TaskDownloadMissingLyrics": "Descarcă versurile lipsă",
"TaskDownloadMissingLyricsDescription": "Descarcă versuri pentru melodii",
"CleanupUserDataTask": "Sarcina de curatare a datelor utilizatorului",
- "CleanupUserDataTaskDescription": "Sterge toate datele utilizatorului (starea vizionarii, starea favoritelor etc.) de pe suporturile media care nu mai sunt prezente timp de cel puțin 90 de zile."
+ "CleanupUserDataTaskDescription": "Sterge toate datele utilizatorului (starea vizionarii, starea favoritelor etc.) de pe suporturile media care nu mai sunt prezente timp de cel puțin 90 de zile.",
+ "LyricDownloadFailureFromForItem": "Versurile nu au putut fi descărcate din {0} pentru {1}",
+ "Original": "Original"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json
index c9a1c7eb87..d7eccf5f25 100644
--- a/Emby.Server.Implementations/Localization/Core/ru.json
+++ b/Emby.Server.Implementations/Localization/Core/ru.json
@@ -1,41 +1,24 @@
{
- "Albums": "Альбомы",
"AppDeviceValues": "Приложение: {0}, Устройство: {1}",
- "Application": "Приложение",
"Artists": "Исполнители",
"AuthenticationSucceededWithUserName": "{0} - авторизация успешна",
"Books": "Книги",
- "CameraImageUploadedFrom": "Новое фото загружено с камеры {0}",
- "Channels": "Каналы",
"ChapterNameValue": "Сцена {0}",
"Collections": "Коллекции",
- "DeviceOfflineWithName": "{0} - отключено",
- "DeviceOnlineWithName": "{0} - подключено",
"FailedLoginAttemptWithUserName": "Неудачная попытка входа с {0}",
"Favorites": "Избранное",
"Folders": "Папки",
"Genres": "Жанры",
- "HeaderAlbumArtists": "Исполнители альбома",
"HeaderContinueWatching": "Продолжить просмотр",
- "HeaderFavoriteAlbums": "Избранные альбомы",
- "HeaderFavoriteArtists": "Избранные исполнители",
"HeaderFavoriteEpisodes": "Избранные эпизоды",
"HeaderFavoriteShows": "Избранные сериалы",
- "HeaderFavoriteSongs": "Избранные композиции",
"HeaderLiveTV": "Эфир",
"HeaderNextUp": "Следующий",
- "HeaderRecordingGroups": "Группы записей",
"HomeVideos": "Домашние видео",
"Inherit": "Наследуемое",
- "ItemAddedWithName": "{0} - добавлено в медиатеку",
- "ItemRemovedWithName": "{0} - изъято из медиатеки",
"LabelIpAddressValue": "IP-адрес: {0}",
"LabelRunningTimeValue": "Длительность: {0}",
"Latest": "Последние",
- "MessageApplicationUpdated": "Jellyfin Server был обновлён",
- "MessageApplicationUpdatedTo": "Jellyfin Server был обновлён до {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Конфигурация сервера (раздел {0}) была обновлена",
- "MessageServerConfigurationUpdated": "Конфигурация сервера была обновлена",
"MixedContent": "Смешанное содержание",
"Movies": "Фильмы",
"Music": "Музыка",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Воспроизведение видео запущено",
"NotificationOptionVideoPlaybackStopped": "Воспроизведение видео остановлено",
"Photos": "Фото",
- "Playlists": "Плей-листы",
- "Plugin": "Плагин",
"PluginInstalledWithName": "{0} - было установлено",
"PluginUninstalledWithName": "{0} - было удалено",
"PluginUpdatedWithName": "{0} - было обновлено",
- "ProviderValue": "Поставщик: {0}",
"ScheduledTaskFailedWithName": "{0} - неудачна",
- "ScheduledTaskStartedWithName": "{0} - запущена",
- "ServerNameNeedsToBeRestarted": "Необходим перезапуск {0}",
"Shows": "Сериалы",
- "Songs": "Композиции",
"StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
"SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
- "Sync": "Синхронизация",
- "System": "Система",
"TvShows": "Телесериалы",
- "User": "Пользователь",
"UserCreatedWithName": "Пользователь {0} был создан",
"UserDeletedWithName": "Пользователь {0} был удалён",
"UserDownloadingItemWithValues": "{0} загружает {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} отключился с {1}",
"UserOnlineFromDevice": "{0} подключился с {1}",
"UserPasswordChangedWithName": "Пароль пользователя {0} был изменён",
- "UserPolicyUpdatedWithName": "Политики пользователя {0} были обновлены",
"UserStartedPlayingItemWithValues": "{0} - воспроизведение «{1}» на {2}",
"UserStoppedPlayingItemWithValues": "{0} - воспроизведение остановлено «{1}» на {2}",
- "ValueHasBeenAddedToLibrary": "{0} добавлено в медиатеку",
- "ValueSpecialEpisodeName": "Спецэпизод - {0}",
"VersionNumber": "Версия {0}",
"TaskDownloadMissingSubtitles": "Загрузка отсутствующих субтитров",
"TaskRefreshChannels": "Обновление каналов",
diff --git a/Emby.Server.Implementations/Localization/Core/sk.json b/Emby.Server.Implementations/Localization/Core/sk.json
index 184e9b0a5c..afea835bd4 100644
--- a/Emby.Server.Implementations/Localization/Core/sk.json
+++ b/Emby.Server.Implementations/Localization/Core/sk.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumy",
"AppDeviceValues": "Aplikácia: {0}, Zariadenie: {1}",
- "Application": "Aplikácia",
"Artists": "Interpreti",
"AuthenticationSucceededWithUserName": "{0} úspešne overený",
"Books": "Knihy",
- "CameraImageUploadedFrom": "Z {0} bola nahraná nová fotografia",
- "Channels": "Kanály",
"ChapterNameValue": "Kapitola {0}",
"Collections": "Kolekcie",
- "DeviceOfflineWithName": "{0} sa odpojil",
- "DeviceOnlineWithName": "{0} je pripojený",
"FailedLoginAttemptWithUserName": "Neúspešný pokus o prihlásenie z {0}",
"Favorites": "Obľúbené",
"Folders": "Priečinky",
"Genres": "Žánre",
- "HeaderAlbumArtists": "Interpreti albumu",
"HeaderContinueWatching": "Pokračovať v pozeraní",
- "HeaderFavoriteAlbums": "Obľúbené albumy",
- "HeaderFavoriteArtists": "Obľúbení interpreti",
"HeaderFavoriteEpisodes": "Obľúbené epizódy",
"HeaderFavoriteShows": "Obľúbené seriály",
- "HeaderFavoriteSongs": "Obľúbené skladby",
"HeaderLiveTV": "Živá TV",
"HeaderNextUp": "Nasleduje",
- "HeaderRecordingGroups": "Skupiny nahrávok",
"HomeVideos": "Domáce videá",
"Inherit": "Zdediť",
- "ItemAddedWithName": "{0} bol pridaný do knižnice",
- "ItemRemovedWithName": "{0} bol odstránený z knižnice",
"LabelIpAddressValue": "IP adresa: {0}",
"LabelRunningTimeValue": "Dĺžka: {0}",
"Latest": "Najnovšie",
- "MessageApplicationUpdated": "Jellyfin Server bol aktualizovaný",
- "MessageApplicationUpdatedTo": "Jellyfin Server bol aktualizovaný na verziu {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Sekcia {0} konfigurácie servera bola aktualizovaná",
- "MessageServerConfigurationUpdated": "Konfigurácia servera bola aktualizovaná",
"MixedContent": "Zmiešaný obsah",
"Movies": "Filmy",
"Music": "Hudba",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Spustené prehrávanie videa",
"NotificationOptionVideoPlaybackStopped": "Zastavené prehrávanie videa",
"Photos": "Fotky",
- "Playlists": "Playlisty",
- "Plugin": "Zásuvný modul",
"PluginInstalledWithName": "{0} bol nainštalovaný",
"PluginUninstalledWithName": "{0} bol odinštalovaný",
"PluginUpdatedWithName": "{0} bol aktualizovaný",
- "ProviderValue": "Poskytovateľ: {0}",
"ScheduledTaskFailedWithName": "{0} zlyhalo",
- "ScheduledTaskStartedWithName": "{0} zahájených",
- "ServerNameNeedsToBeRestarted": "{0} vyžaduje reštart",
"Shows": "Seriály",
- "Songs": "Skladby",
"StartupEmbyServerIsLoading": "Jellyfin Server sa spúšťa. Prosím, skúste to o chvíľu znova.",
"SubtitleDownloadFailureFromForItem": "Sťahovanie titulkov z {0} pre {1} zlyhalo",
- "Sync": "Synchronizácia",
- "System": "Systém",
"TvShows": "TV seriály",
- "User": "Používateľ",
"UserCreatedWithName": "Používateľ {0} bol vytvorený",
"UserDeletedWithName": "Používateľ {0} bol vymazaný",
"UserDownloadingItemWithValues": "{0} sťahuje {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} sa odpojil od {1}",
"UserOnlineFromDevice": "{0} je online z {1}",
"UserPasswordChangedWithName": "Heslo používateľa {0} bolo zmenené",
- "UserPolicyUpdatedWithName": "Používateľské zásady pre {0} boli aktualizované",
"UserStartedPlayingItemWithValues": "{0} spustil prehrávanie {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} ukončil prehrávanie {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} bol pridaný do vašej knižnice médií",
- "ValueSpecialEpisodeName": "Špeciál - {0}",
"VersionNumber": "Verzia {0}",
"TaskDownloadMissingSubtitlesDescription": "Vyhľadá na internete chýbajúce titulky podľa toho, ako sú nakonfigurované metadáta.",
"TaskDownloadMissingSubtitles": "Stiahnuť chýbajúce titulky",
diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json
index 35c5b4a914..8c8ed3254a 100644
--- a/Emby.Server.Implementations/Localization/Core/sl-SI.json
+++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albumi",
"AppDeviceValues": "Aplikacija: {0}, Naprava: {1}",
- "Application": "Aplikacija",
"Artists": "Izvajalci",
"AuthenticationSucceededWithUserName": "{0} se je uspešno prijavil/a",
"Books": "Knjige",
- "CameraImageUploadedFrom": "Nova fotografija je bila naložena iz {0}",
- "Channels": "Kanali",
"ChapterNameValue": "Poglavje {0}",
"Collections": "Zbirke",
- "DeviceOfflineWithName": "{0} je prekinil povezavo",
- "DeviceOnlineWithName": "{0} je povezan",
"FailedLoginAttemptWithUserName": "Neuspešen poskus prijave z {0}",
"Favorites": "Priljubljeno",
"Folders": "Mape",
"Genres": "Zvrsti",
- "HeaderAlbumArtists": "Izvajalci albuma",
"HeaderContinueWatching": "Nadaljuj ogled",
- "HeaderFavoriteAlbums": "Priljubljeni albumi",
- "HeaderFavoriteArtists": "Priljubljeni izvajalci",
"HeaderFavoriteEpisodes": "Priljubljene epizode",
"HeaderFavoriteShows": "Priljubljene serije",
- "HeaderFavoriteSongs": "Priljubljene pesmi",
"HeaderLiveTV": "TV v živo",
"HeaderNextUp": "Sledi",
- "HeaderRecordingGroups": "Zbirke posnetkov",
"HomeVideos": "Domači posnetki",
"Inherit": "Podeduj",
- "ItemAddedWithName": "{0} je dodan v knjižnico",
- "ItemRemovedWithName": "{0} je bil odstranjen iz knjižnice",
"LabelIpAddressValue": "IP naslov: {0}",
"LabelRunningTimeValue": "Čas trajanja: {0}",
"Latest": "Najnovejše",
- "MessageApplicationUpdated": "Jellyfin strežnik je bil posodobljen",
- "MessageApplicationUpdatedTo": "Jellyfin strežnik je bil posodobljen na {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Oddelek nastavitev {0} je bil posodobljen",
- "MessageServerConfigurationUpdated": "Nastavitve strežnika so bile posodobljene",
"MixedContent": "Mešane vsebine",
"Movies": "Filmi",
"Music": "Glasba",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Predvajanje videa se je začelo",
"NotificationOptionVideoPlaybackStopped": "Predvajanje videa se je ustavilo",
"Photos": "Fotografije",
- "Playlists": "Seznami predvajanja",
- "Plugin": "Dodatek",
"PluginInstalledWithName": "{0} je bil nameščen",
"PluginUninstalledWithName": "{0} je bil odstranjen",
"PluginUpdatedWithName": "{0} je bil posodobljen",
- "ProviderValue": "Ponudnik: {0}",
"ScheduledTaskFailedWithName": "{0} ni uspelo",
- "ScheduledTaskStartedWithName": "{0} začeto",
- "ServerNameNeedsToBeRestarted": "{0} mora biti ponovno zagnan",
"Shows": "Serije",
- "Songs": "Pesmi",
"StartupEmbyServerIsLoading": "Jellyfin strežnik se zaganja. Poskusite ponovno kasneje.",
"SubtitleDownloadFailureFromForItem": "Neuspešen prenos podnapisov iz {0} za {1}",
- "Sync": "Sinhroniziraj",
- "System": "Sistem",
"TvShows": "TV serije",
- "User": "Uporabnik",
"UserCreatedWithName": "Uporabnik {0} je bil ustvarjen",
"UserDeletedWithName": "Uporabnik {0} je bil izbrisan",
"UserDownloadingItemWithValues": "{0} prenaša {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} je prekinil povezavo z {1}",
"UserOnlineFromDevice": "{0} je aktiven na {1}",
"UserPasswordChangedWithName": "Geslo za uporabnika {0} je bilo spremenjeno",
- "UserPolicyUpdatedWithName": "Pravilnik uporabe je bil posodobljen za uporabnika {0}",
"UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
- "ValueSpecialEpisodeName": "Posebna epizoda - {0}",
"VersionNumber": "Različica {0}",
"TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise",
"TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.",
diff --git a/Emby.Server.Implementations/Localization/Core/sn.json b/Emby.Server.Implementations/Localization/Core/sn.json
index 74720e7646..45a459cbe1 100644
--- a/Emby.Server.Implementations/Localization/Core/sn.json
+++ b/Emby.Server.Implementations/Localization/Core/sn.json
@@ -1,28 +1,18 @@
{
- "HeaderAlbumArtists": "Vaimbi vemadambarefu",
"HeaderContinueWatching": "Simudzira kuona",
- "HeaderFavoriteSongs": "Nziyo dzaunofarira",
- "Albums": "Dambarefu",
"AppDeviceValues": "Apu: {0}, Dhivhaisi: {1}",
- "Application": "Purogiramu",
"Artists": "Vaimbi",
"AuthenticationSucceededWithUserName": "apinda",
"Books": "Mabhuku",
- "CameraImageUploadedFrom": "Mufananidzo mutsva vabva pakamera {0}",
- "Channels": "Machanewo",
"ChapterNameValue": "Chikamu {0}",
"Collections": "Akafanana",
"Default": "Zvakasarudzwa Kare",
- "DeviceOfflineWithName": "{0} haasisipo",
- "DeviceOnlineWithName": "{0} aripo",
"External": "Zvekunze",
"FailedLoginAttemptWithUserName": "Vatadza kuloga chimboedza kushandisa {0}",
"Favorites": "Zvaunofarira",
"Folders": "Mafoodha",
"Forced": "Zvekumanikidzira",
"Genres": "Mhando",
- "HeaderFavoriteAlbums": "Madambarefu aunofarira",
- "HeaderFavoriteArtists": "Vaimbi vaunofarira",
"HeaderFavoriteEpisodes": "Maepisodhi aunofarira",
"HeaderFavoriteShows": "Masirisi aunofarira"
}
diff --git a/Emby.Server.Implementations/Localization/Core/sq.json b/Emby.Server.Implementations/Localization/Core/sq.json
index 5a284e20b9..b1f76aafbb 100644
--- a/Emby.Server.Implementations/Localization/Core/sq.json
+++ b/Emby.Server.Implementations/Localization/Core/sq.json
@@ -1,5 +1,4 @@
{
- "MessageApplicationUpdatedTo": "Serveri Jellyfin u përditesua në versionin {0}",
"Inherit": "Trashgimi",
"TaskDownloadMissingSubtitlesDescription": "Kërkon në internet për titra që mungojnë bazuar tek konfigurimi i metadata-ve.",
"TaskDownloadMissingSubtitles": "Shkarko titra që mungojnë",
@@ -24,11 +23,8 @@
"TasksLibraryCategory": "Libraria",
"TasksMaintenanceCategory": "Mirëmbajtje",
"VersionNumber": "Versioni {0}",
- "ValueSpecialEpisodeName": "Speciale - {0}",
- "ValueHasBeenAddedToLibrary": "{0} u shtua tek libraria juaj",
"UserStoppedPlayingItemWithValues": "{0} mbaroi së shikuari {1} tek {2}",
"UserStartedPlayingItemWithValues": "{0} po shikon {1} tek {2}",
- "UserPolicyUpdatedWithName": "Politika e përdoruesit u përditësua për {0}",
"UserPasswordChangedWithName": "Fjalëkalimi u ndryshua për përdoruesin {0}",
"UserOnlineFromDevice": "{0} është në linjë nga {1}",
"UserOfflineFromDevice": "{0} u shkëput nga {1}",
@@ -36,23 +32,14 @@
"UserDownloadingItemWithValues": "{0} po shkarkon {1}",
"UserDeletedWithName": "Përdoruesi {0} u fshi",
"UserCreatedWithName": "Përdoruesi {0} u krijua",
- "User": "Përdoruesi",
"TvShows": "Seriale TV",
- "System": "Sistemi",
- "Sync": "Sinkronizo",
"SubtitleDownloadFailureFromForItem": "Titrat deshtuan të shkarkohen nga {0} për {1}",
"StartupEmbyServerIsLoading": "Serveri Jellyfin po ngarkohet. Ju lutemi provoni përseri pas pak.",
- "Songs": "Këngët",
"Shows": "Serialet",
- "ServerNameNeedsToBeRestarted": "{0} duhet të ristartoj",
- "ScheduledTaskStartedWithName": "{0} filloi",
"ScheduledTaskFailedWithName": "{0} dështoi",
- "ProviderValue": "Ofruesi: {0}",
"PluginUpdatedWithName": "{0} u përditësua",
"PluginUninstalledWithName": "{0} u çinstalua",
"PluginInstalledWithName": "{0} u instalua",
- "Plugin": "Plugin",
- "Playlists": "Listat për luajtje",
"Photos": "Fotografitë",
"NotificationOptionVideoPlaybackStopped": "Luajtja e videos ndaloi",
"NotificationOptionVideoPlayback": "Luajtja e videos filloi",
@@ -78,41 +65,25 @@
"Music": "Muzikë",
"Movies": "Filmat",
"MixedContent": "Përmbajtje e përzier",
- "MessageServerConfigurationUpdated": "Konfigurimet e serverit u përditësuan",
- "MessageNamedServerConfigurationUpdatedWithValue": "Seksioni i konfigurimit të serverit {0} u përditësua",
- "MessageApplicationUpdated": "Serveri Jellyfin u përditësua",
"Latest": "Të fundit",
"LabelRunningTimeValue": "Kohëzgjatja: {0}",
"LabelIpAddressValue": "Adresa IP: {0}",
- "ItemRemovedWithName": "{0} u fshi nga libraria",
- "ItemAddedWithName": "{0} u shtua tek libraria",
"HomeVideos": "Video personale",
- "HeaderRecordingGroups": "Grupet e regjistrimit",
"HeaderNextUp": "Në vazhdim",
"HeaderLiveTV": "TV Live",
- "HeaderFavoriteSongs": "Kënget e preferuara",
"HeaderFavoriteShows": "Serialet e preferuar",
"HeaderFavoriteEpisodes": "Episodet e preferuar",
- "HeaderFavoriteArtists": "Artistët e preferuar",
- "HeaderFavoriteAlbums": "Albumet e preferuar",
"HeaderContinueWatching": "Vazhdo të shikosh",
- "HeaderAlbumArtists": "Artistët e albumeve",
"Genres": "Zhanret",
"Folders": "Skedarët",
"Favorites": "Të preferuarat",
"FailedLoginAttemptWithUserName": "Përpjekja për hyrje dështoi nga {0}",
- "DeviceOnlineWithName": "{0} u lidh",
- "DeviceOfflineWithName": "{0} u shkëput",
"Collections": "Koleksionet",
"ChapterNameValue": "Kapituj",
- "Channels": "Kanalet",
- "CameraImageUploadedFrom": "Një foto e re nga kamera u ngarkua nga {0}",
"Books": "Librat",
"AuthenticationSucceededWithUserName": "{0} u identifikua me sukses",
"Artists": "Artistët",
- "Application": "Aplikacioni",
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
- "Albums": "Albumet",
"TaskCleanActivityLogDescription": "Pastro të dhënat mbi aktivitetin më të vjetra sesa koha e përcaktuar.",
"TaskCleanActivityLog": "Pastro të dhënat mbi aktivitetin",
"Undefined": "I papërcaktuar",
diff --git a/Emby.Server.Implementations/Localization/Core/sr.json b/Emby.Server.Implementations/Localization/Core/sr.json
index 52f4124657..56806e25c1 100644
--- a/Emby.Server.Implementations/Localization/Core/sr.json
+++ b/Emby.Server.Implementations/Localization/Core/sr.json
@@ -1,9 +1,6 @@
{
- "UserPolicyUpdatedWithName": "Корисничке смернице ажуриране за {0}",
"NotificationOptionUserLockedOut": "Корисник закључан",
"VersionNumber": "Верзија {0}",
- "ValueSpecialEpisodeName": "Специјал - {0}",
- "ValueHasBeenAddedToLibrary": "{0} је додато у вашу медијску библиотеку",
"UserStoppedPlayingItemWithValues": "{0} завршио пуштање {1} на {2}",
"UserStartedPlayingItemWithValues": "{0} пушта {1} на {2}",
"UserPasswordChangedWithName": "Лозинка је промењена за корисника {0}",
@@ -13,23 +10,14 @@
"UserDownloadingItemWithValues": "{0} преузима {1}",
"UserDeletedWithName": "Корисник {0} је обрисан",
"UserCreatedWithName": "Корисник {0} је направљен",
- "User": "Корисник",
"TvShows": "ТВ серије",
- "System": "Систем",
- "Sync": "Усклади",
"SubtitleDownloadFailureFromForItem": "Неуспело преузимање титлова за {1} са {0}",
"StartupEmbyServerIsLoading": "Џелифин сервер се подиже. Покушајте поново убрзо.",
- "Songs": "Песме",
"Shows": "Серије",
- "ServerNameNeedsToBeRestarted": "{0} треба поново покренути",
- "ScheduledTaskStartedWithName": "{0} покренуто",
"ScheduledTaskFailedWithName": "{0} неуспело",
- "ProviderValue": "Пружалац: {0}",
"PluginUpdatedWithName": "{0} ажуриран",
"PluginUninstalledWithName": "{0} деинсталиран",
"PluginInstalledWithName": "{0} инсталиран",
- "Plugin": "Прикључак",
- "Playlists": "Листе",
"Photos": "Фотографије",
"NotificationOptionVideoPlaybackStopped": "Заустављено пуштање видеа",
"NotificationOptionVideoPlayback": "Покренуто пуштање видеа",
@@ -54,43 +42,26 @@
"Music": "Музика",
"Movies": "Филмови",
"MixedContent": "Мешовит садржај",
- "MessageServerConfigurationUpdated": "Серверска поставка је ажурирана",
- "MessageNamedServerConfigurationUpdatedWithValue": "Одељак серверске поставке {0} је ажуриран",
- "MessageApplicationUpdatedTo": "Џелифин сервер је ажуриран на {0}",
- "MessageApplicationUpdated": "Џелифин сервер је ажуриран",
"Latest": "Последње",
"LabelRunningTimeValue": "Време рада: {0}",
"LabelIpAddressValue": "ИП адреса: {0}",
- "ItemRemovedWithName": "{0} уклоњено из библиотеке",
- "ItemAddedWithName": "{0} додато у библиотеку",
"Inherit": "Наследи",
"HomeVideos": "Кућни Видео",
- "HeaderRecordingGroups": "Групе снимања",
"HeaderNextUp": "Следи",
"HeaderLiveTV": "ТВ уживо",
- "HeaderFavoriteSongs": "Омиљене песме",
"HeaderFavoriteShows": "Омиљене серије",
"HeaderFavoriteEpisodes": "Омиљене епизоде",
- "HeaderFavoriteArtists": "Омиљени извођачи",
- "HeaderFavoriteAlbums": "Омиљени албуми",
"HeaderContinueWatching": "Настави гледање",
- "HeaderAlbumArtists": "Извођачи албума",
"Genres": "Жанрови",
"Folders": "Фасцикле",
"Favorites": "Омиљено",
"FailedLoginAttemptWithUserName": "Неуспели покушај пријавe са {0}",
- "DeviceOnlineWithName": "{0} је повезан",
- "DeviceOfflineWithName": "{0} је прекинуо везу",
"Collections": "Колекције",
"ChapterNameValue": "Поглавље {0}",
- "Channels": "Канали",
- "CameraImageUploadedFrom": "Нова фотографија је учитана са {0}",
"Books": "Књиге",
"AuthenticationSucceededWithUserName": "{0} Успешна аутентификација",
"Artists": "Извођачи",
- "Application": "Апликација",
"AppDeviceValues": "Апликација: {0}, Уређај: {1}",
- "Albums": "Албуми",
"TaskDownloadMissingSubtitlesDescription": "Претражује интернет за недостајуће титлове на основу конфигурације метаподатака.",
"TaskDownloadMissingSubtitles": "Преузмите недостајуће титлове",
"TaskRefreshChannelsDescription": "Освежава информације о интернет каналу.",
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index 015f59af25..af3fbbaded 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -1,41 +1,24 @@
{
- "Albums": "Album",
"AppDeviceValues": "Applikation: {0}, Enhet: {1}",
- "Application": "Applikation",
"Artists": "Artister",
"AuthenticationSucceededWithUserName": "{0} har autentiserats",
"Books": "Böcker",
- "CameraImageUploadedFrom": "En ny kamerabild har laddats upp från {0}",
- "Channels": "Kanaler",
"ChapterNameValue": "Kapitel {0}",
"Collections": "Samlingar",
- "DeviceOfflineWithName": "{0} har kopplat ned",
- "DeviceOnlineWithName": "{0} är ansluten",
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
"Favorites": "Favoriter",
"Folders": "Mappar",
"Genres": "Genrer",
- "HeaderAlbumArtists": "Albumartister",
"HeaderContinueWatching": "Fortsätt titta",
- "HeaderFavoriteAlbums": "Favoritalbum",
- "HeaderFavoriteArtists": "Favoritartister",
"HeaderFavoriteEpisodes": "Favoritavsnitt",
"HeaderFavoriteShows": "Favoritserier",
- "HeaderFavoriteSongs": "Favoritlåtar",
"HeaderLiveTV": "Direktsänd TV",
"HeaderNextUp": "Nästa",
- "HeaderRecordingGroups": "Inspelningsgrupper",
"HomeVideos": "Hemmavideor",
"Inherit": "Ärv",
- "ItemAddedWithName": "{0} lades till i biblioteket",
- "ItemRemovedWithName": "{0} togs bort från biblioteket",
"LabelIpAddressValue": "IP-adress: {0}",
"LabelRunningTimeValue": "Speltid: {0}",
"Latest": "Senaste",
- "MessageApplicationUpdated": "Jellyfin Server har uppdaterats",
- "MessageApplicationUpdatedTo": "Jellyfin Server har uppdaterats till {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serverinställningarna {0} har uppdaterats",
- "MessageServerConfigurationUpdated": "Serverkonfigurationen har uppdaterats",
"MixedContent": "Blandat innehåll",
"Movies": "Filmer",
"Music": "Musik",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Videouppspelning har påbörjats",
"NotificationOptionVideoPlaybackStopped": "Videouppspelning stoppades",
"Photos": "Bilder",
- "Playlists": "Spellistor",
- "Plugin": "Tillägg",
"PluginInstalledWithName": "{0} installerades",
"PluginUninstalledWithName": "{0} avinstallerades",
"PluginUpdatedWithName": "{0} uppdaterades",
- "ProviderValue": "Leverantör: {0}",
"ScheduledTaskFailedWithName": "{0} misslyckades",
- "ScheduledTaskStartedWithName": "{0} startades",
- "ServerNameNeedsToBeRestarted": "{0} behöver startas om",
"Shows": "Serier",
- "Songs": "Låtar",
"StartupEmbyServerIsLoading": "Jellyfin Server arbetar. Pröva igen snart.",
"SubtitleDownloadFailureFromForItem": "Undertexter kunde inte laddas ner från {0} till {1}",
- "Sync": "Synk",
- "System": "System",
"TvShows": "Tv-serier",
- "User": "Användare",
"UserCreatedWithName": "Användaren {0} har skapats",
"UserDeletedWithName": "Användaren {0} har tagits bort",
"UserDownloadingItemWithValues": "{0} laddar ner {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} har kopplat ned från {1}",
"UserOnlineFromDevice": "{0} är uppkopplad från {1}",
"UserPasswordChangedWithName": "Lösenordet för {0} har ändrats",
- "UserPolicyUpdatedWithName": "Användarpolicyn har uppdaterats för {0}",
"UserStartedPlayingItemWithValues": "{0} spelar {1} på {2}",
"UserStoppedPlayingItemWithValues": "{0} har stoppat uppspelningen av {1} på {2}",
- "ValueHasBeenAddedToLibrary": "{0} har lagts till i ditt mediebibliotek",
- "ValueSpecialEpisodeName": "Specialavsnitt - {0}",
"VersionNumber": "Version {0}",
"TaskDownloadMissingSubtitlesDescription": "Söker på internet efter saknade undertexter baserat på metadata-konfiguration.",
"TaskDownloadMissingSubtitles": "Ladda ner saknade undertexter",
diff --git a/Emby.Server.Implementations/Localization/Core/ta.json b/Emby.Server.Implementations/Localization/Core/ta.json
index b68af92033..f613b973db 100644
--- a/Emby.Server.Implementations/Localization/Core/ta.json
+++ b/Emby.Server.Implementations/Localization/Core/ta.json
@@ -1,13 +1,11 @@
{
"VersionNumber": "பதிப்பு {0}",
- "ValueSpecialEpisodeName": "சிறப்பு - {0}",
"TasksMaintenanceCategory": "பராமரிப்பு",
"TaskCleanCache": "தற்காலிக சேமிப்பு கோப்பகத்தை சுத்தம் செய்யவும்",
"TaskRefreshChapterImages": "அத்தியாயப் படங்களை பிரித்தெடுக்கவும்",
"TaskRefreshPeople": "மக்களைப் புதுப்பிக்கவும்",
"TaskCleanTranscode": "டிரான்ஸ்கோட் கோப்பகத்தை சுத்தம் செய்யவும்",
"TaskRefreshChannelsDescription": "இணையச் சேனல் தகவல்களைப் புதுப்பிக்கிறது.",
- "System": "ஒருங்கியம்",
"NotificationOptionTaskFailed": "திட்டமிடப்பட்ட பணி தோல்வியடைந்தது",
"NotificationOptionPluginUpdateInstalled": "உட்செருகி புதுப்பிக்கப்பட்டது",
"NotificationOptionPluginUninstalled": "உட்செருகி நீக்கப்பட்டது",
@@ -15,17 +13,10 @@
"NotificationOptionPluginError": "உட்செருகி செயலிழந்தது",
"NotificationOptionCameraImageUploaded": "புகைப்படம் பதிவேற்றப்பட்டது",
"MixedContent": "கலப்பு உள்ளடக்கங்கள்",
- "MessageServerConfigurationUpdated": "சேவையக அமைப்புகள் புதுப்பிக்கப்பட்டன",
- "MessageApplicationUpdatedTo": "ஜெல்லிஃபின் சேவையகம் {0} இற்கு புதுப்பிக்கப்பட்டது",
- "MessageApplicationUpdated": "ஜெல்லிஃபின் சேவையகம் புதுப்பிக்கப்பட்டது",
"Inherit": "மரபுரிமையாகப் பெறு",
- "HeaderRecordingGroups": "பதிவு குழுக்கள்",
"Folders": "கோப்புறைகள்",
"FailedLoginAttemptWithUserName": "{0} இலிருந்து உள்நுழைவு முயற்சி தோல்வியடைந்தது",
- "DeviceOnlineWithName": "{0} இணைக்கப்பட்டது",
- "DeviceOfflineWithName": "{0} துண்டிக்கப்பட்டது",
"Collections": "தொகுப்புகள்",
- "CameraImageUploadedFrom": "{0} இல் இருந்து புதிய புகைப்படம் பதிவேற்றப்பட்டது",
"AppDeviceValues": "செயலி: {0}, சாதனம்: {1}",
"TaskDownloadMissingSubtitles": "விடுபட்டுபோன வசன வரிகளைப் பதிவிறக்கு",
"TaskRefreshChannels": "சேனல்களை புதுப்பி",
@@ -34,27 +25,18 @@
"TasksChannelsCategory": "இணைய சேனல்கள்",
"TasksApplicationCategory": "செயலி",
"TasksLibraryCategory": "நூலகம்",
- "UserPolicyUpdatedWithName": "பயனர் கொள்கை {0} இற்கு புதுப்பிக்கப்பட்டுள்ளது",
"UserPasswordChangedWithName": "{0} பயனருக்கு கடவுச்சொல் மாற்றப்பட்டுள்ளது",
"UserLockedOutWithName": "பயனர் {0} முடக்கப்பட்டார்",
"UserDownloadingItemWithValues": "{0} ஆல் {1} பதிவிறக்கப்படுகிறது",
"UserDeletedWithName": "பயனர் {0} நீக்கப்பட்டார்",
"UserCreatedWithName": "பயனர் {0} உருவாக்கப்பட்டார்",
- "User": "பயனர்",
"TvShows": "தொலைக்காட்சித் தொடர்கள்",
- "Sync": "ஒத்திசைவு",
"StartupEmbyServerIsLoading": "ஜெல்லிஃபின் சேவையகம் துவங்குகிறது. சிறிது நேரம் கழித்து முயற்சிக்கவும்.",
- "Songs": "பாடல்கள்",
"Shows": "நிகழ்ச்சிகள்",
- "ServerNameNeedsToBeRestarted": "{0} மறுதொடக்கம் செய்யப்பட வேண்டும்",
- "ScheduledTaskStartedWithName": "{0} துவங்கியது",
"ScheduledTaskFailedWithName": "{0} தோல்வியடைந்தது",
- "ProviderValue": "வழங்குநர்: {0}",
"PluginUpdatedWithName": "{0} புதுப்பிக்கப்பட்டது",
"PluginUninstalledWithName": "{0} நீக்கப்பட்டது",
"PluginInstalledWithName": "{0} நிறுவப்பட்டது",
- "Plugin": "உட்செருகி",
- "Playlists": "தொடர் பட்டியல்கள்",
"Photos": "புகைப்படங்கள்",
"NotificationOptionVideoPlaybackStopped": "நிகழ்பட ஒளிபரப்பு நிறுத்தப்பட்டது",
"NotificationOptionVideoPlayback": "நிகழ்பட ஒளிபரப்பு துவங்கியது",
@@ -75,28 +57,18 @@
"Latest": "புதியவை",
"LabelRunningTimeValue": "ஓடும் நேரம்: {0}",
"LabelIpAddressValue": "ஐபி முகவரி: {0}",
- "ItemRemovedWithName": "{0} நூலகத்திலிருந்து அகற்றப்பட்டது",
- "ItemAddedWithName": "{0} நூலகத்தில் சேர்க்கப்பட்டது",
"HeaderNextUp": "அடுத்தது",
"HeaderLiveTV": "நேரடித் தொலைக்காட்சி",
- "HeaderFavoriteSongs": "பிடித்த பாடல்கள்",
"HeaderFavoriteShows": "பிடித்த தொடர்கள்",
"HeaderFavoriteEpisodes": "பிடித்த அத்தியாயங்கள்",
- "HeaderFavoriteArtists": "பிடித்த கலைஞர்கள்",
- "HeaderFavoriteAlbums": "பிடித்த ஆல்பங்கள்",
"HeaderContinueWatching": "தொடர்ந்து பார்",
- "HeaderAlbumArtists": "கலைஞரின் ஆல்பம்",
"Genres": "வகைகள்",
"Favorites": "பிடித்தவை",
"ChapterNameValue": "அத்தியாயம் {0}",
- "Channels": "சேனல்கள்",
"Books": "புத்தகங்கள்",
"AuthenticationSucceededWithUserName": "{0} வெற்றிகரமாக அங்கீகரிக்கப்பட்டது",
"Artists": "கலைஞர்கள்",
- "Application": "செயலி",
- "Albums": "ஆல்பங்கள்",
"NewVersionIsAvailable": "ஜெல்லிஃபின் சேவையகத்தின் புதிய பதிப்பு பதிவிறக்கத்திற்கு கிடைக்கிறது.",
- "MessageNamedServerConfigurationUpdatedWithValue": "சேவையக உள்ளமைவு பிரிவு {0} புதுப்பிக்கப்பட்டது",
"TaskCleanCacheDescription": "கணினிக்கு இனி தேவைப்படாத தற்காலிக கோப்புகளை நீக்கு.",
"UserOfflineFromDevice": "{0} இலிருந்து {1} துண்டிக்கப்பட்டுள்ளது",
"SubtitleDownloadFailureFromForItem": "வசன வரிகள் {0} இல் இருந்து {1} க்கு பதிவிறக்கத் தவறிவிட்டன",
@@ -108,7 +80,6 @@
"TaskCleanLogs": "பதிவு அடைவை சுத்தம் செய்யுங்கள்",
"TaskRefreshLibraryDescription": "புதிய கோப்புகளுக்காக உங்கள் ஊடக நூலகத்தை ஆராய்ந்து மீத்தரவை புதுப்பிக்கும்.",
"TaskRefreshChapterImagesDescription": "அத்தியாயங்களைக் கொண்ட வீடியோக்களுக்கான சிறு உருவங்களை உருவாக்குகிறது.",
- "ValueHasBeenAddedToLibrary": "உங்கள் மீடியா நூலகத்தில் {0} சேர்க்கப்பட்டது",
"UserOnlineFromDevice": "{1} இருந்து {0} ஆன்லைன்",
"HomeVideos": "முகப்பு வீடியோக்கள்",
"UserStoppedPlayingItemWithValues": "{0} {2} இல் {1} முடித்துவிட்டது",
diff --git a/Emby.Server.Implementations/Localization/Core/te.json b/Emby.Server.Implementations/Localization/Core/te.json
index ca9e345214..7ac770752e 100644
--- a/Emby.Server.Implementations/Localization/Core/te.json
+++ b/Emby.Server.Implementations/Localization/Core/te.json
@@ -1,51 +1,31 @@
{
- "ValueSpecialEpisodeName": "ప్రత్యేక - {0}",
- "Sync": "సమకాలీకరించు",
- "Songs": "పాటలు",
"Shows": "ప్రదర్శనలు",
- "Playlists": "ప్లేజాబితాలు",
"Photos": "ఫోటోలు",
"MusicVideos": "మ్యూజిక్ వీడియోలు",
"Music": "సంగీతం",
"Movies": "సినిమాలు",
"HeaderContinueWatching": "చూడటం కొనసాగించండి",
- "HeaderAlbumArtists": "ఆల్బమ్ కళాకారులు",
"Genres": "శైలులు",
"Forced": "బలవంతంగా",
"Folders": "ఫోల్డర్లు",
"Favorites": "ఇష్టమైనవి",
"Default": "డిఫాల్ట్",
"Collections": "సేకరణలు",
- "Channels": "ఛానెల్‌లు",
"Books": "పుస్తకాలు",
"Artists": "కళాకారులు",
- "Albums": "ఆల్బమ్‌లు",
"HearingImpaired": "వినికిడి లోపం",
"HomeVideos": "హోమ్ వీడియోలు",
"AppDeviceValues": "అప్లికేషన్ : {0}, పరికరం: {1}",
- "Application": "అప్లికేషన్",
"AuthenticationSucceededWithUserName": "విజయవంతంగా ఆమోదించబడింది",
- "CameraImageUploadedFrom": "{0} నుండి కొత్త కెమెరా చిత్రం అప్‌లోడ్ చేయబడింది",
"ChapterNameValue": "అధ్యాయం",
- "DeviceOfflineWithName": "{0} డిస్‌కనెక్ట్ చేయబడింది",
- "DeviceOnlineWithName": "{0} కనెక్ట్ చేయబడింది",
"External": "బాహ్య",
"FailedLoginAttemptWithUserName": "{0} నుండి విఫలమైన లాగిన్ ప్రయత్నం",
- "HeaderFavoriteAlbums": "ఇష్టమైన ఆల్బమ్‌లు",
- "HeaderFavoriteArtists": "ఇష్టమైన కళాకారులు",
"HeaderFavoriteEpisodes": "ఇష్టమైన ఎపిసోడ్‌లు",
"HeaderFavoriteShows": "ఇష్టమైన ప్రదర్శనలు",
- "HeaderFavoriteSongs": "ఇష్టమైన పాటలు",
"HeaderLiveTV": "ప్రత్యక్ష TV",
"HeaderNextUp": "తదుపరి",
- "HeaderRecordingGroups": "రికార్డింగ్ గుంపులు",
- "MessageApplicationUpdated": "జెల్లీఫిన్ సర్వర్ అప్‌డేట్ చేయడం పూర్తి అయ్యింది",
- "MessageApplicationUpdatedTo": "జెల్లీఫిన్ సర్వర్ {0} వెర్షన్ కి అప్‌డేట్ చెయ్యబడింది",
- "MessageServerConfigurationUpdated": "సర్వర్ కన్ఫిగరేషన్ అప్డేట్ చేయబడింది",
"NewVersionIsAvailable": "జెల్లీఫిన్ సర్వర్ యొక్క కొత్త వెర్షన్ డౌన్‌లోడ్ చేసుకోవడానికి అందుబాటులో ఉంది.",
"NotificationOptionApplicationUpdateInstalled": "అప్లికేషన్ అప్‌డేట్ ఇన్‌స్టాల్ చేయబడింది",
- "ItemAddedWithName": "{0} లైబ్రరీకి జోడించబడింది",
- "ItemRemovedWithName": "లైబ్రరీ నుండి {0} తీసివేయబడింది",
"LabelIpAddressValue": "ఐపీ చిరునామా: {0}",
"LabelRunningTimeValue": "నడుస్తున్న సమయం: {0}",
"Latest": "తాజా",
diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json
index f0a62646f7..89c2c26748 100644
--- a/Emby.Server.Implementations/Localization/Core/th.json
+++ b/Emby.Server.Implementations/Localization/Core/th.json
@@ -1,10 +1,7 @@
{
- "ProviderValue": "ผู้ให้บริการ: {0}",
"PluginUpdatedWithName": "อัปเดต {0} แล้ว",
"PluginUninstalledWithName": "ถอนการติดตั้ง {0} แล้ว",
"PluginInstalledWithName": "ติดตั้ง {0} แล้ว",
- "Plugin": "ปลั๊กอิน",
- "Playlists": "เพลย์ลิสต์",
"Photos": "รูปภาพ",
"NotificationOptionVideoPlaybackStopped": "หยุดเล่นวิดีโอ",
"NotificationOptionVideoPlayback": "เริ่มเล่นวิดีโอ",
@@ -30,48 +27,28 @@
"Music": "ดนตรี",
"Movies": "ภาพยนตร์",
"MixedContent": "เนื้อหาผสม",
- "MessageServerConfigurationUpdated": "อัปเดตการกำหนดค่าเซิร์ฟเวอร์แล้ว",
- "MessageNamedServerConfigurationUpdatedWithValue": "อัปเดตการกำหนดค่าเซิร์ฟเวอร์ในส่วน {0} แล้ว",
- "MessageApplicationUpdatedTo": "เซิร์ฟเวอร์ Jellyfin ได้รับการอัปเดตเป็น {0}",
- "MessageApplicationUpdated": "อัพเดตเซิร์ฟเวอร์ Jellyfin แล้ว",
"Latest": "ล่าสุด",
"LabelRunningTimeValue": "ผ่านไปแล้ว: {0}",
"LabelIpAddressValue": "ที่อยู่ IP: {0}",
- "ItemRemovedWithName": "{0} ถูกลบออกจากไลบรารี",
- "ItemAddedWithName": "{0} ถูกเพิ่มลงในไลบรารีแล้ว",
"Inherit": "สืบทอด",
"HomeVideos": "โฮมวิดีโอ",
- "HeaderRecordingGroups": "กลุ่มการบันทึก",
"HeaderNextUp": "ถัดไป",
"HeaderLiveTV": "ทีวีสด",
- "HeaderFavoriteSongs": "เพลงที่ชื่นชอบ",
"HeaderFavoriteShows": "รายการที่ชื่นชอบ",
"HeaderFavoriteEpisodes": "ตอนที่ชื่นชอบ",
- "HeaderFavoriteArtists": "ศิลปินที่ชื่นชอบ",
- "HeaderFavoriteAlbums": "อัมบั้มที่ชื่นชอบ",
"HeaderContinueWatching": "ดูต่อ",
- "HeaderAlbumArtists": "ศิลปินอัลบั้ม",
"Genres": "ประเภท",
"Folders": "โฟลเดอร์",
"Favorites": "รายการโปรด",
"FailedLoginAttemptWithUserName": "ความพยายามในการเข้าสู่ระบบล้มเหลวจาก {0}",
- "DeviceOnlineWithName": "{0} เชื่อมต่อสำเร็จแล้ว",
- "DeviceOfflineWithName": "{0} ยกเลิกการเชื่อมต่อแล้ว",
"Collections": "คอลเลกชัน",
"ChapterNameValue": "บทที่ {0}",
- "Channels": "ช่อง",
- "CameraImageUploadedFrom": "ภาพถ่ายใหม่ได้ถูกอัปโหลดมาจาก {0}",
"Books": "หนังสือ",
"AuthenticationSucceededWithUserName": "{0} ยืนยันตัวตนสำเร็จแล้ว",
"Artists": "ศิลปิน",
- "Application": "แอปพลิเคชัน",
"AppDeviceValues": "แอป: {0}, อุปกรณ์: {1}",
- "Albums": "อัลบั้ม",
- "ScheduledTaskStartedWithName": "{0} เริ่มต้น",
"ScheduledTaskFailedWithName": "{0} ล้มเหลว",
- "Songs": "เพลง",
"Shows": "รายการ",
- "ServerNameNeedsToBeRestarted": "{0} ต้องการการรีสตาร์ท",
"TaskDownloadMissingSubtitlesDescription": "ค้นหาคำบรรยายที่หายไปในอินเทอร์เน็ตตามค่ากำหนดในข้อมูลเมตา",
"TaskDownloadMissingSubtitles": "ดาวน์โหลดคำบรรยายที่ขาดหายไป",
"TaskRefreshChannelsDescription": "รีเฟรชข้อมูลช่องอินเทอร์เน็ต",
@@ -95,11 +72,8 @@
"TasksLibraryCategory": "ไลบรารี",
"TasksMaintenanceCategory": "ปิดซ่อมบำรุง",
"VersionNumber": "เวอร์ชัน {0}",
- "ValueSpecialEpisodeName": "พิเศษ - {0}",
- "ValueHasBeenAddedToLibrary": "เพิ่ม {0} ลงในไลบรารีสื่อของคุณแล้ว",
"UserStoppedPlayingItemWithValues": "{0} เล่นเสร็จแล้ว {1} บน {2}",
"UserStartedPlayingItemWithValues": "{0} กำลังเล่น {1} บน {2}",
- "UserPolicyUpdatedWithName": "มีการอัปเดตนโยบายผู้ใช้ของ {0}",
"UserPasswordChangedWithName": "มีการเปลี่ยนรหัสผ่านของผู้ใช้ {0}",
"UserOnlineFromDevice": "{0} ออนไลน์จาก {1}",
"UserOfflineFromDevice": "{0} ได้ยกเลิกการเชื่อมต่อจาก {1}",
@@ -107,10 +81,7 @@
"UserDownloadingItemWithValues": "{0} กำลังดาวน์โหลด {1}",
"UserDeletedWithName": "ลบผู้ใช้ {0} แล้ว",
"UserCreatedWithName": "สร้างผู้ใช้ {0} แล้ว",
- "User": "ผู้ใช้งาน",
"TvShows": "รายการทีวี",
- "System": "ระบบ",
- "Sync": "ซิงค์",
"SubtitleDownloadFailureFromForItem": "ไม่สามารถดาวน์โหลดคำบรรยายจาก {0} สำหรับ {1} ได้",
"StartupEmbyServerIsLoading": "กำลังโหลดเซิร์ฟเวอร์ Jellyfin โปรดลองอีกครั้งในอีกสักครู่",
"Default": "ค่าเริ่มต้น",
diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json
index 3789466868..0c42d4a55f 100644
--- a/Emby.Server.Implementations/Localization/Core/tr.json
+++ b/Emby.Server.Implementations/Localization/Core/tr.json
@@ -1,41 +1,24 @@
{
- "Albums": "Albümler",
"AppDeviceValues": "Uygulama: {0}, Aygıt: {1}",
- "Application": "Uygulama",
"Artists": "Sanatçılar",
"AuthenticationSucceededWithUserName": "{0} kimliği başarıyla doğrulandı",
"Books": "Kitaplar",
- "CameraImageUploadedFrom": "{0} 'den yeni bir kamera resmi yüklendi",
- "Channels": "Kanallar",
"ChapterNameValue": "{0}. Bölüm",
"Collections": "Koleksiyonlar",
- "DeviceOfflineWithName": "{0} bağlantısı kesildi",
- "DeviceOnlineWithName": "{0} bağlı",
"FailedLoginAttemptWithUserName": "{0} kullanıcısının başarısız oturum açma girişimi",
"Favorites": "Favoriler",
"Folders": "Klasörler",
"Genres": "Türler",
- "HeaderAlbumArtists": "Albüm sanatçıları",
"HeaderContinueWatching": "İzlemeye Devam Et",
- "HeaderFavoriteAlbums": "Favori Albümler",
- "HeaderFavoriteArtists": "Favori Sanatçılar",
"HeaderFavoriteEpisodes": "Favori Bölümler",
"HeaderFavoriteShows": "Favori Diziler",
- "HeaderFavoriteSongs": "Favori Şarkılar",
"HeaderLiveTV": "Canlı TV",
"HeaderNextUp": "Sıradaki Bölümler",
- "HeaderRecordingGroups": "Kayıt Grupları",
"HomeVideos": "Ana Ekran Videoları",
"Inherit": "Devral",
- "ItemAddedWithName": "{0} kütüphaneye eklendi",
- "ItemRemovedWithName": "{0} kütüphaneden silindi",
"LabelIpAddressValue": "IP adresi: {0}",
"LabelRunningTimeValue": "Oynatma süresi: {0}",
"Latest": "En son",
- "MessageApplicationUpdated": "Jellyfin Sunucusu güncellendi",
- "MessageApplicationUpdatedTo": "Jellyfin Sunucusu {0} sürümüne güncellendi",
- "MessageNamedServerConfigurationUpdatedWithValue": "Sunucu yapılandırma bölümü {0} güncellendi",
- "MessageServerConfigurationUpdated": "Sunucu yapılandırması güncellendi",
"MixedContent": "Karışık içerik",
"Movies": "Filmler",
"Music": "Müzik",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "Video oynatma başladı",
"NotificationOptionVideoPlaybackStopped": "Video oynatma durduruldu",
"Photos": "Fotoğraflar",
- "Playlists": "Çalma listeleri",
- "Plugin": "Eklenti",
"PluginInstalledWithName": "{0} yüklendi",
"PluginUninstalledWithName": "{0} kaldırıldı",
"PluginUpdatedWithName": "{0} güncellendi",
- "ProviderValue": "Sağlayıcı: {0}",
"ScheduledTaskFailedWithName": "{0} başarısız oldu",
- "ScheduledTaskStartedWithName": "{0} başladı",
- "ServerNameNeedsToBeRestarted": "{0} yeniden başlatılması gerekiyor",
"Shows": "Diziler",
- "Songs": "Şarkılar",
"StartupEmbyServerIsLoading": "Jellyfin Sunucusu yükleniyor. Lütfen kısa süre sonra tekrar deneyin.",
"SubtitleDownloadFailureFromForItem": "{1} için altyazılar {0} sağlayıcısından indirilemedi",
- "Sync": "Eşzamanlama",
- "System": "Sistem",
"TvShows": "Diziler",
- "User": "Kullanıcı",
"UserCreatedWithName": "{0} kullanıcısı oluşturuldu",
"UserDeletedWithName": "{0} kullanıcısı silindi",
"UserDownloadingItemWithValues": "{0} kullanıcısı {1} medyasını indiriyor",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} kullanıcısının {1} ile bağlantısı kesildi",
"UserOnlineFromDevice": "{0} kullanıcısı {1} ile çevrimiçi",
"UserPasswordChangedWithName": "{0} kullanıcısının parolası değiştirildi",
- "UserPolicyUpdatedWithName": "{0} için kullanıcı politikası güncellendi",
"UserStartedPlayingItemWithValues": "{0}, {2} cihazında {1} izliyor",
"UserStoppedPlayingItemWithValues": "{0}, {2} cihazında {1} izlemeyi bitirdi",
- "ValueHasBeenAddedToLibrary": "{0} medya kütüphanenize eklendi",
- "ValueSpecialEpisodeName": "Özel - {0}",
"VersionNumber": "Sürüm {0}",
"TaskCleanCache": "Önbellek Dizinini Temizle",
"TasksChannelsCategory": "İnternet Kanalları",
@@ -135,5 +106,7 @@
"TaskDownloadMissingLyricsDescription": "Şarkı sözlerini indirir",
"TaskExtractMediaSegmentsDescription": "MediaSegment özelliği etkin olan eklentilerden medya segmentlerini çıkarır veya alır.",
"CleanupUserDataTask": "Kullanıcı verisi temizleme görevi",
- "CleanupUserDataTaskDescription": "En az 90 gün boyunca artık mevcut olmayan medyadaki tüm kullanıcı verilerini (İzleme durumu, favori durumu vb.) temizler."
+ "CleanupUserDataTaskDescription": "En az 90 gün boyunca artık mevcut olmayan medyadaki tüm kullanıcı verilerini (İzleme durumu, favori durumu vb.) temizler.",
+ "LyricDownloadFailureFromForItem": "{1} şarkı sözleri {0} adresinden indirilemedi",
+ "Original": "Orijinal"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ug.json b/Emby.Server.Implementations/Localization/Core/ug.json
index 0bcbffb41a..1d5adecb26 100644
--- a/Emby.Server.Implementations/Localization/Core/ug.json
+++ b/Emby.Server.Implementations/Localization/Core/ug.json
@@ -1,22 +1,15 @@
{
"ChapterNameValue": "باب {0}",
- "Channels": "قانال",
- "CameraImageUploadedFrom": "{0} ئورۇندىن يېڭى سۈرەت چىقىرىلدى",
"Books": "كىتاب",
"AuthenticationSucceededWithUserName": "{0} تەستىقلاش مۇۋاپىقىيەتلىك بولدى",
"Artists": "سەنئەتكار",
- "Albums": "پىلاستىنكا",
- "DeviceOnlineWithName": "{0} ئۇلاندى",
- "DeviceOfflineWithName": "{0} ئۈزۈلدى",
"Collections": "توپلام",
- "Application": "ئەپ",
"AppDeviceValues": "ئەپ: {0}، ئۈسكۈنە: {1}",
"HeaderLiveTV": "تور تېلېۋىزىيەسى",
"Default": "سۈكۈتتىكى",
"Folders": "ھۆججەت خالتىسى",
"Favorites": "ساقلىغۇچ",
"LabelRunningTimeValue": "ئىجرا بولغان ۋاقتى:{0}",
- "HeaderRecordingGroups": "خاتىرلەش گۇرۇپىسى",
"Forced": "ئەڭ",
"TaskKeyframeExtractor": "ھالقىلىق رامكا ئاجراتقۇچ",
"TaskKeyframeExtractorDescription": "سىن ھۆججەتلىرىدىن رامكا ئاجرىتىپ، تېخىمۇ ئېنىق بولغان HLS قويۇلۇش تىزىملىكىنى قۇرۇلىدۇ. بۇ ۋەزىپە ئۇزۇن داۋام قىلىشى مۇمكىن.",
@@ -46,35 +39,23 @@
"TasksLibraryCategory": "مېدىيا ئامبىرى",
"TasksMaintenanceCategory": "ئاسراش",
"VersionNumber": "نەشرى {0}",
- "ValueSpecialEpisodeName": "خاسلىق - {0}",
- "ValueHasBeenAddedToLibrary": "{0} مېدىيا ئامبىرىڭىزغا قوشۇلدى",
"UserStoppedPlayingItemWithValues": "{0}،{1} نى {2} دە قويۇنشتىن توختىدى",
"UserStartedPlayingItemWithValues": "{0}،{1} نى {2} دە قويۇۋاتىدۇ",
- "UserPolicyUpdatedWithName": "ئابونتلار سىياسىتى {0} غا يېڭىلاندى",
"UserPasswordChangedWithName": "ئابونت{0} ئۈچۈن پارول ئۆزگەرتىلدى",
"UserOfflineFromDevice": "{0} بىلەن {1} نىڭ ئالاقىسى ئۈزۈلدى",
"UserLockedOutWithName": "ئابونت {0} قۇلۇپلاندى",
"UserDownloadingItemWithValues": "{0} چۈشۈرۈۋاتىدۇ {1}",
"UserDeletedWithName": "{0} ئابونت ئۆچۈرۈلدى",
"UserCreatedWithName": "{0} ئابونت يېڭىدىن قوشۇلدى",
- "User": "ئابونت",
"Undefined": "بېكىتىلمىگەن",
"TvShows": "تىياتىرلار",
- "System": "سىستېما",
- "Sync": "ماس قەدەمدەش",
"SubtitleDownloadFailureFromForItem": "{0} دىن {0} نىڭ فىلىم خېتىنى چۈشۈرگىلى بولمىدى",
"StartupEmbyServerIsLoading": "Jellyfin مۇلازىمىتېرى يۈكلىنىۋاتىدۇ. سەل تۇرۇپ قايتا سىناڭ.",
- "Songs": "ناخشىلار",
"Shows": "پروگراممىلار",
- "ServerNameNeedsToBeRestarted": "{0} قايتا قوزغىتىلىشى كېرەك",
- "ScheduledTaskStartedWithName": "{0} باشلاندى",
"ScheduledTaskFailedWithName": "{0} مەغلۇپ بولدى",
- "ProviderValue": "تەمىنلىگۈچى: {0}",
"PluginUpdatedWithName": "{0} يېڭىلاندى",
"PluginUninstalledWithName": "{0} ئۆچۈرۈلدى",
"PluginInstalledWithName": "{0} قاچىلاندى",
- "Plugin": "قىستۇرما",
- "Playlists": "قويۇش تىزىملىكى",
"Photos": "رەسىملەر",
"NotificationOptionVideoPlaybackStopped": "سىن قويۇلۇش توختىدى",
"NotificationOptionVideoPlayback": "سىن قويۇلدى",
@@ -100,24 +81,14 @@
"Music": "مۇزىكا",
"Movies": "فىلىملەر",
"MixedContent": "ئارىلاشما مەزمۇن",
- "MessageNamedServerConfigurationUpdatedWithValue": "مۇلازىمىتېر تەڭشىكىنىڭ {0} قىسمى يېڭىلىنىپ بولدى",
- "MessageServerConfigurationUpdated": "مۇلازىمىتېر يېڭىلىنىپ بولدى",
- "MessageApplicationUpdated": "Jellyfin مۇلازىمىتېرى يېڭىلاندى",
- "MessageApplicationUpdatedTo": "Jellyfin مۇلازىمىتېر نەشرى {0} گە يېڭىلاندى",
"Latest": "ئەڭ يېڭى",
"LabelIpAddressValue": "{0}: IP ئادرىسى",
- "ItemRemovedWithName": "{0} ئامباردىن چىقىرىلدى",
- "ItemAddedWithName": "{0} ئامبارغا قوشۇلدى",
"Inherit": "داۋاملاشتۇرۇش",
"HomeVideos": "ئائىلە سىنلىرى",
"HeaderNextUp": "كېيىنكىسى",
- "HeaderFavoriteSongs": "ئەڭ ياقتۇرىدىغان ناخشىلار",
"HeaderFavoriteShows": "ئەڭ ياقتۇرىدىغان پروگراممىلار",
"HeaderFavoriteEpisodes": "ئەڭ ياقتۇرىدىغان تىياتېرلار",
- "HeaderFavoriteArtists": "ئەڭ ياقتۇرىدىغان سەنئەتكارلار",
- "HeaderFavoriteAlbums": "ياقتۇرىدىغان پىلاستىنكىلار",
"HeaderContinueWatching": "داۋاملىق كۆرۈش",
- "HeaderAlbumArtists": "پىلاستىنكا سەنئەتكارلىرى",
"Genres": "ئۇسلۇبلار",
"FailedLoginAttemptWithUserName": "{0} كىرىش ئوڭۇشلۇق بولمىدى",
"External": "سىرتقى"
diff --git a/Emby.Server.Implementations/Localization/Core/uk.json b/Emby.Server.Implementations/Localization/Core/uk.json
index 61d5d6964c..ccb9d915d1 100644
--- a/Emby.Server.Implementations/Localization/Core/uk.json
+++ b/Emby.Server.Implementations/Localization/Core/uk.json
@@ -2,36 +2,22 @@
"MusicVideos": "Відеокліпи",
"Music": "Музика",
"Movies": "Фільми",
- "MessageApplicationUpdatedTo": "Jellyfin Server оновлено до версії {0}",
- "MessageApplicationUpdated": "Jellyfin Server оновлено",
"Latest": "Останні",
"LabelIpAddressValue": "IP-адреса: {0}",
- "ItemRemovedWithName": "{0} видалено з медіатеки",
- "ItemAddedWithName": "{0} додано до медіатеки",
"HeaderNextUp": "Наступний",
"HeaderLiveTV": "Ефірне ТБ",
- "HeaderFavoriteSongs": "Обрані пісні",
"HeaderFavoriteShows": "Обрані шоу",
"HeaderFavoriteEpisodes": "Обрані епізоди",
- "HeaderFavoriteArtists": "Обрані виконавці",
- "HeaderFavoriteAlbums": "Обрані альбоми",
"HeaderContinueWatching": "Продовжити перегляд",
- "HeaderAlbumArtists": "Виконавці альбому",
"Genres": "Жанри",
"Folders": "Теки",
"Favorites": "Обрані",
- "DeviceOnlineWithName": "Пристрій {0} підключився",
- "DeviceOfflineWithName": "Пристрій {0} відключився",
"Collections": "Колекції",
"ChapterNameValue": "Сцена {0}",
- "Channels": "Канали",
- "CameraImageUploadedFrom": "Нову фотографію завантажено з {0}",
"Books": "Книги",
"AuthenticationSucceededWithUserName": "{0} успішно авторизовано",
"Artists": "Виконавці",
- "Application": "Додаток",
"AppDeviceValues": "Додаток: {0}, Пристрій: {1}",
- "Albums": "Альбоми",
"NotificationOptionServerRestartRequired": "Необхідно перезапустити сервер",
"NotificationOptionPluginUpdateInstalled": "Встановлено оновлення плагіна",
"NotificationOptionPluginUninstalled": "Плагін видалено",
@@ -64,11 +50,8 @@
"TasksLibraryCategory": "Медіатека",
"TasksMaintenanceCategory": "Обслуговування",
"VersionNumber": "Версія {0}",
- "ValueSpecialEpisodeName": "Спецепізод - {0}",
- "ValueHasBeenAddedToLibrary": "{0} додано до медіатеки",
"UserStoppedPlayingItemWithValues": "{0} закінчив відтворення {1} на {2}",
"UserStartedPlayingItemWithValues": "{0} відтворює {1} на {2}",
- "UserPolicyUpdatedWithName": "Політика користувача оновлена для {0}",
"UserPasswordChangedWithName": "Пароль змінено для користувача {0}",
"UserOnlineFromDevice": "{0} підключився з {1}",
"UserOfflineFromDevice": "{0} відключився від {1}",
@@ -76,23 +59,14 @@
"UserDownloadingItemWithValues": "{0} завантажує {1}",
"UserDeletedWithName": "Користувача {0} видалено",
"UserCreatedWithName": "Користувача {0} створено",
- "User": "Користувач",
"TvShows": "ТВ-шоу",
- "System": "Система",
- "Sync": "Синхронізація",
"SubtitleDownloadFailureFromForItem": "Не вдалося завантажити субтитри з {0} для {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server завантажується. Будь ласка, спробуйте трішки пізніше.",
- "Songs": "Пісні",
"Shows": "Серіали",
- "ServerNameNeedsToBeRestarted": "{0} потрібно перезапустити",
- "ScheduledTaskStartedWithName": "{0} розпочато",
"ScheduledTaskFailedWithName": "{0} незавершено, збій",
- "ProviderValue": "Постачальник: {0}",
"PluginUpdatedWithName": "{0} оновлено",
"PluginUninstalledWithName": "{0} видалено",
"PluginInstalledWithName": "{0} встановлено",
- "Plugin": "Плагін",
- "Playlists": "Плейлисти",
"Photos": "Фотографії",
"NotificationOptionVideoPlaybackStopped": "Відтворення відео зупинено",
"NotificationOptionVideoPlayback": "Розпочато відтворення відео",
@@ -109,10 +83,7 @@
"NameSeasonNumber": "Сезон {0}",
"NameInstallFailed": "Не вдалося встановити {0}",
"MixedContent": "Змішаний контент",
- "MessageServerConfigurationUpdated": "Конфігурація сервера оновлена",
- "MessageNamedServerConfigurationUpdatedWithValue": "Розділ конфігурації сервера {0} оновлено",
"Inherit": "Успадкувати",
- "HeaderRecordingGroups": "Групи запису",
"Forced": "Форсовані",
"TaskCleanActivityLogDescription": "Видаляє старші за встановлений термін записи з журналу активності.",
"TaskCleanActivityLog": "Очистити журнал активності",
@@ -136,5 +107,6 @@
"TaskExtractMediaSegmentsDescription": "Витягує або отримує медіа-сегменти з плагінів з підтримкою MediaSegment.",
"CleanupUserDataTask": "Завдання очищення даних користувача",
"CleanupUserDataTaskDescription": "Очищає всі дані користувача (стан перегляду, статус обраного тощо) з медіа, які перестали бути доступними щонайменше 90 днів тому.",
- "Original": "Оригінал"
+ "Original": "Оригінал",
+ "LyricDownloadFailureFromForItem": "Не вдалося завантажити текст пісні з {0} для {1}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ur.json b/Emby.Server.Implementations/Localization/Core/ur.json
index 94d9c8541e..07d309c270 100644
--- a/Emby.Server.Implementations/Localization/Core/ur.json
+++ b/Emby.Server.Implementations/Localization/Core/ur.json
@@ -1,16 +1,10 @@
{
"Books": "کتابیں",
"AppDeviceValues": "ایپ: {0}، ڈیوائس: {1}",
- "Albums": "البمز",
- "Application": "ایپلی کیشن",
"Artists": "فنکار",
"AuthenticationSucceededWithUserName": "{0} کی کامیابی سے تصدیق ہو چکی ہے",
- "CameraImageUploadedFrom": "ایک نئی کیمرے کی تصویر {0} سے اپ لوڈ کی گئی ہے",
- "Channels": "چینلز",
"ChapterNameValue": "باب {0}",
"Collections": "مجموعے",
"Default": "ڈیفالٹ",
- "DeviceOfflineWithName": "{0} نے رابطہ منقطع کر دیا ہے",
- "DeviceOnlineWithName": "{0} منسلک ہے",
"External": "بیرونی"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ur_PK.json b/Emby.Server.Implementations/Localization/Core/ur_PK.json
index f6539adff3..b3f24a31e3 100644
--- a/Emby.Server.Implementations/Localization/Core/ur_PK.json
+++ b/Emby.Server.Implementations/Localization/Core/ur_PK.json
@@ -1,27 +1,17 @@
{
- "HeaderFavoriteAlbums": "پسندیدہ البمز",
"HeaderNextUp": "اگلا",
- "HeaderFavoriteArtists": "پسندیدہ فنکار",
- "HeaderAlbumArtists": "البم کے فنکار",
"Movies": "فلمیں",
"HeaderFavoriteEpisodes": "پسندیدہ اقساط",
"Collections": "مجموعے",
"Folders": "فولڈرز",
"HeaderLiveTV": "براہ راست ٹی وی",
- "Channels": "چینلز",
"HeaderContinueWatching": "دیکھنا جاری رکھیں",
- "Playlists": "پلے لسٹس",
- "ValueSpecialEpisodeName": "خصوصی - {0}",
"Shows": "دکھاتا ہے",
"Genres": "انواع",
"Artists": "فنکار",
- "Sync": "مطابقت پذیری",
"Photos": "تصاویر",
- "Albums": "البمز",
"Favorites": "پسندیدہ",
- "Songs": "گانے",
"Books": "کتابیں",
- "HeaderFavoriteSongs": "پسندیدہ گانے",
"HeaderFavoriteShows": "پسندیدہ شوز",
"TaskDownloadMissingSubtitlesDescription": "میٹا ڈیٹا کی تشکیل پر مبنی ذیلی عنوانات کے غائب عنوانات انٹرنیٹ پے تلاش کرتا ہے۔",
"TaskDownloadMissingSubtitles": "غائب سب ٹائٹلز ڈاؤن لوڈ کریں",
@@ -46,10 +36,8 @@
"TasksLibraryCategory": "لآیبریری",
"TasksMaintenanceCategory": "مرمت",
"VersionNumber": "ورژن {0}",
- "ValueHasBeenAddedToLibrary": "{0} آپ کی میڈیا لائبریری میں شامل کر دیا گیا ہے",
"UserStoppedPlayingItemWithValues": "{0} نے {1} چلانا ختم کر دیا ھے {2} پے",
"UserStartedPlayingItemWithValues": "{0} چلا رہا ہے {1} {2} پے",
- "UserPolicyUpdatedWithName": "صارف {0} کی پالیسی کیلئے تازہ کاری کی گئی ہے",
"UserPasswordChangedWithName": "صارف {0} کے لئے پاس ورڈ تبدیل کر دیا گیا ہے",
"UserOnlineFromDevice": "{0} آن لائن ہے {1} سے",
"UserOfflineFromDevice": "{0} سے منقطع ہوگیا ہے {1}",
@@ -57,19 +45,13 @@
"UserDownloadingItemWithValues": "{0} ڈاؤن لوڈ کر رھا ھے {1}",
"UserDeletedWithName": "صارف {0} کو ہٹا دیا گیا ہے",
"UserCreatedWithName": "صارف {0} تشکیل دیا گیا ہے",
- "User": "صارف",
"TvShows": "ٹی وی کے پروگرام",
- "System": "نظام",
"SubtitleDownloadFailureFromForItem": "ذیلی عنوانات {0} سے ڈاؤن لوڈ کرنے میں ناکام {1} کے لیے",
"StartupEmbyServerIsLoading": "جیلیفن سرور لوڈ ہورہا ہے۔ براہ کرم جلد ہی دوبارہ کوشش کریں۔",
- "ServerNameNeedsToBeRestarted": "{0} دوبارہ چلانے کرنے کی ضرورت ہے",
- "ScheduledTaskStartedWithName": "{0} شروع",
"ScheduledTaskFailedWithName": "{0} ناکام",
- "ProviderValue": "فراہم کرنے والا: {0}",
"PluginUpdatedWithName": "{0} تازہ کاری کی گئی تھی",
"PluginUninstalledWithName": "[0} ہٹا دیا گیا تھا",
"PluginInstalledWithName": "{0} انسٹال کیا گیا تھا",
- "Plugin": "پلگن",
"NotificationOptionVideoPlaybackStopped": "ویڈیو پلے بیک رک گیا",
"NotificationOptionVideoPlayback": "ویڈیو پلے بیک شروع ہوا",
"NotificationOptionUserLockedOut": "صارف کو لاک آؤٹ کیا گیا",
@@ -93,25 +75,14 @@
"MusicVideos": "میوزک ویڈیوز",
"Music": "موسیقی",
"MixedContent": "مخلوط مواد",
- "MessageServerConfigurationUpdated": "سرور کو اپ ڈیٹ کر دیا گیا ہے",
- "MessageNamedServerConfigurationUpdatedWithValue": "سرور ضمن {0} کو ترتیب دے دیا گیا ھے",
- "MessageApplicationUpdatedTo": "جیلیفن سرور کو اپ ڈیٹ کیا ہے {0}",
- "MessageApplicationUpdated": "جیلیفن سرور کو اپ ڈیٹ کر دیا گیا ہے",
"Latest": "تازہ ترین",
"LabelRunningTimeValue": "چلانے کی مدت",
"LabelIpAddressValue": "آئ پی ایڈریس {0}",
- "ItemRemovedWithName": "لائبریری سے ہٹا دیا گیا ھے",
- "ItemAddedWithName": "[0} لائبریری میں شامل کیا گیا ھے",
"Inherit": "وراثت",
"HomeVideos": "ہوم ویڈیوز",
- "HeaderRecordingGroups": "ریکارڈنگ گروپس",
"FailedLoginAttemptWithUserName": "{0} سے لاگ ان کی ناکام کوشش",
- "DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
- "DeviceOfflineWithName": "{0} منقطع ھو چکا ھے",
"ChapterNameValue": "باب",
"AuthenticationSucceededWithUserName": "{0} کامیابی کے ساتھ تصدیق ھوچکی ھے",
- "CameraImageUploadedFrom": "ایک نئی کیمرہ تصویر اپ لوڈ کی گئی ہے {0}",
- "Application": "پروگرام",
"AppDeviceValues": "پروگرام:{0}, ڈیوائس:{1}",
"Forced": "جَبری",
"Undefined": "غير وضاحتى",
diff --git a/Emby.Server.Implementations/Localization/Core/uz.json b/Emby.Server.Implementations/Localization/Core/uz.json
index e44b3f5167..998d799a95 100644
--- a/Emby.Server.Implementations/Localization/Core/uz.json
+++ b/Emby.Server.Implementations/Localization/Core/uz.json
@@ -1,47 +1,32 @@
{
"HeaderContinueWatching": "Ko‘rishda davom etish",
- "HeaderAlbumArtists": "Albom ijrochilari",
"Genres": "Janrlar",
"Folders": "Jildlar",
"Favorites": "Sevimlilar",
"Collections": "To'plamlar",
- "Channels": "Kanallar",
"Books": "Kitoblar",
"Artists": "Ijrochilar",
- "Albums": "Albomlar",
"AuthenticationSucceededWithUserName": "{0} muvaffaqiyatli tasdiqlandi",
"AppDeviceValues": "Ilova: {0}, Qurilma: {1}",
- "Application": "Ilova",
- "CameraImageUploadedFrom": "{0}dan yangi kamera rasmi yuklandi",
- "DeviceOnlineWithName": "{0} ulangan",
- "ItemRemovedWithName": "{0} kutbxonadan o'chirildi",
"External": "Tashqi",
"FailedLoginAttemptWithUserName": "Muvafaqiyatsiz kirishlar soni {0}",
"Forced": "Majburiy",
"ChapterNameValue": "{0}chi bo'lim",
- "DeviceOfflineWithName": "{0} aloqa uzildi",
"HeaderLiveTV": "Jonli TV",
"HeaderNextUp": "Keyingisi",
- "ItemAddedWithName": "{0} kutbxonaga qo'shildi",
"LabelIpAddressValue": "IP manzil: {0}",
"SubtitleDownloadFailureFromForItem": "{0} dan {1} uchun taglavhalarni yuklab boʻlmadi",
"UserPasswordChangedWithName": "Foydalanuvchi {0} paroli oʻzgartirildi",
- "ValueHasBeenAddedToLibrary": "{0} kutubxonaga qoʻshildi",
"TaskCleanActivityLogDescription": "Belgilangan yoshdan kattaroq faoliyat jurnali yozuvlarini oʻchiradi.",
"TaskAudioNormalization": "Ovozni normallashtirish",
"TaskRefreshLibraryDescription": "Media kutubxonasi yangi fayllar uchun skanerlanmoqda va metama'lumotlar yangilanmoqda.",
"Default": "Joriy",
- "HeaderFavoriteAlbums": "Tanlangan albomlar",
- "HeaderFavoriteArtists": "Tanlangan artistlar",
"HeaderFavoriteEpisodes": "Tanlangan epizodlar",
"HeaderFavoriteShows": "Tanlangan shoular",
- "HeaderFavoriteSongs": "Tanlangan qo'shiqlar",
- "HeaderRecordingGroups": "Yozuvlar guruhi",
"HomeVideos": "Uy videolari",
"NotificationOptionVideoPlaybackStopped": "Video ijrosi toʻxtatildi",
"TvShows": "TV seriallar",
"Undefined": "Belgilanmagan",
- "User": "Foydalanuvchi",
"UserCreatedWithName": "{0} foydalanuvchi yaratildi",
"TaskCleanCacheDescription": "Tizimga kerak bo'lmagan kesh fayllari o'chiriladi.",
"TaskAudioNormalizationDescription": "Ovozni normallashtirish ma'lumotlari uchun fayllarni skanerlaydi.",
@@ -67,10 +52,6 @@
"NotificationOptionVideoPlayback": "Video ijrosi boshlandi",
"Photos": "Surat",
"Latest": "So'ngi",
- "MessageApplicationUpdated": "Jellyfin Server yangilandi",
- "MessageApplicationUpdatedTo": "Jellyfin Server {0} gacha yangilandi",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server konfiguratsiyasi ({0}-boʻlim) yangilandi",
- "MessageServerConfigurationUpdated": "Server konfiguratsiyasi yangilandi",
"MixedContent": "Aralashgan tarkib",
"Movies": "Kinolar",
"Music": "Qo'shiqlar",
@@ -78,29 +59,19 @@
"NameInstallFailed": "Omadsiz ornatish {0}",
"NameSeasonNumber": "{0} Fasl",
"NameSeasonUnknown": "Fasl aniqlanmagan",
- "Playlists": "Pleylistlar",
"NewVersionIsAvailable": "Yuklab olish uchun Jellyfin Server ning yangi versiyasi mavjud",
- "Plugin": "Plagin",
"TaskCleanLogs": "Jurnallar katalogini tozalash",
"PluginUpdatedWithName": "{0} - yangilandi",
- "ProviderValue": "Yetkazib beruvchi: {0}",
"ScheduledTaskFailedWithName": "{0} - omadsiz",
- "ScheduledTaskStartedWithName": "{0} - ishga tushirildi",
- "ServerNameNeedsToBeRestarted": "Qayta yuklash kerak {0}",
"Shows": "Teleko'rsatuv",
- "Songs": "Kompozitsiyalar",
"StartupEmbyServerIsLoading": "Jellyfin Server yuklanmoqda. Tez orada qayta urinib koʻring.",
- "Sync": "Sinxronizatsiya",
- "System": "Tizim",
"UserDeletedWithName": "{0} foydalanuvchisi oʻchirib tashlandi",
"UserDownloadingItemWithValues": "{0} yuklanmoqda {1}",
"UserLockedOutWithName": "{0} foydalanuvchisi bloklandi",
"UserOfflineFromDevice": "{0} {1}dan uzildi",
"UserOnlineFromDevice": "{0} {1} dan ulandi",
- "UserPolicyUpdatedWithName": "{0} foydalanuvchisining siyosatlari yangilandi",
"UserStartedPlayingItemWithValues": "{0} - {2} da \"{1}\" ijrosi",
"UserStoppedPlayingItemWithValues": "{0} - ijro etish to‘xtatildi {1} {2}",
- "ValueSpecialEpisodeName": "Maxsus qism – {0}",
"VersionNumber": "Versiya {0}",
"TasksMaintenanceCategory": "Xizmat ko'rsatish",
"TasksLibraryCategory": "Media kutubxona",
diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json
index 831ec62fb3..2ba665e2ff 100644
--- a/Emby.Server.Implementations/Localization/Core/vi.json
+++ b/Emby.Server.Implementations/Localization/Core/vi.json
@@ -3,17 +3,11 @@
"Favorites": "Yêu Thích",
"Folders": "Thư Mục",
"Genres": "Thể Loại",
- "HeaderAlbumArtists": "Album nghệ sĩ",
"HeaderContinueWatching": "Xem Tiếp",
"HeaderLiveTV": "TV Trực Tiếp",
"Movies": "Phim",
"Photos": "Ảnh",
- "Playlists": "Danh sách phát",
"Shows": "Chương Trình TV",
- "Songs": "Bài Hát",
- "Sync": "Đồng Bộ",
- "ValueSpecialEpisodeName": "Đặc Biệt - {0}",
- "Albums": "Album",
"Artists": "Ca Sĩ",
"TaskDownloadMissingSubtitlesDescription": "Tìm kiếm phụ đề bị thiếu trên Internet dựa trên cấu hình dữ liệu mô tả.",
"TaskDownloadMissingSubtitles": "Tải Xuống Phụ Đề Bị Thiếu",
@@ -38,10 +32,8 @@
"TasksLibraryCategory": "Thư Viện",
"TasksMaintenanceCategory": "Bảo Trì",
"VersionNumber": "Phiên Bản {0}",
- "ValueHasBeenAddedToLibrary": "{0} đã được thêm vào thư viện của bạn",
"UserStoppedPlayingItemWithValues": "{0} đã kết thúc phát {1} trên {2}",
"UserStartedPlayingItemWithValues": "{0} đang phát {1} trên {2}",
- "UserPolicyUpdatedWithName": "Chính sách người dùng đã được cập nhật cho {0}",
"UserPasswordChangedWithName": "Mật khẩu đã được thay đổi cho người dùng {0}",
"UserOnlineFromDevice": "{0} trực tuyến từ {1}",
"UserOfflineFromDevice": "{0} đã ngắt kết nối từ {1}",
@@ -49,19 +41,13 @@
"UserDownloadingItemWithValues": "{0} đang tải xuống {1}",
"UserDeletedWithName": "Người Dùng {0} đã được xóa",
"UserCreatedWithName": "Người Dùng {0} đã được tạo",
- "User": "Người Dùng",
"TvShows": "Chương Trình TV",
- "System": "Hệ Thống",
"SubtitleDownloadFailureFromForItem": "Không thể tải xuống phụ đề từ {0} cho {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server đang tải. Vui lòng thử lại trong thời gian ngắn.",
- "ServerNameNeedsToBeRestarted": "{0} cần được khởi động lại",
- "ScheduledTaskStartedWithName": "{0} đã bắt đầu",
"ScheduledTaskFailedWithName": "{0} đã thất bại",
- "ProviderValue": "Provider: {0}",
"PluginUpdatedWithName": "{0} đã cập nhật",
"PluginUninstalledWithName": "{0} đã được gỡ bỏ",
"PluginInstalledWithName": "{0} đã được cài đặt",
- "Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Đã dừng phát lại video",
"NotificationOptionVideoPlayback": "Đã bắt đầu phát lại video",
"NotificationOptionUserLockedOut": "Người dùng bị khóa",
@@ -85,33 +71,18 @@
"MusicVideos": "Videos Nhạc",
"Music": "Nhạc",
"MixedContent": "Nội dung hỗn hợp",
- "MessageServerConfigurationUpdated": "Cấu hình máy chủ đã được cập nhật",
- "MessageNamedServerConfigurationUpdatedWithValue": "Phần cấu hình máy chủ {0} đã được cập nhật",
- "MessageApplicationUpdatedTo": "Jellyfin Server đã được cập nhật lên {0}",
- "MessageApplicationUpdated": "Jellyfin Server đã được cập nhật",
"Latest": "Gần Nhất",
"LabelRunningTimeValue": "Thời Gian Chạy: {0}",
"LabelIpAddressValue": "Địa chỉ IP: {0}",
- "ItemRemovedWithName": "{0} đã xóa khỏi thư viện",
- "ItemAddedWithName": "{0} được thêm vào thư viện",
"Inherit": "Thừa hưởng",
"HomeVideos": "Video Nhà",
- "HeaderRecordingGroups": "Nhóm Ghi Video",
"HeaderNextUp": "Tiếp Theo",
- "HeaderFavoriteSongs": "Bài Hát Yêu Thích",
"HeaderFavoriteShows": "Chương Trình Yêu Thích",
"HeaderFavoriteEpisodes": "Tập Phim Yêu Thích",
- "HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích",
- "HeaderFavoriteAlbums": "Album Ưa Thích",
"FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập không thành công từ {0}",
- "DeviceOnlineWithName": "{0} đã kết nối",
- "DeviceOfflineWithName": "{0} đã ngắt kết nối",
"ChapterNameValue": "Phân Cảnh {0}",
- "Channels": "Kênh",
- "CameraImageUploadedFrom": "Một hình ảnh máy ảnh mới đã được tải lên từ {0}",
"Books": "Sách",
"AuthenticationSucceededWithUserName": "{0} xác thực thành công",
- "Application": "Ứng Dụng",
"AppDeviceValues": "Ứng Dụng: {0}, Thiết Bị: {1}",
"TaskCleanActivityLogDescription": "Xóa các mục nhật ký hoạt động cũ hơn độ tuổi đã cài đặt.",
"TaskCleanActivityLog": "Xóa Nhật Ký Hoạt Động",
@@ -136,5 +107,6 @@
"TaskExtractMediaSegments": "Quét Phân Đoạn Phương Tiện",
"CleanupUserDataTask": "Tác vụ dọn dẹp dữ liệu người dùng",
"CleanupUserDataTaskDescription": "Làm sạch tất cả dữ liệu người dùng (trạng thái xem, trạng thái yêu thích, v.v.) từ phương tiện không còn có mặt trong ít nhất 90 ngày.",
- "Original": "Gốc"
+ "Original": "Gốc",
+ "LyricDownloadFailureFromForItem": "Lời bài hát không tải xuống được từ {0} cho {1}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json
index 6a7b7fb4e6..8c36139f29 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-CN.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json
@@ -1,41 +1,24 @@
{
- "Albums": "专辑",
"AppDeviceValues": "应用:{0},设备:{1}",
- "Application": "应用程序",
"Artists": "艺术家",
"AuthenticationSucceededWithUserName": "{0} 认证成功",
"Books": "书籍",
- "CameraImageUploadedFrom": "已从 {0} 上传新的相机照片",
- "Channels": "频道",
"ChapterNameValue": "章节 {0}",
"Collections": "合集",
- "DeviceOfflineWithName": "{0} 已断开连接",
- "DeviceOnlineWithName": "{0} 已连接",
"FailedLoginAttemptWithUserName": "来自 {0} 的登录失败",
"Favorites": "收藏夹",
"Folders": "文件夹",
"Genres": "类型",
- "HeaderAlbumArtists": "专辑艺术家",
"HeaderContinueWatching": "继续观看",
- "HeaderFavoriteAlbums": "收藏的专辑",
- "HeaderFavoriteArtists": "收藏的艺术家",
"HeaderFavoriteEpisodes": "收藏的剧集",
"HeaderFavoriteShows": "收藏的节目",
- "HeaderFavoriteSongs": "收藏的歌曲",
"HeaderLiveTV": "电视直播",
"HeaderNextUp": "接下来播放",
- "HeaderRecordingGroups": "录制组",
"HomeVideos": "家庭视频",
"Inherit": "继承",
- "ItemAddedWithName": "{0} 已添加到媒体库",
- "ItemRemovedWithName": "{0} 已从媒体库移除",
"LabelIpAddressValue": "IP 地址:{0}",
"LabelRunningTimeValue": "运行时间:{0}",
"Latest": "最新",
- "MessageApplicationUpdated": "Jellyfin 服务器已更新",
- "MessageApplicationUpdatedTo": "Jellyfin 服务器版本已更新到 {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "服务器配置 {0} 部分已更新",
- "MessageServerConfigurationUpdated": "服务器配置已更新",
"MixedContent": "混合内容",
"Movies": "电影",
"Music": "音乐",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "视频已开始播放",
"NotificationOptionVideoPlaybackStopped": "视频播放已停止",
"Photos": "照片",
- "Playlists": "播放列表",
- "Plugin": "插件",
"PluginInstalledWithName": "{0} 已安装",
"PluginUninstalledWithName": "{0} 已卸载",
"PluginUpdatedWithName": "{0} 已更新",
- "ProviderValue": "提供商:{0}",
"ScheduledTaskFailedWithName": "{0} 已失败",
- "ScheduledTaskStartedWithName": "{0} 已开始",
- "ServerNameNeedsToBeRestarted": "{0} 需要重新启动",
"Shows": "节目",
- "Songs": "歌曲",
"StartupEmbyServerIsLoading": "Jellyfin 服务器正在启动,请稍后再试。",
"SubtitleDownloadFailureFromForItem": "无法从 {0} 下载 {1} 的字幕",
- "Sync": "同步",
- "System": "系统",
"TvShows": "电视剧",
- "User": "用户",
"UserCreatedWithName": "已创建用户 {0}",
"UserDeletedWithName": "已删除用户 {0}",
"UserDownloadingItemWithValues": "{0} 正在下载 {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} 已从 {1} 断开",
"UserOnlineFromDevice": "{0} 已在 {1} 上线",
"UserPasswordChangedWithName": "用户 {0} 的密码已更改",
- "UserPolicyUpdatedWithName": "用户协议已更新为 {0}",
"UserStartedPlayingItemWithValues": "{0} 在 {2} 上开始播放 {1}",
"UserStoppedPlayingItemWithValues": "{0} 在 {2} 上停止播放 {1}",
- "ValueHasBeenAddedToLibrary": "{0} 已添加至您的媒体库中",
- "ValueSpecialEpisodeName": "特典 - {0}",
"VersionNumber": "版本 {0}",
"TaskUpdatePluginsDescription": "为已设置为自动更新的插件下载和安装更新。",
"TaskRefreshPeople": "刷新演职人员",
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index f3ad8be2a8..8b9665cf9a 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -1,41 +1,24 @@
{
- "Albums": "專輯",
"AppDeviceValues": "程式:{0},裝置:{1}",
- "Application": "應用程式",
"Artists": "藝人",
"AuthenticationSucceededWithUserName": "{0} 成功通過驗證",
"Books": "書籍",
- "CameraImageUploadedFrom": "{0} 已經成功上載咗一張新相",
- "Channels": "頻道",
"ChapterNameValue": "第 {0} 章",
"Collections": "系列",
- "DeviceOfflineWithName": "{0} 斷開咗連線",
- "DeviceOnlineWithName": "{0} 連線咗",
"FailedLoginAttemptWithUserName": "來自 {0} 嘅登入嘗試失敗咗",
"Favorites": "心水",
"Folders": "資料夾",
"Genres": "風格",
- "HeaderAlbumArtists": "專輯歌手",
"HeaderContinueWatching": "繼續睇返",
- "HeaderFavoriteAlbums": "心水嘅專輯",
- "HeaderFavoriteArtists": "心水嘅藝人",
"HeaderFavoriteEpisodes": "心水嘅劇集",
"HeaderFavoriteShows": "心水嘅節目",
- "HeaderFavoriteSongs": "心水嘅歌曲",
"HeaderLiveTV": "電視直播",
"HeaderNextUp": "跟住落嚟",
- "HeaderRecordingGroups": "錄製組",
"HomeVideos": "家庭影片",
"Inherit": "繼承",
- "ItemAddedWithName": "{0} 經已加咗入媒體櫃",
- "ItemRemovedWithName": "{0} 經已由媒體櫃移除咗",
"LabelIpAddressValue": "IP 位址:{0}",
"LabelRunningTimeValue": "運行時間:{0}",
"Latest": "最新",
- "MessageApplicationUpdated": "Jellyfin 經已更新咗",
- "MessageApplicationUpdatedTo": "Jellyfin 已經更新到 {0} 版本",
- "MessageNamedServerConfigurationUpdatedWithValue": "伺服器設定「{0}」經已更新咗",
- "MessageServerConfigurationUpdated": "伺服器設定經已更新咗",
"MixedContent": "混合內容",
"Movies": "電影",
"Music": "音樂",
@@ -61,23 +44,14 @@
"NotificationOptionVideoPlayback": "開始播放影片",
"NotificationOptionVideoPlaybackStopped": "停咗播放影片",
"Photos": "相片",
- "Playlists": "播放清單",
- "Plugin": "外掛程式",
"PluginInstalledWithName": "裝好咗 {0}",
"PluginUninstalledWithName": "剷走咗 {0}",
"PluginUpdatedWithName": "更新好咗 {0}",
- "ProviderValue": "提供者:{0}",
"ScheduledTaskFailedWithName": "{0} 執行失敗",
- "ScheduledTaskStartedWithName": "開始執行 {0}",
- "ServerNameNeedsToBeRestarted": "{0} 需要重新啟動",
"Shows": "節目",
- "Songs": "歌曲",
"StartupEmbyServerIsLoading": "Jellyfin 伺服器載入緊,唔該稍後再試。",
"SubtitleDownloadFailureFromForItem": "經 {0} 下載 {1} 嘅字幕失敗咗",
- "Sync": "同步",
- "System": "系統",
"TvShows": "電視節目",
- "User": "使用者",
"UserCreatedWithName": "經已建立咗新使用者 {0}",
"UserDeletedWithName": "使用者 {0} 經已被刪走",
"UserDownloadingItemWithValues": "{0} 下載緊 {1}",
@@ -85,11 +59,8 @@
"UserOfflineFromDevice": "{0} 經已由 {1} 斷開咗連線",
"UserOnlineFromDevice": "{0} 正喺 {1} 連線",
"UserPasswordChangedWithName": "使用者 {0} 嘅密碼經已更改咗",
- "UserPolicyUpdatedWithName": "使用者 {0} 嘅權限經已更新咗",
"UserStartedPlayingItemWithValues": "{0} 正喺 {2} 播緊 {1}",
"UserStoppedPlayingItemWithValues": "{0} 已經喺 {2} 停止播放 {1}",
- "ValueHasBeenAddedToLibrary": "{0} 已經成功加入咗你嘅媒體櫃",
- "ValueSpecialEpisodeName": "特輯 - {0}",
"VersionNumber": "版本 {0}",
"TaskDownloadMissingSubtitles": "下載漏咗嘅字幕",
"TaskUpdatePlugins": "更新外掛程式",
diff --git a/Emby.Server.Implementations/Localization/Core/zh-TW.json b/Emby.Server.Implementations/Localization/Core/zh-TW.json
index 1caf887094..5dace3b0b7 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-TW.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-TW.json
@@ -1,39 +1,23 @@
{
- "Albums": "專輯",
"AppDeviceValues": "應用程式:{0},裝置:{1}",
- "Application": "應用程式",
"Artists": "藝人",
"AuthenticationSucceededWithUserName": "成功授權 {0}",
"Books": "書籍",
- "CameraImageUploadedFrom": "已從 {0} 成功上傳一張照片",
- "Channels": "頻道",
"ChapterNameValue": "章節 {0}",
"Collections": "系列作",
- "DeviceOfflineWithName": "{0} 已中斷連接",
- "DeviceOnlineWithName": "{0} 已連接",
"FailedLoginAttemptWithUserName": "來自 {0} 的登入失敗嘗試",
"Favorites": "我的最愛",
"Folders": "資料夾",
"Genres": "風格",
- "HeaderAlbumArtists": "專輯演出者",
"HeaderContinueWatching": "繼續觀看",
- "HeaderFavoriteAlbums": "最愛專輯",
- "HeaderFavoriteArtists": "最愛的藝人",
"HeaderFavoriteEpisodes": "最愛的劇集",
"HeaderFavoriteShows": "最愛的節目",
- "HeaderFavoriteSongs": "最愛的歌曲",
"HeaderLiveTV": "電視直播",
"HeaderNextUp": "接下來",
"HomeVideos": "家庭影片",
- "ItemAddedWithName": "{0} 已新增至媒體庫",
- "ItemRemovedWithName": "{0} 已從媒體庫移除",
"LabelIpAddressValue": "IP 位址:{0}",
"LabelRunningTimeValue": "運行時間:{0}",
"Latest": "最新",
- "MessageApplicationUpdated": "Jellyfin 伺服器已經更新",
- "MessageApplicationUpdatedTo": "Jellyfin 伺服器已經更新至 {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "伺服器設定 {0} 部分已經更新",
- "MessageServerConfigurationUpdated": "伺服器設定已經更新",
"MixedContent": "混合內容",
"Movies": "電影",
"Music": "音樂",
@@ -59,22 +43,13 @@
"NotificationOptionVideoPlayback": "影片播放已開始",
"NotificationOptionVideoPlaybackStopped": "影片播放已停止",
"Photos": "相片",
- "Playlists": "播放清單",
- "Plugin": "擴充功能",
"PluginInstalledWithName": "已安裝 {0}",
"PluginUninstalledWithName": "已移除 {0}",
"PluginUpdatedWithName": "已更新 {0}",
- "ProviderValue": "提供者:{0}",
"ScheduledTaskFailedWithName": "排程任務 {0} 執行失敗",
- "ScheduledTaskStartedWithName": "排程任務 {0} 已開始",
- "ServerNameNeedsToBeRestarted": "伺服器 {0} 需要重新啟動",
"Shows": "節目",
- "Songs": "歌曲",
"StartupEmbyServerIsLoading": "Jellyfin 伺服器載入中,請稍後再試。",
- "Sync": "同步",
- "System": "系統",
"TvShows": "電視節目",
- "User": "使用者",
"UserCreatedWithName": "已建立使用者 {0}",
"UserDeletedWithName": "已刪除使用者 {0}",
"UserDownloadingItemWithValues": "使用者 {0} 正在下載 {1}",
@@ -82,13 +57,9 @@
"UserOfflineFromDevice": "使用者 {0} 已從 {1} 斷線",
"UserOnlineFromDevice": "使用者 {0} 已從 {1} 連線",
"UserPasswordChangedWithName": "使用者 {0} 的密碼已變更",
- "UserPolicyUpdatedWithName": "使用者權限已更新為 {0}",
"UserStartedPlayingItemWithValues": "{0} 正在 {2} 上播放 {1}",
"UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
- "ValueHasBeenAddedToLibrary": "{0} 已新增至您的媒體庫",
- "ValueSpecialEpisodeName": "特輯 - {0}",
"VersionNumber": "版本 {0}",
- "HeaderRecordingGroups": "錄製組",
"Inherit": "繼承",
"SubtitleDownloadFailureFromForItem": "無法從 {0} 下載 {1} 的字幕",
"TaskDownloadMissingSubtitlesDescription": "透過媒體資訊從網路上搜尋遺失的字幕。",
diff --git a/Emby.Server.Implementations/Localization/Core/zu.json b/Emby.Server.Implementations/Localization/Core/zu.json
index aa056d4498..669ea0372d 100644
--- a/Emby.Server.Implementations/Localization/Core/zu.json
+++ b/Emby.Server.Implementations/Localization/Core/zu.json
@@ -2,37 +2,24 @@
"TasksApplicationCategory": "Ukusetshenziswa",
"TasksLibraryCategory": "Umtapo",
"TasksMaintenanceCategory": "Ukunakekela",
- "User": "Umsebenzisi",
"Undefined": "Akuchaziwe",
- "System": "Isistimu",
- "Sync": "Vumelanisa",
- "Songs": "Amaculo",
"Shows": "Izinhlelo",
- "Plugin": "Isijobelelo",
- "Playlists": "Izinhla Zokudlalayo",
"Photos": "Izithombe",
"Music": "Umculo",
"Movies": "Amamuvi",
"Latest": "lwakamuva",
"Inherit": "Ngefa",
"Forced": "Kuphoqiwe",
- "Application": "Ukusetshenziswa",
"Genres": "Izinhlobo",
"Folders": "Izikhwama",
"Favorites": "Izintandokazi",
"Default": "Okumisiwe",
"Collections": "Amaqoqo",
- "Channels": "Amashaneli",
"Books": "Izincwadi",
"Artists": "Abadlali",
- "Albums": "Ama-albhamu",
- "CameraImageUploadedFrom": "Kulandelayo lwesithonjana sekhamera selithunyelwe kusuka ku {0}",
- "HeaderFavoriteArtists": "Abasethi Abathandekayo",
"HeaderFavoriteEpisodes": "Izilimi Ezithandekayo",
"HeaderFavoriteShows": "Izisho Ezithandekayo",
"External": "Kwezifungo",
"FailedLoginAttemptWithUserName": "Ukushayiswa kwesithombe sokungena okungekho {0}",
- "HeaderContinueWatching": "Buyela Ukubona",
- "HeaderFavoriteAlbums": "Izimpahla Ezithandwayo",
- "HeaderAlbumArtists": "Abasethi wenkulumo"
+ "HeaderContinueWatching": "Buyela Ukubona"
}
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index d8797e612b..0b0b300d30 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -26,6 +27,7 @@ namespace Emby.Server.Implementations.Localization
private const string RatingsPath = "Emby.Server.Implementations.Localization.Ratings.";
private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt";
private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json";
+ private const string CoreResourcePrefix = "Emby.Server.Implementations.Localization.Core.";
private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
private static readonly string[] _unratedValues = ["n/a", "unrated", "not rated", "nr"];
@@ -34,13 +36,21 @@ namespace Emby.Server.Implementations.Localization
private readonly Dictionary<string, Dictionary<string, ParentalRatingScore?>> _allParentalRatings = new(StringComparer.OrdinalIgnoreCase);
- private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries = new(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, Dictionary<string, string>> _cultureOnlyDictionaries = new(StringComparer.OrdinalIgnoreCase);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private readonly ConcurrentDictionary<string, CultureDto?> _cultureCache = new(StringComparer.OrdinalIgnoreCase);
private List<CultureDto> _cultures = [];
+ private static readonly (IReadOnlyList<LocalizationOption> Options, FrozenDictionary<string, string> Bcp47ToJellyfinMap) _localizationData = BuildLocalizationData();
+ private static readonly IReadOnlyList<LocalizationOption> _localizationOptions = _localizationData.Options;
+
+ // Maps BCP-47 hyphenated culture codes (set by ASP.NET Core's RequestLocalizationMiddleware
+ // and used as CurrentUICulture.Name) to Jellyfin's underscore-based resource file codes.
+ // Built reflexively from the resource file scan so both directions stay in sync.
+ private static readonly FrozenDictionary<string, string> _bcp47ToJellyfinMap = _localizationData.Bcp47ToJellyfinMap;
+
private FrozenDictionary<string, string> _iso6392BtoT = null!;
/// <summary>
@@ -54,6 +64,59 @@ namespace Emby.Server.Implementations.Localization
{
_configurationManager = configurationManager;
_logger = logger;
+
+ _configurationManager.ConfigurationUpdated += OnConfigurationUpdated;
+ }
+
+ /// <summary>
+ /// Gets the supported UI cultures.
+ /// </summary>
+ /// <returns>A list of <see cref="CultureInfo"/> objects covering every embedded translation.</returns>
+ public static IList<CultureInfo> GetSupportedUICultures()
+ {
+ var cultures = new List<CultureInfo>();
+ foreach (var option in _localizationOptions)
+ {
+ // Skip novelty codes (e.g. "pr" Pirate, "jbo" Lojban) that .NET cannot resolve.
+ if (TryGetCultureInfo(option.Value, out var cultureInfo))
+ {
+ cultures.Add(cultureInfo);
+ }
+ }
+
+ return cultures;
+ }
+
+ /// <summary>
+ /// Resolves a Jellyfin resource culture code (which may use underscores, e.g. <c>es_419</c>)
+ /// to a <see cref="CultureInfo"/>. Returns <see langword="false"/> for codes .NET cannot resolve.
+ /// </summary>
+ private static bool TryGetCultureInfo(string cultureCode, [NotNullWhen(true)] out CultureInfo? cultureInfo)
+ {
+ try
+ {
+ // Resource files use underscores for some variants (e.g. es_419);
+ // CultureInfo only accepts hyphenated BCP-47 codes.
+ cultureInfo = CultureInfo.GetCultureInfo(cultureCode.Replace('_', '-'));
+ return true;
+ }
+ catch (CultureNotFoundException)
+ {
+ cultureInfo = null;
+ return false;
+ }
+ }
+
+ private static void OnConfigurationUpdated(object? sender, EventArgs e)
+ {
+ if (sender is IServerConfigurationManager configManager)
+ {
+ var uiCulture = configManager.Configuration.UICulture;
+ if (!string.IsNullOrEmpty(uiCulture))
+ {
+ CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(uiCulture);
+ }
+ }
}
/// <summary>
@@ -420,6 +483,12 @@ namespace Emby.Server.Implementations.Localization
/// <inheritdoc />
public string GetLocalizedString(string phrase)
{
+ return GetLocalizedString(phrase, CultureInfo.CurrentUICulture.Name);
+ }
+
+ /// <inheritdoc />
+ public string GetServerLocalizedString(string phrase)
+ {
return GetLocalizedString(phrase, _configurationManager.Configuration.UICulture);
}
@@ -436,6 +505,12 @@ namespace Emby.Server.Implementations.Localization
culture = DefaultCulture;
}
+ // Normalize BCP-47 hyphenated codes to Jellyfin's underscore-based codes
+ if (_bcp47ToJellyfinMap.TryGetValue(culture, out var mapped))
+ {
+ culture = mapped;
+ }
+
var dictionary = GetLocalizationDictionary(culture);
if (dictionary.TryGetValue(phrase, out var value))
@@ -443,6 +518,15 @@ namespace Emby.Server.Implementations.Localization
return value;
}
+ if (!string.Equals(culture, DefaultCulture, StringComparison.OrdinalIgnoreCase))
+ {
+ var fallback = GetLocalizationDictionary(DefaultCulture);
+ if (fallback.TryGetValue(phrase, out var fallbackValue))
+ {
+ return fallbackValue;
+ }
+ }
+
return phrase;
}
@@ -450,26 +534,17 @@ namespace Emby.Server.Implementations.Localization
{
ArgumentException.ThrowIfNullOrEmpty(culture);
- const string Prefix = "Core";
-
- return _dictionaries.GetOrAdd(
+ return _cultureOnlyDictionaries.GetOrAdd(
culture,
- static (key, localizationManager) => localizationManager.GetDictionary(Prefix, key, DefaultCulture + ".json").GetAwaiter().GetResult(),
- this);
- }
-
- private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename)
- {
- ArgumentException.ThrowIfNullOrEmpty(culture);
-
- var dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- var namespaceName = GetType().Namespace + "." + prefix;
-
- await CopyInto(dictionary, namespaceName + "." + baseFilename).ConfigureAwait(false);
- await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)).ConfigureAwait(false);
+ static (key, localizationManager) =>
+ {
+ var dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ var namespaceName = localizationManager.GetType().Namespace + ".Core";
+ localizationManager.CopyInto(dictionary, namespaceName + "." + GetResourceFilename(key)).GetAwaiter().GetResult();
- return dictionary;
+ return dictionary;
+ },
+ this);
}
private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath)
@@ -508,77 +583,55 @@ namespace Emby.Server.Implementations.Localization
/// <inheritdoc />
public IEnumerable<LocalizationOption> GetLocalizationOptions()
{
- yield return new LocalizationOption("Afrikaans", "af");
- yield return new LocalizationOption("العربية", "ar");
- yield return new LocalizationOption("Беларуская", "be");
- yield return new LocalizationOption("Български", "bg-BG");
- yield return new LocalizationOption("বাংলা (বাংলাদেশ)", "bn");
- yield return new LocalizationOption("Català", "ca");
- yield return new LocalizationOption("Čeština", "cs");
- yield return new LocalizationOption("Cymraeg", "cy");
- yield return new LocalizationOption("Dansk", "da");
- yield return new LocalizationOption("Deutsch", "de");
- yield return new LocalizationOption("English (United Kingdom)", "en-GB");
- yield return new LocalizationOption("English", "en-US");
- yield return new LocalizationOption("Ελληνικά", "el");
- yield return new LocalizationOption("Esperanto", "eo");
- yield return new LocalizationOption("Español", "es");
- yield return new LocalizationOption("Español americano", "es_419");
- yield return new LocalizationOption("Español (Argentina)", "es-AR");
- yield return new LocalizationOption("Español (Dominicana)", "es_DO");
- yield return new LocalizationOption("Español (México)", "es-MX");
- yield return new LocalizationOption("Eesti", "et");
- yield return new LocalizationOption("Basque", "eu");
- yield return new LocalizationOption("فارسی", "fa");
- yield return new LocalizationOption("Suomi", "fi");
- yield return new LocalizationOption("Filipino", "fil");
- yield return new LocalizationOption("Français", "fr");
- yield return new LocalizationOption("Français (Canada)", "fr-CA");
- yield return new LocalizationOption("Galego", "gl");
- yield return new LocalizationOption("Schwiizerdütsch", "gsw");
- yield return new LocalizationOption("עִבְרִית", "he");
- yield return new LocalizationOption("हिन्दी", "hi");
- yield return new LocalizationOption("Hrvatski", "hr");
- yield return new LocalizationOption("Magyar", "hu");
- yield return new LocalizationOption("Bahasa Indonesia", "id");
- yield return new LocalizationOption("Íslenska", "is");
- yield return new LocalizationOption("Italiano", "it");
- yield return new LocalizationOption("日本語", "ja");
- yield return new LocalizationOption("Qazaqşa", "kk");
- yield return new LocalizationOption("한국어", "ko");
- yield return new LocalizationOption("Lietuvių", "lt");
- yield return new LocalizationOption("Latviešu", "lv");
- yield return new LocalizationOption("Македонски", "mk");
- yield return new LocalizationOption("മലയാളം", "ml");
- yield return new LocalizationOption("मराठी", "mr");
- yield return new LocalizationOption("Bahasa Melayu", "ms");
- yield return new LocalizationOption("Norsk bokmål", "nb");
- yield return new LocalizationOption("नेपाली", "ne");
- yield return new LocalizationOption("Nederlands", "nl");
- yield return new LocalizationOption("Norsk nynorsk", "nn");
- yield return new LocalizationOption("ਪੰਜਾਬੀ", "pa");
- yield return new LocalizationOption("Polski", "pl");
- yield return new LocalizationOption("Pirate", "pr");
- yield return new LocalizationOption("Português", "pt");
- yield return new LocalizationOption("Português (Brasil)", "pt-BR");
- yield return new LocalizationOption("Português (Portugal)", "pt-PT");
- yield return new LocalizationOption("Românește", "ro");
- yield return new LocalizationOption("Русский", "ru");
- yield return new LocalizationOption("Slovenčina", "sk");
- yield return new LocalizationOption("Slovenščina", "sl-SI");
- yield return new LocalizationOption("Shqip", "sq");
- yield return new LocalizationOption("Српски", "sr");
- yield return new LocalizationOption("Svenska", "sv");
- yield return new LocalizationOption("தமிழ்", "ta");
- yield return new LocalizationOption("తెలుగు", "te");
- yield return new LocalizationOption("ภาษาไทย", "th");
- yield return new LocalizationOption("Türkçe", "tr");
- yield return new LocalizationOption("Українська", "uk");
- yield return new LocalizationOption("اُردُو", "ur_PK");
- yield return new LocalizationOption("Tiếng Việt", "vi");
- yield return new LocalizationOption("汉语 (简体字)", "zh-CN");
- yield return new LocalizationOption("漢語 (繁體字)", "zh-TW");
- yield return new LocalizationOption("廣東話 (香港)", "zh-HK");
+ return _localizationOptions;
+ }
+
+ private static (IReadOnlyList<LocalizationOption> Options, FrozenDictionary<string, string> Bcp47ToJellyfinMap) BuildLocalizationData()
+ {
+ var options = new List<LocalizationOption>();
+ var bcp47Map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ var prefix = CoreResourcePrefix;
+
+ foreach (var resource in _assembly.GetManifestResourceNames())
+ {
+ if (!resource.StartsWith(prefix, StringComparison.Ordinal)
+ || !resource.EndsWith(".json", StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ // Extract culture code from resource name: "...Core.de.json" -> "de", "...Core.pt-BR.json" -> "pt-BR"
+ var code = resource[prefix.Length..^5];
+
+ // Record the BCP-47 → Jellyfin mapping for any resource file using underscores.
+ if (code.Contains('_', StringComparison.Ordinal))
+ {
+ bcp47Map[code.Replace('_', '-')] = code;
+ }
+
+ // Skip the base language file — en-US is added explicitly below
+ if (code.Equals(DefaultCulture, StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ var displayName = GetDisplayName(code);
+ options.Add(new LocalizationOption(displayName, code));
+ }
+
+ // Ensure en-US is always present
+ options.Add(new LocalizationOption("English", DefaultCulture));
+
+ options.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
+ return (options, bcp47Map.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase));
+ }
+
+ private static string GetDisplayName(string cultureCode)
+ {
+ // Custom/novelty codes like "pr" (Pirate) — fall back to code itself
+ return TryGetCultureInfo(cultureCode, out var cultureInfo)
+ ? cultureInfo.NativeName
+ : cultureCode;
}
/// <inheritdoc />
diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs
index 2f53784db1..cfc8be28ae 100644
--- a/Jellyfin.Api/Controllers/FilterController.cs
+++ b/Jellyfin.Api/Controllers/FilterController.cs
@@ -8,6 +8,8 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@@ -24,16 +26,19 @@ public class FilterController : BaseJellyfinApiController
{
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="FilterController"/> class.
/// </summary>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
- public FilterController(ILibraryManager libraryManager, IUserManager userManager)
+ /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
+ public FilterController(ILibraryManager libraryManager, IUserManager userManager, ILocalizationManager localization)
{
_libraryManager = libraryManager;
_userManager = userManager;
+ _localization = localization;
}
/// <summary>
@@ -183,6 +188,36 @@ public class FilterController : BaseJellyfinApiController
}).ToArray();
}
+ if (includeItemTypes.Contains(BaseItemKind.Movie) || includeItemTypes.Contains(BaseItemKind.Series))
+ {
+ filters.AudioLanguages = _libraryManager
+ .GetMediaStreamLanguages(MediaStreamType.Audio)
+ .Select(language =>
+ {
+ var culture = _localization.FindLanguageInfo(language);
+ return new NameValuePair
+ {
+ Name = culture is null ? language : $"{culture.DisplayName} ({language})",
+ Value = language
+ };
+ })
+ .OrderBy(l => l.Name)
+ .ToArray();
+ filters.SubtitleLanguages = _libraryManager
+ .GetMediaStreamLanguages(MediaStreamType.Subtitle)
+ .Select(language =>
+ {
+ var culture = _localization.FindLanguageInfo(language);
+ return new NameValuePair
+ {
+ Name = culture is null ? language : $"{culture.DisplayName} ({language})",
+ Value = language
+ };
+ })
+ .OrderBy(l => l.Name)
+ .ToArray();
+ }
+
return filters;
}
}
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index e6ba4e7f29..43e4737694 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -157,6 +157,8 @@ public class ItemsController : BaseJellyfinApiController
/// <param name="nameLessThan">Optional filter by items whose name is equally or lesser than a given input string.</param>
/// <param name="studioIds">Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.</param>
/// <param name="genreIds">Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.</param>
+ /// <param name="audioLanguages">Optional. If specified, results will be filtered based on audio language. This allows multiple, comma delimited values.</param>
+ /// <param name="subtitleLanguages">Optional. If specified, results will be filtered based on subtitle language. This allows multiple, comma delimited values.</param>
/// <param name="enableTotalRecordCount">Optional. Enable the total record count.</param>
/// <param name="enableImages">Optional, include image information in output.</param>
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
@@ -247,6 +249,8 @@ public class ItemsController : BaseJellyfinApiController
[FromQuery] string? nameLessThan,
[FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds,
[FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] audioLanguages,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] subtitleLanguages,
[FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true)
{
@@ -399,6 +403,8 @@ public class ItemsController : BaseJellyfinApiController
MinDateLastSavedForUser = minDateLastSavedForUser?.ToUniversalTime(),
MinPremiereDate = minPremiereDate?.ToUniversalTime(),
MaxPremiereDate = maxPremiereDate?.ToUniversalTime(),
+ AudioLanguages = audioLanguages,
+ SubtitleLanguages = subtitleLanguages,
};
if (ids.Length != 0 || !string.IsNullOrWhiteSpace(searchTerm))
@@ -406,6 +412,33 @@ public class ItemsController : BaseJellyfinApiController
query.CollapseBoxSetItems = false;
}
+ if (query.SubtitleLanguages.Count > 0 && query.HasSubtitles.HasValue)
+ {
+ if (query.HasSubtitles.Value)
+ {
+ // if we check for specific subtitles we don't need a separate check for subtitle existence
+ query.HasSubtitles = null;
+ }
+ else
+ {
+ // if we search for items without subtitles, we don't need to check for subtitles of a specific language
+ query.SubtitleLanguages = [];
+ }
+ }
+
+ // for filter values that rely on media streams, we need to include alternative and linked versions
+ if (query.HasSubtitles.HasValue
+ || query.SubtitleLanguages.Count > 0
+ || query.AudioLanguages.Count > 0
+ || query.Is3D.HasValue
+ || query.IsHD.HasValue
+ || query.Is4K.HasValue
+ || query.VideoTypes.Length > 0
+ )
+ {
+ query.IncludeOwnedItems = true;
+ }
+
query.ApplyFilters(filters);
// Filter by Series Status
@@ -785,6 +818,8 @@ public class ItemsController : BaseJellyfinApiController
nameLessThan,
studioIds,
genreIds,
+ [],
+ [],
enableTotalRecordCount,
enableImages).ConfigureAwait(false);
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 69c17f2486..abf27b7702 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -47,6 +47,7 @@ namespace Jellyfin.Api.Controllers;
public class LibraryController : BaseJellyfinApiController
{
private readonly IProviderManager _providerManager;
+ private readonly ISimilarItemsManager _similarItemsManager;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDtoService _dtoService;
@@ -60,6 +61,7 @@ public class LibraryController : BaseJellyfinApiController
/// Initializes a new instance of the <see cref="LibraryController"/> class.
/// </summary>
/// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
+ /// <param name="similarItemsManager">Instance of the <see cref="ISimilarItemsManager"/> interface.</param>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
@@ -70,6 +72,7 @@ public class LibraryController : BaseJellyfinApiController
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
public LibraryController(
IProviderManager providerManager,
+ ISimilarItemsManager similarItemsManager,
ILibraryManager libraryManager,
IUserManager userManager,
IDtoService dtoService,
@@ -80,6 +83,7 @@ public class LibraryController : BaseJellyfinApiController
IServerConfigurationManager serverConfigurationManager)
{
_providerManager = providerManager;
+ _similarItemsManager = similarItemsManager;
_libraryManager = libraryManager;
_userManager = userManager;
_dtoService = dtoService;
@@ -708,6 +712,7 @@ public class LibraryController : BaseJellyfinApiController
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
/// <param name="limit">Optional. The maximum number of records to return.</param>
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <response code="200">Similar items returned.</response>
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> containing the similar items.</returns>
[HttpGet("Artists/{itemId}/Similar", Name = "GetSimilarArtists")]
@@ -718,12 +723,13 @@ public class LibraryController : BaseJellyfinApiController
[HttpGet("Trailers/{itemId}/Similar", Name = "GetSimilarTrailers")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetSimilarItems(
+ public async Task<ActionResult<QueryResult<BaseItemDto>>> GetSimilarItems(
[FromRoute, Required] Guid itemId,
[FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
- [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields)
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields,
+ CancellationToken cancellationToken)
{
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
@@ -746,57 +752,22 @@ public class LibraryController : BaseJellyfinApiController
var dtoOptions = new DtoOptions { Fields = fields };
- var program = item as IHasProgramAttributes;
- bool? isMovie = item is Movie || (program is not null && program.IsMovie) || item is Trailer;
- bool? isSeries = item is Series || (program is not null && program.IsSeries);
+ // Get library options for provider configuration
+ var libraryOptions = _libraryManager.GetLibraryOptions(item);
- var includeItemTypes = new List<BaseItemKind>();
- if (isMovie.Value)
- {
- includeItemTypes.Add(BaseItemKind.Movie);
- if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
- {
- includeItemTypes.Add(BaseItemKind.Trailer);
- includeItemTypes.Add(BaseItemKind.LiveTvProgram);
- }
- }
- else if (isSeries.Value)
- {
- includeItemTypes.Add(BaseItemKind.Series);
- }
- else
- {
- // For non series and movie types these columns are typically null
- // isSeries = null;
- isMovie = null;
- includeItemTypes.Add(item.GetBaseItemKind());
- }
-
- var query = new InternalItemsQuery(user)
- {
- Genres = item.Genres,
- Tags = item.Tags,
- Limit = limit,
- IncludeItemTypes = includeItemTypes.ToArray(),
- DtoOptions = dtoOptions,
- EnableTotalRecordCount = !isMovie ?? true,
- EnableGroupByMetadataKey = isMovie ?? false,
- ExcludeItemIds = [itemId],
- OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
- };
-
- // ExcludeArtistIds
- if (excludeArtistIds.Length != 0)
- {
- query.ExcludeArtistIds = excludeArtistIds;
- }
-
- var itemsResult = _libraryManager.GetItemList(query);
+ var itemsResult = await _similarItemsManager.GetSimilarItemsAsync(
+ item,
+ excludeArtistIds,
+ user,
+ dtoOptions,
+ limit,
+ libraryOptions,
+ cancellationToken).ConfigureAwait(false);
var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
return new QueryResult<BaseItemDto>(
- query.StartIndex,
+ 0,
itemsResult.Count,
returnList);
}
@@ -907,6 +878,17 @@ public class LibraryController : BaseJellyfinApiController
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.ToArray(),
+ SimilarItemProviders = plugins
+ .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
+ .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.LocalSimilarityProvider || p.Type == MetadataPluginType.SimilarityProvider))
+ .Select(i => new LibraryOptionInfoDto
+ {
+ Name = i.Name,
+ DefaultEnabled = i.Type == MetadataPluginType.LocalSimilarityProvider
+ })
+ .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .ToArray(),
+
SupportedImageTypes = plugins
.Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
.SelectMany(i => i.SupportedImageTypes ?? Array.Empty<ImageType>())
@@ -935,11 +917,11 @@ public class LibraryController : BaseJellyfinApiController
try
{
await _activityManager.CreateAsync(new ActivityLog(
- string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name),
+ string.Format(CultureInfo.InvariantCulture, _localization.GetServerLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name),
"UserDownloadingContent",
User.GetUserId())
{
- ShortOverview = string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("AppDeviceValues"), User.GetClient(), User.GetDevice()),
+ ShortOverview = string.Format(CultureInfo.InvariantCulture, _localization.GetServerLocalizedString("AppDeviceValues"), User.GetClient(), User.GetDevice()),
ItemId = item.Id.ToString("N", CultureInfo.InvariantCulture)
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs
index e2075c2b8d..121db66858 100644
--- a/Jellyfin.Api/Controllers/TrailersController.cs
+++ b/Jellyfin.Api/Controllers/TrailersController.cs
@@ -115,6 +115,8 @@ public class TrailersController : BaseJellyfinApiController
/// <param name="nameLessThan">Optional filter by items whose name is equally or lesser than a given input string.</param>
/// <param name="studioIds">Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.</param>
/// <param name="genreIds">Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.</param>
+ /// <param name="audioLanguages">Optional. If specified, results will be filtered based on audio language. This allows multiple, comma delimited values.</param>
+ /// <param name="subtitleLanguages">Optional. If specified, results will be filtered based on subtitale language. This allows multiple, comma delimited values.</param>
/// <param name="enableTotalRecordCount">Optional. Enable the total record count.</param>
/// <param name="enableImages">Optional, include image information in output.</param>
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the trailers.</returns>
@@ -203,6 +205,8 @@ public class TrailersController : BaseJellyfinApiController
[FromQuery] string? nameLessThan,
[FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds,
[FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] audioLanguages,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] subtitleLanguages,
[FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true)
{
@@ -294,6 +298,8 @@ public class TrailersController : BaseJellyfinApiController
nameLessThan,
studioIds,
genreIds,
+ audioLanguages,
+ subtitleLanguages,
enableTotalRecordCount,
enableImages).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Models/LibraryDtos/LibraryTypeOptionsDto.cs b/Jellyfin.Api/Models/LibraryDtos/LibraryTypeOptionsDto.cs
index f76c4a9678..98da6c8f44 100644
--- a/Jellyfin.Api/Models/LibraryDtos/LibraryTypeOptionsDto.cs
+++ b/Jellyfin.Api/Models/LibraryDtos/LibraryTypeOptionsDto.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@@ -18,20 +17,25 @@ public class LibraryTypeOptionsDto
/// <summary>
/// Gets or sets the metadata fetchers.
/// </summary>
- public IReadOnlyList<LibraryOptionInfoDto> MetadataFetchers { get; set; } = Array.Empty<LibraryOptionInfoDto>();
+ public IReadOnlyList<LibraryOptionInfoDto> MetadataFetchers { get; set; } = [];
/// <summary>
/// Gets or sets the image fetchers.
/// </summary>
- public IReadOnlyList<LibraryOptionInfoDto> ImageFetchers { get; set; } = Array.Empty<LibraryOptionInfoDto>();
+ public IReadOnlyList<LibraryOptionInfoDto> ImageFetchers { get; set; } = [];
+
+ /// <summary>
+ /// Gets or sets the similar item providers.
+ /// </summary>
+ public IReadOnlyList<LibraryOptionInfoDto> SimilarItemProviders { get; set; } = [];
/// <summary>
/// Gets or sets the supported image types.
/// </summary>
- public IReadOnlyList<ImageType> SupportedImageTypes { get; set; } = Array.Empty<ImageType>();
+ public IReadOnlyList<ImageType> SupportedImageTypes { get; set; } = [];
/// <summary>
/// Gets or sets the default image options.
/// </summary>
- public IReadOnlyList<ImageOption> DefaultImageOptions { get; set; } = Array.Empty<ImageOption>();
+ public IReadOnlyList<ImageOption> DefaultImageOptions { get; set; } = [];
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs
index 5f4864e953..cfd1cbe05b 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Library/LyricDownloadFailureLogger.cs
@@ -37,7 +37,7 @@ public class LyricDownloadFailureLogger : IEventConsumer<LyricDownloadFailureEve
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LyricDownloadFailureFromForItem"),
+ _localizationManager.GetServerLocalizedString("LyricDownloadFailureFromForItem"),
eventArgs.Provider,
GetItemName(eventArgs.Item)),
"LyricDownloadFailure",
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs
index 8fe380e4f4..24146210c6 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs
@@ -37,7 +37,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Library
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
+ _localizationManager.GetServerLocalizedString("SubtitleDownloadFailureFromForItem"),
eventArgs.Provider,
GetItemName(eventArgs.Item)),
"SubtitleDownloadFailure",
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs
index 1a8931a6dc..df526977a2 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs
@@ -35,7 +35,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("FailedLoginAttemptWithUserName"),
+ _localizationManager.GetServerLocalizedString("FailedLoginAttemptWithUserName"),
eventArgs.Username),
"AuthenticationFailed",
Guid.Empty)
@@ -43,7 +43,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security
LogSeverity = LogLevel.Error,
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LabelIpAddressValue"),
+ _localizationManager.GetServerLocalizedString("LabelIpAddressValue"),
eventArgs.RemoteEndPoint),
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs
index 584d559e44..fa9ce21170 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs
@@ -33,14 +33,14 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("AuthenticationSucceededWithUserName"),
+ _localizationManager.GetServerLocalizedString("AuthenticationSucceededWithUserName"),
eventArgs.User.Name),
"AuthenticationSucceeded",
eventArgs.User.Id)
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LabelIpAddressValue"),
+ _localizationManager.GetServerLocalizedString("LabelIpAddressValue"),
eventArgs.SessionInfo?.RemoteEndPoint),
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs
index 73323acb37..8f71966b83 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs
@@ -61,7 +61,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"),
+ _localizationManager.GetServerLocalizedString("UserStartedPlayingItemWithValues"),
user.Username,
GetItemName(eventArgs.MediaInfo),
eventArgs.DeviceName),
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs
index b75567539c..09d68e4451 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs
@@ -69,7 +69,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserStoppedPlayingItemWithValues"),
+ _localizationManager.GetServerLocalizedString("UserStoppedPlayingItemWithValues"),
user.Username,
GetItemName(item),
eventArgs.DeviceName),
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs
index b90708a2f2..74dfeebba6 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs
@@ -38,7 +38,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserOfflineFromDevice"),
+ _localizationManager.GetServerLocalizedString("UserOfflineFromDevice"),
eventArgs.Argument.UserName,
eventArgs.Argument.DeviceName),
"SessionEnded",
@@ -46,7 +46,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LabelIpAddressValue"),
+ _localizationManager.GetServerLocalizedString("LabelIpAddressValue"),
eventArgs.Argument.RemoteEndPoint),
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs
index 139c2e2acb..4028522838 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs
@@ -38,7 +38,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserOnlineFromDevice"),
+ _localizationManager.GetServerLocalizedString("UserOnlineFromDevice"),
eventArgs.Argument.UserName,
eventArgs.Argument.DeviceName),
"SessionStarted",
@@ -46,7 +46,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LabelIpAddressValue"),
+ _localizationManager.GetServerLocalizedString("LabelIpAddressValue"),
eventArgs.Argument.RemoteEndPoint)
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs
index da82a3b30f..1e3dc7c92e 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs
@@ -47,7 +47,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.System
var time = result.EndTimeUtc - result.StartTimeUtc;
var runningTime = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("LabelRunningTimeValue"),
+ _localizationManager.GetServerLocalizedString("LabelRunningTimeValue"),
ToUserFriendlyString(time));
if (result.Status == TaskCompletionStatus.Failed)
@@ -65,7 +65,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.System
}
await _activityManager.CreateAsync(new ActivityLog(
- string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
+ string.Format(CultureInfo.InvariantCulture, _localizationManager.GetServerLocalizedString("ScheduledTaskFailedWithName"), task.Name),
NotificationType.TaskFailed.ToString(),
Guid.Empty)
{
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs
index 632f30c7ad..9fb007aca7 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs
@@ -35,14 +35,14 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("NameInstallFailed"),
+ _localizationManager.GetServerLocalizedString("NameInstallFailed"),
eventArgs.InstallationInfo.Name),
NotificationType.InstallationFailed.ToString(),
Guid.Empty)
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("VersionNumber"),
+ _localizationManager.GetServerLocalizedString("VersionNumber"),
eventArgs.InstallationInfo.Version),
Overview = eventArgs.Exception.Message
}).ConfigureAwait(false);
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs
index 4b49b714cf..2aa738c153 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs
@@ -35,14 +35,14 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("PluginInstalledWithName"),
+ _localizationManager.GetServerLocalizedString("PluginInstalledWithName"),
eventArgs.Argument.Name),
NotificationType.PluginInstalled.ToString(),
Guid.Empty)
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("VersionNumber"),
+ _localizationManager.GetServerLocalizedString("VersionNumber"),
eventArgs.Argument.Version)
}).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs
index 2d24de7fc6..f7e651173d 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs
@@ -35,7 +35,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("PluginUninstalledWithName"),
+ _localizationManager.GetServerLocalizedString("PluginUninstalledWithName"),
eventArgs.Argument.Name),
NotificationType.PluginUninstalled.ToString(),
Guid.Empty))
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs
index e892d3dd9a..bca9662839 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs
@@ -35,14 +35,14 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("PluginUpdatedWithName"),
+ _localizationManager.GetServerLocalizedString("PluginUpdatedWithName"),
eventArgs.Argument.Name),
NotificationType.PluginUpdateInstalled.ToString(),
Guid.Empty)
{
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("VersionNumber"),
+ _localizationManager.GetServerLocalizedString("VersionNumber"),
eventArgs.Argument.Version),
Overview = eventArgs.Argument.Changelog
}).ConfigureAwait(false);
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs
index 4f063f6a1b..cf5c81b981 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs
@@ -33,7 +33,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserCreatedWithName"),
+ _localizationManager.GetServerLocalizedString("UserCreatedWithName"),
eventArgs.Argument.Username),
"UserCreated",
eventArgs.Argument.Id))
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs
index ba4a072e84..720480c28f 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs
@@ -34,7 +34,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserDeletedWithName"),
+ _localizationManager.GetServerLocalizedString("UserDeletedWithName"),
eventArgs.Argument.Username),
"UserDeleted",
Guid.Empty))
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs
index bbc00567d1..efaf19397f 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs
@@ -35,7 +35,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserLockedOutWithName"),
+ _localizationManager.GetServerLocalizedString("UserLockedOutWithName"),
eventArgs.Argument.Username),
NotificationType.UserLockedOut.ToString(),
eventArgs.Argument.Id)
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs
index 7219704ec6..cc9efa7061 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs
@@ -33,7 +33,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
await _activityManager.CreateAsync(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
- _localizationManager.GetLocalizedString("UserPasswordChangedWithName"),
+ _localizationManager.GetServerLocalizedString("UserPasswordChangedWithName"),
eventArgs.Argument.Username),
"UserPasswordChanged",
eventArgs.Argument.Id))
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
index 59e61cfd65..624b1b561c 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.TranslateQuery.cs
@@ -824,6 +824,26 @@ public sealed partial class BaseItemRepository
}
}
+ if (filter.SubtitleLanguages.Count > 0)
+ {
+ var foldersWithSubtitles = DescendantQueryHelper.GetFolderIdsMatching(context, new HasMediaStreamType(MediaStreamTypeEntity.Subtitle, filter.SubtitleLanguages));
+ baseQuery = baseQuery
+ .Where(e =>
+ (!e.IsFolder && e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle
+ && (filter.SubtitleLanguages.Contains(f.Language) || (filter.SubtitleLanguages.Contains("und") && string.IsNullOrEmpty(f.Language)))))
+ || (e.IsFolder && foldersWithSubtitles.Contains(e.Id)));
+ }
+
+ if (filter.AudioLanguages.Count > 0)
+ {
+ var foldersWithAudio = DescendantQueryHelper.GetFolderIdsMatching(context, new HasMediaStreamType(MediaStreamTypeEntity.Audio, filter.AudioLanguages));
+ baseQuery = baseQuery
+ .Where(e =>
+ (!e.IsFolder && e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Audio
+ && (filter.AudioLanguages.Contains(f.Language) || (filter.AudioLanguages.Contains("und") && string.IsNullOrEmpty(f.Language)))))
+ || (e.IsFolder && foldersWithAudio.Contains(e.Id)));
+ }
+
if (filter.HasChapterImages.HasValue)
{
var hasChapterImages = filter.HasChapterImages.Value;
@@ -953,6 +973,17 @@ public sealed partial class BaseItemRepository
}
}
+ if (filter.HasAnyProviderIds is not null && filter.HasAnyProviderIds.Count > 0)
+ {
+ var includeAny = filter.HasAnyProviderIds
+ .SelectMany(kvp => kvp.Value.Select(v => $"{kvp.Key}:{v}"))
+ .ToArray();
+ if (includeAny.Length > 0)
+ {
+ baseQuery = baseQuery.Where(e => e.Provider!.Select(f => f.ProviderId + ":" + f.ProviderValue)!.Any(f => includeAny.Contains(f)));
+ }
+ }
+
if (filter.HasImdbId.HasValue)
{
baseQuery = filter.HasImdbId.Value
@@ -1057,8 +1088,12 @@ public sealed partial class BaseItemRepository
if (filter.VideoTypes.Length > 0)
{
+ // Dvds and Blu-rays can either be stored in a folder structure or as an iso file
+ // => to find all matches we need to check both: VideoType and IsoType
+ // alternatively, we could provide specific IsoType filters
var videoTypeBs = filter.VideoTypes.Select(vt => $"\"VideoType\":\"{vt}\"").ToArray();
- Expression<Func<BaseItemEntity, bool>> hasVideoType = e => videoTypeBs.Any(f => e.Data!.Contains(f));
+ var isoTypeBs = filter.VideoTypes.Select(vt => $"\"IsoType\":\"{vt}\"").ToArray();
+ Expression<Func<BaseItemEntity, bool>> hasVideoType = e => videoTypeBs.Any(f => e.Data!.Contains(f)) || isoTypeBs.Any(f => e.Data!.Contains(f));
baseQuery = baseQuery.WhereItemOrDescendantMatches(context, hasVideoType);
}
diff --git a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
index dd0446f49a..7fa33c8639 100644
--- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
@@ -55,6 +55,17 @@ public class MediaStreamRepository : IMediaStreamRepository
return TranslateQuery(context.MediaStreamInfos.AsNoTracking(), filter).AsEnumerable().Select(Map).ToArray();
}
+ /// <inheritdoc />
+ public IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType)
+ {
+ using var context = _dbProvider.CreateDbContext();
+ return context.MediaStreamInfos
+ .Where(e => e.StreamType == (MediaStreamTypeEntity)mediaStreamType)
+ .Select(s => string.IsNullOrEmpty(s.Language) ? "und" : s.Language) // und = undetermined
+ .Distinct()
+ .ToArray();
+ }
+
private string? GetPathToSave(string? path)
{
if (path is null)
diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs
index f6a4ae7d6e..1802440dc4 100644
--- a/Jellyfin.Server/Startup.cs
+++ b/Jellyfin.Server/Startup.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Http;
@@ -6,6 +7,7 @@ using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
using Emby.Server.Implementations.EntryPoints;
+using Emby.Server.Implementations.Localization;
using Jellyfin.Api.Middleware;
using Jellyfin.Database.Implementations;
using Jellyfin.LiveTv.Extensions;
@@ -22,6 +24,7 @@ using MediaBrowser.Controller.Extensions;
using MediaBrowser.XbmcMetadata;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -127,6 +130,25 @@ namespace Jellyfin.Server
services.AddHlsPlaylistGenerator();
services.AddLiveTvServices();
+ var serverUICulture = _serverConfigurationManager.Configuration.UICulture;
+ if (string.IsNullOrEmpty(serverUICulture))
+ {
+ serverUICulture = "en-US";
+ }
+
+ CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(serverUICulture);
+
+ services.Configure<RequestLocalizationOptions>(options =>
+ {
+ var supportedUICultures = LocalizationManager.GetSupportedUICultures();
+ options.SupportedCultures = supportedUICultures;
+ options.SupportedUICultures = supportedUICultures;
+ options.DefaultRequestCulture = new RequestCulture(serverUICulture);
+ options.ApplyCurrentCultureToResponseHeaders = true;
+ options.FallBackToParentCultures = true;
+ options.FallBackToParentUICultures = true;
+ });
+
services.AddHostedService<RecordingsHost>();
services.AddHostedService<AutoDiscoveryHost>();
services.AddHostedService<NfoUserDataSaver>();
@@ -168,6 +190,8 @@ namespace Jellyfin.Server
mainApp.UseCors();
+ mainApp.UseRequestLocalization();
+
if (config.RequireHttps && _serverApplicationHost.ListenWithHttps)
{
mainApp.UseHttpsRedirection();
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index fa82ea8663..1e5b5aa164 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -58,6 +58,8 @@ namespace MediaBrowser.Controller.Entities
VideoTypes = [];
Years = [];
SkipDeserialization = false;
+ AudioLanguages = [];
+ SubtitleLanguages = [];
}
public InternalItemsQuery(User? user)
@@ -351,6 +353,8 @@ namespace MediaBrowser.Controller.Entities
public Dictionary<string, string>? HasAnyProviderId { get; set; }
+ public Dictionary<string, string[]>? HasAnyProviderIds { get; set; }
+
public Guid[] AlbumArtistIds { get; set; }
public Guid[] BoxSetLibraryFolders { get; set; }
@@ -385,6 +389,10 @@ namespace MediaBrowser.Controller.Entities
public bool IncludeExtras { get; set; }
+ public IReadOnlyList<string> AudioLanguages { get; set; }
+
+ public IReadOnlyList<string> SubtitleLanguages { get; set; }
+
public void SetUser(User user)
{
var maxRating = user.MaxParentalRatingScore;
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index f5e3d7034e..f4c2196400 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -784,5 +784,12 @@ namespace MediaBrowser.Controller.Library
/// <param name="query">The query filter.</param>
/// <returns>Aggregated filter values.</returns>
QueryFiltersLegacy GetQueryFiltersLegacy(InternalItemsQuery query);
+
+ /// <summary>
+ /// Gets a list of all language codes of the provided stream type.
+ /// </summary>
+ /// <param name="mediaStreamType">The stream type.</param>
+ /// <returns>List of language codes.</returns>
+ IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType);
}
}
diff --git a/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs b/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs
new file mode 100644
index 0000000000..b8e41ec810
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Provides similar items from the local library.
+/// Returns fully resolved BaseItems directly - no additional resolution needed.
+/// </summary>
+public interface ILocalSimilarItemsProvider : ISimilarItemsProvider
+{
+ /// <summary>
+ /// Determines whether the provider can handle items of the specified type.
+ /// </summary>
+ /// <param name="itemType">The item type.</param>
+ /// <returns><c>true</c> if the provider handles this item type; otherwise <c>false</c>.</returns>
+ bool Supports(Type itemType);
+
+ /// <summary>
+ /// Gets similar items from the local library.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions, etc.).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>The list of similar items from the library.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+}
+
+/// <summary>
+/// Provides similar items from the local library for a specific item type.
+/// Returns fully resolved BaseItems directly - no additional resolution needed.
+/// </summary>
+/// <typeparam name="TItemType">The type of item this provider handles.</typeparam>
+public interface ILocalSimilarItemsProvider<TItemType> : ILocalSimilarItemsProvider
+ where TItemType : BaseItem
+{
+ /// <summary>
+ /// Gets similar items from the local library.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions, etc.).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>The list of similar items from the library.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ TItemType item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+
+ bool ILocalSimilarItemsProvider.Supports(Type itemType)
+ => typeof(TItemType).IsAssignableFrom(itemType);
+
+ Task<IReadOnlyList<BaseItem>> ILocalSimilarItemsProvider.GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken)
+ => GetSimilarItemsAsync((TItemType)item, query, cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs b/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs
new file mode 100644
index 0000000000..3803e51769
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Provides similar item references from remote/external sources.
+/// Returns lightweight references with ProviderIds that the manager resolves to library items.
+/// </summary>
+public interface IRemoteSimilarItemsProvider : ISimilarItemsProvider
+{
+ /// <summary>
+ /// Determines whether the provider can handle items of the specified type.
+ /// </summary>
+ /// <param name="itemType">The item type.</param>
+ /// <returns><c>true</c> if the provider handles this item type; otherwise <c>false</c>.</returns>
+ bool Supports(Type itemType);
+
+ /// <summary>
+ /// Gets similar item references from an external source as an async stream.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>An async enumerable of similar item references.</returns>
+ IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+}
+
+/// <summary>
+/// Provides similar item references from remote/external sources for a specific item type.
+/// Returns lightweight references with ProviderIds that the manager resolves to library items.
+/// </summary>
+/// <typeparam name="TItemType">The type of item this provider handles.</typeparam>
+public interface IRemoteSimilarItemsProvider<TItemType> : IRemoteSimilarItemsProvider
+ where TItemType : BaseItem
+{
+ /// <summary>
+ /// Gets similar item references from an external source as an async stream.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>An async enumerable of similar item references.</returns>
+ IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ TItemType item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+
+ bool IRemoteSimilarItemsProvider.Supports(Type itemType)
+ => typeof(TItemType).IsAssignableFrom(itemType);
+
+ IAsyncEnumerable<SimilarItemReference> IRemoteSimilarItemsProvider.GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken)
+ => GetSimilarItemsAsync((TItemType)item, query, cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/ISimilarItemsManager.cs b/MediaBrowser.Controller/Library/ISimilarItemsManager.cs
new file mode 100644
index 0000000000..0ced6f71ee
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ISimilarItemsManager.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Database.Implementations.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Interface for managing similar items providers and operations.
+/// </summary>
+public interface ISimilarItemsManager
+{
+ /// <summary>
+ /// Registers similar items providers discovered through dependency injection.
+ /// </summary>
+ /// <param name="providers">The similar items providers to register.</param>
+ void AddParts(IEnumerable<ISimilarItemsProvider> providers);
+
+ /// <summary>
+ /// Gets the similar items providers for a specific item type.
+ /// </summary>
+ /// <typeparam name="T">The item type.</typeparam>
+ /// <returns>The list of similar items providers for that type.</returns>
+ IReadOnlyList<ISimilarItemsProvider> GetSimilarItemsProviders<T>()
+ where T : BaseItem;
+
+ /// <summary>
+ /// Gets similar items for the specified item.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="excludeArtistIds">Artist IDs to exclude from results.</param>
+ /// <param name="user">The user context.</param>
+ /// <param name="dtoOptions">The DTO options.</param>
+ /// <param name="limit">Maximum number of results.</param>
+ /// <param name="libraryOptions">The library options for provider configuration.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The list of similar items.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ BaseItem item,
+ IReadOnlyList<Guid> excludeArtistIds,
+ User? user,
+ DtoOptions dtoOptions,
+ int? limit,
+ LibraryOptions? libraryOptions,
+ CancellationToken cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs b/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs
new file mode 100644
index 0000000000..0d089369a8
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs
@@ -0,0 +1,26 @@
+using System;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Base marker interface for similar items providers.
+/// </summary>
+public interface ISimilarItemsProvider
+{
+ /// <summary>
+ /// Gets the name of the provider.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the type of the provider.
+ /// </summary>
+ MetadataPluginType Type { get; }
+
+ /// <summary>
+ /// Gets the cache duration for results from this provider.
+ /// If null, results will not be cached.
+ /// </summary>
+ TimeSpan? CacheDuration => null;
+}
diff --git a/MediaBrowser.Controller/Library/SimilarItemReference.cs b/MediaBrowser.Controller/Library/SimilarItemReference.cs
new file mode 100644
index 0000000000..2a40c93bdd
--- /dev/null
+++ b/MediaBrowser.Controller/Library/SimilarItemReference.cs
@@ -0,0 +1,22 @@
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// A reference to a similar item by provider ID with a similarity score.
+/// </summary>
+public class SimilarItemReference
+{
+ /// <summary>
+ /// Gets or sets the provider name (e.g., "Tmdb", "MusicBrainzArtist").
+ /// </summary>
+ public required string ProviderName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the provider ID value.
+ /// </summary>
+ public required string ProviderId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the similarity score (0.0 to 1.0).
+ /// </summary>
+ public float? Score { get; set; }
+}
diff --git a/MediaBrowser.Controller/Library/SimilarItemsQuery.cs b/MediaBrowser.Controller/Library/SimilarItemsQuery.cs
new file mode 100644
index 0000000000..1ed3ceec16
--- /dev/null
+++ b/MediaBrowser.Controller/Library/SimilarItemsQuery.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using Jellyfin.Database.Implementations.Entities;
+using MediaBrowser.Controller.Dto;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Query options for similar items requests.
+/// </summary>
+public class SimilarItemsQuery
+{
+ /// <summary>
+ /// Gets or sets the user context.
+ /// </summary>
+ public User? User { get; set; }
+
+ /// <summary>
+ /// Gets or sets the maximum number of results.
+ /// </summary>
+ public int? Limit { get; set; }
+
+ /// <summary>
+ /// Gets or sets the DTO options.
+ /// </summary>
+ public DtoOptions? DtoOptions { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item IDs to exclude from results.
+ /// </summary>
+ public IReadOnlyList<Guid> ExcludeItemIds { get; set; } = [];
+
+ /// <summary>
+ /// Gets or sets the artist IDs to exclude from results.
+ /// </summary>
+ public IReadOnlyList<Guid> ExcludeArtistIds { get; set; } = [];
+}
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 6b1eac8047..2bcce168cf 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -209,6 +209,11 @@ namespace MediaBrowser.Controller.Net
var (connection, cts, state) = tuple;
var cancellationToken = cts.Token;
+ // Restore the culture context captured when the connection was established
+ // so that GetDataToSendForConnection produces a localized payload matching
+ // the client's Accept-Language preference rather than the server default.
+ connection.ApplyRequestCulture();
+
var data = await GetDataToSendForConnection(connection).ConfigureAwait(false);
if (data is null)
{
diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
index bdc0f9a10f..48431e75c3 100644
--- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
@@ -77,5 +77,14 @@ namespace MediaBrowser.Controller.Net
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task ReceiveAsync(CancellationToken cancellationToken = default);
+
+ /// <summary>
+ /// Applies the culture context captured when the connection was established
+ /// (from the upgrade request's <c>Accept-Language</c> header) to the current
+ /// async flow. Server-initiated message senders should call this before
+ /// localising any payload so that the response uses the client's preferred
+ /// language rather than the server default.
+ /// </summary>
+ void ApplyRequestCulture();
}
}
diff --git a/MediaBrowser.Controller/Persistence/IMediaStreamRepository.cs b/MediaBrowser.Controller/Persistence/IMediaStreamRepository.cs
index 665129eafd..de04ff021d 100644
--- a/MediaBrowser.Controller/Persistence/IMediaStreamRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IMediaStreamRepository.cs
@@ -22,6 +22,13 @@ public interface IMediaStreamRepository
IReadOnlyList<MediaStream> GetMediaStreams(MediaStreamQuery filter);
/// <summary>
+ /// Gets all language codes of the provided stream type.
+ /// </summary>
+ /// <param name="mediaStreamType">The type of the media stream.</param>
+ /// <returns>IEnumerable{string}.</returns>
+ IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType);
+
+ /// <summary>
/// Saves the media streams.
/// </summary>
/// <param name="id">The identifier.</param>
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 0d3a334dfb..c87f09a117 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -144,6 +144,17 @@ namespace MediaBrowser.Controller.Providers
where T : BaseItem;
/// <summary>
+ /// Gets the metadata providers for the provided item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="libraryOptions">The library options.</param>
+ /// <param name="includeDisabled">Whether to include disabled providers.</param>
+ /// <typeparam name="T">The type of metadata provider.</typeparam>
+ /// <returns>The metadata providers.</returns>
+ IEnumerable<IMetadataProvider<T>> GetMetadataProviders<T>(BaseItem item, LibraryOptions libraryOptions, bool includeDisabled)
+ where T : BaseItem;
+
+ /// <summary>
/// Gets the metadata savers for the provided item.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs
index 1ca8e80a6f..57803c9765 100644
--- a/MediaBrowser.Model/Channels/ChannelFeatures.cs
+++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
namespace MediaBrowser.Model.Channels
{
@@ -8,9 +9,9 @@ namespace MediaBrowser.Model.Channels
{
public ChannelFeatures(string name, Guid id)
{
- MediaTypes = Array.Empty<ChannelMediaType>();
- ContentTypes = Array.Empty<ChannelMediaContentType>();
- DefaultSortFields = Array.Empty<ChannelItemSortField>();
+ MediaTypes = [];
+ ContentTypes = [];
+ DefaultSortFields = [];
Name = name;
Id = id;
@@ -38,13 +39,13 @@ namespace MediaBrowser.Model.Channels
/// Gets or sets the media types.
/// </summary>
/// <value>The media types.</value>
- public ChannelMediaType[] MediaTypes { get; set; }
+ public IReadOnlyList<ChannelMediaType> MediaTypes { get; set; }
/// <summary>
/// Gets or sets the content types.
/// </summary>
/// <value>The content types.</value>
- public ChannelMediaContentType[] ContentTypes { get; set; }
+ public IReadOnlyList<ChannelMediaContentType> ContentTypes { get; set; }
/// <summary>
/// Gets or sets the maximum number of records the channel allows retrieving at a time.
@@ -61,7 +62,7 @@ namespace MediaBrowser.Model.Channels
/// Gets or sets the default sort orders.
/// </summary>
/// <value>The default sort orders.</value>
- public ChannelItemSortField[] DefaultSortFields { get; set; }
+ public IReadOnlyList<ChannelItemSortField> DefaultSortFields { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a sort ascending/descending toggle is supported.
diff --git a/MediaBrowser.Model/Configuration/MetadataPluginType.cs b/MediaBrowser.Model/Configuration/MetadataPluginType.cs
index 670d6e3837..476060ceef 100644
--- a/MediaBrowser.Model/Configuration/MetadataPluginType.cs
+++ b/MediaBrowser.Model/Configuration/MetadataPluginType.cs
@@ -15,6 +15,8 @@ namespace MediaBrowser.Model.Configuration
MetadataSaver,
SubtitleFetcher,
LyricFetcher,
- MediaSegmentProvider
+ MediaSegmentProvider,
+ LocalSimilarityProvider,
+ SimilarityProvider
}
}
diff --git a/MediaBrowser.Model/Configuration/TypeOptions.cs b/MediaBrowser.Model/Configuration/TypeOptions.cs
index d0179e5aab..3aa85034e5 100644
--- a/MediaBrowser.Model/Configuration/TypeOptions.cs
+++ b/MediaBrowser.Model/Configuration/TypeOptions.cs
@@ -304,11 +304,13 @@ namespace MediaBrowser.Model.Configuration
public TypeOptions()
{
- MetadataFetchers = Array.Empty<string>();
- MetadataFetcherOrder = Array.Empty<string>();
- ImageFetchers = Array.Empty<string>();
- ImageFetcherOrder = Array.Empty<string>();
- ImageOptions = Array.Empty<ImageOption>();
+ MetadataFetchers = [];
+ MetadataFetcherOrder = [];
+ ImageFetchers = [];
+ ImageFetcherOrder = [];
+ ImageOptions = [];
+ SimilarItemProviders = [];
+ SimilarItemProviderOrder = [];
}
public string Type { get; set; }
@@ -323,6 +325,10 @@ namespace MediaBrowser.Model.Configuration
public ImageOption[] ImageOptions { get; set; }
+ public string[] SimilarItemProviders { get; set; }
+
+ public string[] SimilarItemProviderOrder { get; set; }
+
public ImageOption GetImageOptions(ImageType type)
{
foreach (var i in ImageOptions)
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index f6e65028e4..7ad240abfb 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -51,6 +51,15 @@ public interface ILocalizationManager
string GetLocalizedString(string phrase);
/// <summary>
+ /// Gets the localized string using the server's configured UICulture,
+ /// ignoring the current request's culture. Use this for data that is
+ /// persisted (e.g. activity log entries) rather than returned per-request.
+ /// </summary>
+ /// <param name="phrase">The phrase.</param>
+ /// <returns>System.String.</returns>
+ string GetServerLocalizedString(string phrase);
+
+ /// <summary>
/// Gets the localization options.
/// </summary>
/// <returns><see cref="IEnumerable{LocalizationOption}" />.</returns>
diff --git a/MediaBrowser.Model/Querying/QueryFilters.cs b/MediaBrowser.Model/Querying/QueryFilters.cs
index 73b27a7b06..095f460923 100644
--- a/MediaBrowser.Model/Querying/QueryFilters.cs
+++ b/MediaBrowser.Model/Querying/QueryFilters.cs
@@ -2,6 +2,7 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.Querying
@@ -12,10 +13,16 @@ namespace MediaBrowser.Model.Querying
{
Tags = Array.Empty<string>();
Genres = Array.Empty<NameGuidPair>();
+ AudioLanguages = Array.Empty<NameValuePair>();
+ SubtitleLanguages = Array.Empty<NameValuePair>();
}
- public NameGuidPair[] Genres { get; set; }
+ public IReadOnlyList<NameGuidPair> Genres { get; set; }
- public string[] Tags { get; set; }
+ public IReadOnlyList<string> Tags { get; set; }
+
+ public IReadOnlyList<NameValuePair> AudioLanguages { get; set; }
+
+ public IReadOnlyList<NameValuePair> SubtitleLanguages { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 65edcb2a92..73df6d03d2 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -1,17 +1,20 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AsyncKeyedLock;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Events;
using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.BaseItemManager;
@@ -64,6 +67,7 @@ namespace MediaBrowser.Providers.Manager
private readonly PriorityQueue<(Guid ItemId, MetadataRefreshOptions RefreshOptions), RefreshPriority> _refreshQueue = new();
private readonly IMemoryCache _memoryCache;
private readonly IMediaSegmentManager _mediaSegmentManager;
+ private readonly ISimilarItemsManager _similarItemsManager;
private readonly AsyncKeyedLocker<string> _imageSaveLock = new(o =>
{
o.PoolSize = 20;
@@ -101,6 +105,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="lyricManager">The lyric manager.</param>
/// <param name="memoryCache">The memory cache.</param>
/// <param name="mediaSegmentManager">The media segment manager.</param>
+ /// <param name="similarItemsManager">The similar items manager.</param>
public ProviderManager(
IHttpClientFactory httpClientFactory,
ISubtitleManager subtitleManager,
@@ -113,7 +118,8 @@ namespace MediaBrowser.Providers.Manager
IBaseItemManager baseItemManager,
ILyricManager lyricManager,
IMemoryCache memoryCache,
- IMediaSegmentManager mediaSegmentManager)
+ IMediaSegmentManager mediaSegmentManager,
+ ISimilarItemsManager similarItemsManager)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
@@ -127,6 +133,7 @@ namespace MediaBrowser.Providers.Manager
_lyricManager = lyricManager;
_memoryCache = memoryCache;
_mediaSegmentManager = mediaSegmentManager;
+ _similarItemsManager = similarItemsManager;
CollectionFolder.LibraryOptionsUpdated += OnLibraryOptionsUpdated;
}
@@ -687,6 +694,14 @@ namespace MediaBrowser.Providers.Manager
Type = MetadataPluginType.MediaSegmentProvider
}));
+ // Similar items providers
+ var similarItemsProviders = _similarItemsManager.GetSimilarItemsProviders<T>();
+ pluginList.AddRange(similarItemsProviders.Select(i => new MetadataPlugin
+ {
+ Name = i.Name,
+ Type = i.Type
+ }));
+
summary.Plugins = pluginList.ToArray();
var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index ed0c63b97f..8b727a8cac 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -52,6 +52,12 @@
<EmbeddedResource Include="Plugins\AudioDb\Configuration\config.html" />
<None Remove="Plugins\Omdb\Configuration\config.html" />
<EmbeddedResource Include="Plugins\Omdb\Configuration\config.html" />
+ <None Remove="Plugins\ListenBrainz\Configuration\config.html" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\config.html" />
+ <None Remove="Plugins\ListenBrainz\Configuration\ListenBrainz_logo.svg" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\ListenBrainz_logo.svg" />
+ <None Remove="Plugins\ListenBrainz\Configuration\NOTICE.md" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\NOTICE.md" />
<None Remove="Plugins\MusicBrainz\Configuration\config.html" />
<EmbeddedResource Include="Plugins\MusicBrainz\Configuration\config.html" />
<None Remove="Plugins\StudioImages\Configuration\config.html" />
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs
new file mode 100644
index 0000000000..e080370b8c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api;
+
+/// <summary>
+/// Client for the ListenBrainz Labs API.
+/// </summary>
+public class ListenBrainzLabsClient : IDisposable
+{
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly ILogger<ListenBrainzLabsClient> _logger;
+ private readonly SemaphoreSlim _rateLimitLock = new(1, 1);
+
+ private DateTime _lastRequestTime = DateTime.MinValue;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzLabsClient"/> class.
+ /// </summary>
+ /// <param name="httpClientFactory">The HTTP client factory.</param>
+ /// <param name="logger">The logger.</param>
+ public ListenBrainzLabsClient(
+ IHttpClientFactory httpClientFactory,
+ ILogger<ListenBrainzLabsClient> logger)
+ {
+ _httpClientFactory = httpClientFactory;
+ _logger = logger;
+ }
+
+ /// <summary>
+ /// Gets similar artists for the given MusicBrainz artist ID.
+ /// </summary>
+ /// <param name="artistMbid">The MusicBrainz artist ID.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A list of similar artist MusicBrainz IDs ordered by similarity score.</returns>
+ public async Task<IReadOnlyList<Guid>> GetSimilarArtistsAsync(
+ Guid artistMbid,
+ CancellationToken cancellationToken)
+ {
+ var config = ListenBrainzPlugin.Instance?.Configuration;
+ var baseUrl = config?.LabsServer ?? PluginConfiguration.DefaultLabsServer;
+ var algorithm = config?.AlgorithmString ?? new PluginConfiguration().AlgorithmString;
+ var rateLimit = config?.RateLimit ?? PluginConfiguration.DefaultRateLimit;
+
+ // Enforce rate limit
+ await EnforceRateLimitAsync(rateLimit, cancellationToken).ConfigureAwait(false);
+
+ var url = $"{baseUrl}/similar-artists/json?artist_mbids={artistMbid}&algorithm={algorithm}";
+
+ _logger.LogDebug("Fetching similar artists from ListenBrainz Labs: {Url}", url);
+
+ try
+ {
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
+ var response = await httpClient.GetFromJsonAsync<List<SimilarArtistData>>(url, cancellationToken).ConfigureAwait(false);
+
+ if (response is null || response.Count == 0)
+ {
+ _logger.LogDebug("No similar artists found for {ArtistMbid}", artistMbid);
+ return [];
+ }
+
+ var similarMbids = response
+ .Where(a => !a.ArtistMbid.Equals(artistMbid)) // Exclude the source artist
+ .OrderByDescending(a => a.Score)
+ .Select(a => a.ArtistMbid)
+ .ToList();
+
+ _logger.LogDebug("Found {Count} similar artists for {ArtistMbid}", similarMbids.Count, artistMbid);
+
+ return similarMbids;
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogWarning(ex, "Failed to fetch similar artists from ListenBrainz Labs for {ArtistMbid}", artistMbid);
+ return [];
+ }
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _rateLimitLock.Dispose();
+ }
+ }
+
+ private async Task EnforceRateLimitAsync(double rateLimitSeconds, CancellationToken cancellationToken)
+ {
+ await _rateLimitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ try
+ {
+ var timeSinceLastRequest = DateTime.UtcNow - _lastRequestTime;
+ var requiredDelay = TimeSpan.FromSeconds(rateLimitSeconds) - timeSinceLastRequest;
+
+ if (requiredDelay > TimeSpan.Zero)
+ {
+ await Task.Delay(requiredDelay, cancellationToken).ConfigureAwait(false);
+ }
+
+ _lastRequestTime = DateTime.UtcNow;
+ }
+ finally
+ {
+ _rateLimitLock.Release();
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs
new file mode 100644
index 0000000000..237f33ee3a
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+
+/// <summary>
+/// A similar artist data entry from the ListenBrainz Labs API.
+/// </summary>
+public class SimilarArtistData
+{
+ /// <summary>
+ /// Gets or sets the MusicBrainz artist ID.
+ /// </summary>
+ [JsonPropertyName("artist_mbid")]
+ public Guid ArtistMbid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the artist name.
+ /// </summary>
+ [JsonPropertyName("name")]
+ public string? Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the similarity score.
+ /// </summary>
+ [JsonPropertyName("score")]
+ public double Score { get; set; }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs
new file mode 100644
index 0000000000..12e8f25dcc
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+
+/// <summary>
+/// Response from ListenBrainz Labs similar-artists endpoint.
+/// </summary>
+public class SimilarArtistsResponse
+{
+ /// <summary>
+ /// Gets or sets the list of similar artists.
+ /// </summary>
+ [JsonPropertyName("data")]
+ public IReadOnlyList<SimilarArtistData>? Data { get; set; }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg
new file mode 100644
index 0000000000..416a097f9c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg
@@ -0,0 +1,60 @@
+<svg version="1.2" baseProfile="tiny-ps" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450" width="800" height="450">
+ <title>ListenBrainz_logo-svg</title>
+ <defs>
+ <image width="800" height="450" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAHCAQMAAAAtrT+LAAAAAXNSR0IB2cksfwAAAANQTFRF9tmZzxpnDgAAAENJREFUeJztwYEAAAAAw6D5U1/hAFUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALwGsYoAAQbjkYoAAAAASUVORK5CYII="/>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp1">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp2">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp3">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ </defs>
+ <style>
+ tspan { white-space:pre }
+ .shp0 { fill: #eb743b }
+ .shp1 { fill: #353070 }
+ .shp2 { fill: #000000 }
+ .shp3 { fill: #d3562c }
+ .shp4 { fill: #fffedb }
+ .shp5 { opacity: 0.251;fill: #000000 }
+ </style>
+ <use id="Background" href="#img1" x="0" y="0" />
+ <path id="Layer" class="shp0" d="M173.35 152.82L173.35 296.82L234.35 261.82L234.35 187.82L173.35 152.82Z" />
+ <path id="Layer" class="shp1" d="M168.35 152.82L107.35 187.82L107.35 261.82L168.35 296.82L168.35 152.82Z" />
+ <g id="Layer" style="opacity: 0.071">
+ <g id="Clip-Path" clip-path="url(#cp1)">
+ <path id="Layer" class="shp2" d="M190.66 244.56C190.75 244.4 190.86 244.26 190.99 244.13C191.12 244 191.27 243.89 191.43 243.8C191.59 243.71 191.76 243.64 191.93 243.59C192.11 243.55 192.29 243.53 192.48 243.53C192.85 243.53 193.23 243.63 193.55 243.82C193.79 243.97 194 244.15 194.17 244.38C194.33 244.6 194.45 244.85 194.52 245.12C194.59 245.39 194.6 245.67 194.56 245.94C194.52 246.22 194.43 246.48 194.29 246.72C194.2 246.88 194.08 247.02 193.95 247.15C193.82 247.28 193.68 247.39 193.52 247.48C193.36 247.57 193.19 247.64 193.01 247.69C192.84 247.73 192.65 247.75 192.47 247.75C192.09 247.75 191.72 247.65 191.39 247.45C191.27 247.38 191.16 247.3 191.05 247.21C190.95 247.12 190.86 247.01 190.78 246.9C190.69 246.79 190.62 246.67 190.56 246.55C190.5 246.42 190.46 246.29 190.42 246.16C190.39 246.02 190.37 245.89 190.36 245.75C190.35 245.61 190.36 245.47 190.38 245.33C190.4 245.2 190.43 245.06 190.48 244.93C190.53 244.8 190.59 244.68 190.66 244.56M203.26 266.92C203.05 267.1 202.8 267.24 202.54 267.32C202.28 267.41 202 267.44 201.72 267.42C201.45 267.4 201.18 267.33 200.93 267.2C200.68 267.08 200.46 266.9 200.28 266.69C200.1 266.48 199.96 266.24 199.87 265.97C199.79 265.71 199.76 265.43 199.78 265.16C199.8 264.88 199.87 264.61 200 264.36C200.13 264.11 200.3 263.89 200.51 263.71C200.6 263.63 200.7 263.56 200.81 263.49C200.92 263.43 201.03 263.38 201.15 263.33C201.27 263.29 201.39 263.26 201.51 263.23C201.63 263.21 201.76 263.2 201.88 263.2C202.17 263.2 202.46 263.26 202.73 263.38C203 263.5 203.24 263.67 203.43 263.88C203.63 264.09 203.78 264.35 203.88 264.62C203.98 264.9 204.01 265.19 203.99 265.48C203.98 265.62 203.96 265.75 203.92 265.89C203.88 266.02 203.83 266.15 203.77 266.27C203.71 266.4 203.63 266.51 203.55 266.62C203.46 266.73 203.36 266.83 203.26 266.92M193.73 208.08C193.88 207.85 194.08 207.65 194.3 207.49C194.53 207.33 194.79 207.21 195.06 207.15C195.33 207.09 195.61 207.09 195.88 207.13C196.15 207.18 196.41 207.28 196.65 207.42C196.88 207.57 197.09 207.77 197.25 207.99C197.41 208.22 197.52 208.48 197.58 208.75C197.64 209.02 197.65 209.3 197.6 209.57C197.56 209.85 197.46 210.11 197.31 210.34C197.16 210.58 196.97 210.78 196.74 210.94C196.51 211.1 196.26 211.22 195.99 211.28C195.72 211.34 195.44 211.35 195.16 211.3C194.89 211.25 194.63 211.15 194.39 211C194.16 210.85 193.95 210.66 193.79 210.43C193.63 210.21 193.52 209.95 193.46 209.68C193.4 209.41 193.39 209.13 193.44 208.85C193.49 208.58 193.59 208.32 193.73 208.08ZM200.11 187.89C199.51 188.84 198.18 189.16 197.2 188.55L197.1 188.48C196.89 188.33 196.7 188.13 196.55 187.91C196.41 187.68 196.31 187.43 196.26 187.17C196.21 186.91 196.2 186.64 196.25 186.37C196.3 186.11 196.4 185.86 196.55 185.63C196.64 185.48 196.76 185.35 196.88 185.22C197.01 185.1 197.16 185 197.31 184.91C197.47 184.83 197.63 184.76 197.81 184.72C197.98 184.67 198.15 184.65 198.33 184.65C198.71 184.65 199.08 184.75 199.41 184.95C199.73 185.14 200 185.42 200.18 185.75C200.36 186.08 200.45 186.45 200.44 186.83C200.43 187.21 200.32 187.57 200.11 187.89M216.88 199.49C216.97 199.34 217.09 199.2 217.22 199.08C217.35 198.96 217.49 198.86 217.64 198.77C217.8 198.68 217.97 198.62 218.14 198.58C218.31 198.53 218.49 198.51 218.66 198.51C219.06 198.51 219.45 198.62 219.79 198.84C220.27 199.14 220.6 199.61 220.72 200.17C220.76 200.3 220.77 200.44 220.78 200.58C220.78 200.71 220.77 200.85 220.74 200.99C220.72 201.12 220.68 201.25 220.63 201.38C220.58 201.51 220.52 201.63 220.44 201.75C219.85 202.7 218.51 203.02 217.53 202.4L217.44 202.34C217.22 202.19 217.03 201.99 216.89 201.77C216.74 201.54 216.64 201.29 216.59 201.03C216.54 200.77 216.54 200.49 216.59 200.23C216.64 199.97 216.74 199.72 216.88 199.49M216.88 222.95C216.97 222.8 217.09 222.67 217.22 222.54C217.35 222.42 217.49 222.32 217.64 222.23C217.8 222.15 217.97 222.08 218.14 222.04C218.31 222 218.49 221.97 218.66 221.97C219.06 221.97 219.45 222.09 219.79 222.3C220.27 222.6 220.6 223.07 220.72 223.63C220.76 223.76 220.77 223.9 220.78 224.04C220.78 224.18 220.77 224.31 220.74 224.45C220.72 224.59 220.68 224.72 220.63 224.85C220.58 224.98 220.52 225.1 220.44 225.21C219.85 226.16 218.51 226.48 217.53 225.87L217.44 225.8C217.22 225.65 217.03 225.45 216.89 225.23C216.74 225 216.64 224.75 216.59 224.49C216.54 224.23 216.54 223.96 216.59 223.69C216.64 223.43 216.74 223.18 216.88 222.95M216.88 249.26C216.97 249.11 217.09 248.97 217.22 248.85C217.35 248.73 217.49 248.62 217.64 248.54C217.8 248.45 217.97 248.39 218.14 248.34C218.31 248.3 218.49 248.28 218.66 248.28C219.06 248.28 219.45 248.39 219.79 248.6C220.27 248.91 220.6 249.38 220.72 249.93C220.76 250.07 220.77 250.2 220.78 250.34C220.78 250.48 220.77 250.62 220.74 250.75C220.72 250.89 220.68 251.02 220.63 251.15C220.58 251.28 220.52 251.4 220.44 251.52C219.85 252.47 218.51 252.79 217.53 252.17L217.44 252.11C217.22 251.95 217.03 251.76 216.89 251.53C216.74 251.31 216.64 251.06 216.59 250.79C216.54 250.53 216.54 250.26 216.59 250C216.64 249.73 216.74 249.48 216.88 249.26" />
+ </g>
+ <g id="Clip-Path" clip-path="url(#cp2)">
+ <path id="Layer" fill-rule="evenodd" class="shp2" d="M206.53 258.93C206.79 259.23 207.02 259.56 207.22 259.91C207.42 260.26 207.58 260.63 207.71 261.01C207.83 261.39 207.92 261.78 207.96 262.18C208.01 262.58 208.02 262.98 207.99 263.38C207.96 263.78 207.89 264.17 207.78 264.56C207.67 264.95 207.53 265.32 207.35 265.68C207.17 266.04 206.95 266.38 206.7 266.69C206.45 267.01 206.17 267.3 205.87 267.56C205.59 267.79 205.3 268 204.99 268.19C204.68 268.37 204.35 268.52 204.01 268.65C203.67 268.78 203.32 268.87 202.96 268.94C202.61 269 202.25 269.03 201.89 269.03C201.49 269.03 201.1 268.99 200.71 268.92C200.32 268.84 199.94 268.73 199.57 268.58C199.21 268.43 198.85 268.24 198.52 268.02C198.19 267.81 197.88 267.56 197.6 267.28C195.75 267.98 192.69 269 190.58 269C190.48 269 190.37 269 190.27 269C188.3 268.89 187.03 268.03 186.01 267.34C184.44 266.28 182.95 265.27 177.6 266.63C175.24 267.71 173.63 267.79 173.36 267.82L173.36 263.82C173.86 263.72 174.73 263.55 175.91 263.01C175.94 263 175.97 262.98 176 262.97C176.03 262.95 176.06 262.94 176.09 262.92C176.12 262.91 176.15 262.89 176.18 262.88C176.21 262.87 176.24 262.86 176.27 262.85C179.62 261.24 184.79 257.38 188.84 248.16C188.56 247.95 188.29 247.72 188.05 247.47C187.8 247.22 187.58 246.94 187.39 246.65C187.19 246.36 187.02 246.05 186.88 245.73C186.74 245.41 186.62 245.07 186.54 244.73C186.44 244.34 186.38 243.95 186.36 243.55C186.33 243.15 186.35 242.74 186.41 242.35C186.47 241.95 186.57 241.56 186.7 241.18C186.84 240.8 187.01 240.44 187.22 240.1C187.49 239.64 187.82 239.23 188.19 238.86C188.57 238.49 188.99 238.17 189.45 237.91C189.91 237.65 190.4 237.45 190.91 237.32C191.42 237.18 191.95 237.11 192.48 237.11C192.75 237.11 193.02 237.13 193.3 237.17C193.57 237.2 193.84 237.26 194.1 237.33C194.37 237.4 194.62 237.5 194.88 237.6C195.13 237.71 195.37 237.83 195.61 237.97C198.51 239.71 199.46 243.47 197.73 246.37C197.47 246.8 197.16 247.21 196.79 247.56C196.43 247.92 196.03 248.23 195.59 248.49C195.15 248.75 194.68 248.95 194.2 249.1C193.71 249.24 193.2 249.32 192.69 249.34C190.12 255.34 187.05 259.41 184.11 262.18C185.84 262.51 187.09 263.23 188.26 264.02C189.18 264.65 189.66 264.95 190.48 264.99C191.55 265.03 193.86 264.36 195.81 263.66C195.75 263.16 195.75 262.66 195.81 262.16C195.87 261.66 196 261.17 196.18 260.7C196.36 260.23 196.6 259.79 196.89 259.38C197.18 258.97 197.52 258.59 197.9 258.26C198.51 257.74 199.22 257.34 199.98 257.09C200.74 256.84 201.55 256.74 202.35 256.8C203.15 256.87 203.94 257.08 204.65 257.45C205.37 257.81 206.01 258.32 206.53 258.93ZM190.66 242.15C190.59 242.27 190.53 242.4 190.48 242.53C190.43 242.66 190.4 242.79 190.38 242.93C190.36 243.07 190.35 243.2 190.36 243.34C190.37 243.48 190.39 243.62 190.42 243.75C190.46 243.89 190.5 244.02 190.56 244.14C190.62 244.27 190.69 244.39 190.78 244.5C190.86 244.61 190.95 244.71 191.05 244.8C191.16 244.89 191.27 244.98 191.39 245.05C191.72 245.24 192.09 245.35 192.47 245.35C192.65 245.35 192.84 245.33 193.01 245.28C193.19 245.23 193.36 245.16 193.52 245.07C193.68 244.98 193.82 244.87 193.95 244.75C194.08 244.62 194.2 244.47 194.29 244.32C194.58 243.83 194.66 243.26 194.52 242.71C194.38 242.17 194.04 241.7 193.56 241.42C193.07 241.13 192.5 241.05 191.95 241.18C191.41 241.32 190.94 241.67 190.66 242.15ZM203.26 264.51C203.36 264.42 203.46 264.32 203.55 264.22C203.63 264.11 203.71 263.99 203.77 263.87C203.83 263.74 203.88 263.62 203.92 263.48C203.96 263.35 203.98 263.21 203.99 263.07C204.01 262.78 203.98 262.49 203.88 262.22C203.78 261.94 203.63 261.69 203.43 261.47C203.24 261.26 203 261.09 202.73 260.97C202.46 260.86 202.17 260.8 201.88 260.8C201.76 260.8 201.63 260.81 201.51 260.83C201.39 260.85 201.27 260.88 201.15 260.93C201.03 260.97 200.92 261.02 200.81 261.09C200.7 261.15 200.6 261.23 200.51 261.31C200.3 261.49 200.13 261.71 200 261.96C199.87 262.2 199.8 262.47 199.78 262.75C199.76 263.03 199.79 263.31 199.87 263.57C199.96 263.83 200.1 264.08 200.28 264.29C200.46 264.5 200.68 264.67 200.93 264.8C201.18 264.92 201.45 265 201.72 265.02C202 265.04 202.28 265 202.54 264.92C202.8 264.83 203.05 264.69 203.26 264.51ZM204.3 183.03C204.39 183.42 204.44 183.82 204.45 184.22C204.46 184.62 204.43 185.02 204.36 185.41C204.3 185.8 204.19 186.19 204.04 186.56C203.9 186.94 203.72 187.29 203.5 187.63C203.23 188.07 202.9 188.47 202.52 188.82C202.15 189.17 201.73 189.48 201.28 189.72C200.83 189.97 200.35 190.16 199.85 190.29C199.36 190.42 198.84 190.48 198.33 190.48C198.18 190.48 198.03 190.47 197.88 190.46C197.73 190.45 197.58 190.43 197.43 190.41C197.29 190.39 197.14 190.36 196.99 190.33C196.85 190.29 196.7 190.26 196.56 190.21C194.18 193.04 191.3 194.53 188.78 195.31C190.8 196.86 192.59 198.72 194.12 200.88C195.7 200.52 197.41 200.76 198.79 201.63C201.65 203.44 202.5 207.23 200.7 210.08C200.42 210.52 200.09 210.92 199.72 211.27C199.34 211.63 198.93 211.93 198.47 212.18C198.02 212.43 197.54 212.62 197.04 212.74C196.54 212.87 196.03 212.94 195.52 212.93C194.36 212.93 193.23 212.61 192.25 211.98C189.4 210.18 188.55 206.39 190.34 203.54C190.37 203.49 190.4 203.45 190.43 203.4C190.46 203.36 190.49 203.31 190.53 203.27C190.56 203.22 190.59 203.18 190.62 203.13C190.66 203.09 190.69 203.04 190.72 203C188.45 199.89 185.56 197.52 182.12 195.96C182.11 195.96 182.11 195.96 182.1 195.96C178.91 194.5 175.8 193.96 173.35 193.82L173.35 189.82C176.13 189.98 179.67 190.54 183.36 192.14C184.59 192.16 189.66 191.97 193.3 187.85C192.96 187.36 192.69 186.82 192.51 186.25C192.32 185.68 192.22 185.09 192.21 184.49C192.2 183.89 192.27 183.3 192.43 182.72C192.59 182.14 192.84 181.59 193.16 181.09C193.43 180.65 193.76 180.25 194.13 179.9C194.51 179.55 194.92 179.24 195.38 178.99C195.83 178.74 196.31 178.55 196.81 178.43C197.3 178.3 197.82 178.24 198.33 178.24C198.62 178.24 198.91 178.26 199.19 178.3C199.47 178.34 199.76 178.4 200.03 178.48C200.31 178.56 200.58 178.66 200.84 178.78C201.1 178.89 201.35 179.03 201.6 179.18C201.94 179.4 202.26 179.64 202.55 179.92C202.84 180.2 203.1 180.5 203.34 180.83C203.57 181.16 203.77 181.51 203.93 181.88C204.09 182.25 204.22 182.63 204.3 183.03ZM193.73 205.67C193.59 205.91 193.49 206.17 193.44 206.45C193.39 206.72 193.4 207 193.46 207.27C193.52 207.54 193.63 207.8 193.79 208.03C193.95 208.25 194.16 208.45 194.39 208.6C194.63 208.75 194.89 208.85 195.16 208.89C195.44 208.94 195.72 208.93 195.99 208.87C196.26 208.81 196.51 208.7 196.74 208.54C196.97 208.38 197.16 208.17 197.31 207.94C197.46 207.7 197.56 207.44 197.6 207.17C197.65 206.89 197.64 206.61 197.58 206.34C197.52 206.07 197.41 205.81 197.25 205.59C197.09 205.36 196.88 205.17 196.65 205.02C196.41 204.87 196.15 204.77 195.88 204.73C195.61 204.68 195.33 204.69 195.06 204.75C194.79 204.81 194.53 204.92 194.3 205.08C194.08 205.24 193.88 205.44 193.73 205.67ZM200.11 185.49C200.32 185.17 200.43 184.8 200.44 184.42C200.45 184.05 200.36 183.67 200.18 183.34C200 183.01 199.73 182.73 199.41 182.54C199.08 182.35 198.71 182.25 198.33 182.25C198.15 182.25 197.98 182.27 197.81 182.31C197.63 182.35 197.47 182.42 197.31 182.51C197.16 182.59 197.01 182.7 196.88 182.82C196.76 182.94 196.64 183.08 196.55 183.23C196.4 183.45 196.3 183.7 196.25 183.97C196.2 184.23 196.21 184.5 196.26 184.76C196.31 185.03 196.41 185.28 196.55 185.5C196.7 185.73 196.89 185.92 197.11 186.08L197.2 186.14C198.18 186.76 199.51 186.44 200.11 185.49Z" />
+ </g>
+ <g id="Clip-Path" clip-path="url(#cp3)">
+ <path id="Layer" fill-rule="evenodd" class="shp2" d="M213 224.01C210.76 224.39 209.57 225.15 208.14 226.08C206.98 226.83 205.74 227.64 203.93 228.27C208.47 231.6 214.56 237.87 217.12 242.06C217.52 241.95 217.94 241.89 218.35 241.87C218.77 241.85 219.19 241.87 219.6 241.93C220.01 242 220.42 242.11 220.81 242.25C221.2 242.4 221.58 242.58 221.93 242.81C222.27 243.02 222.59 243.27 222.88 243.55C223.17 243.82 223.44 244.13 223.67 244.46C223.9 244.79 224.1 245.14 224.26 245.51C224.43 245.88 224.55 246.26 224.64 246.65C224.73 247.04 224.78 247.44 224.79 247.84C224.8 248.24 224.77 248.64 224.7 249.03C224.63 249.43 224.52 249.81 224.38 250.19C224.23 250.56 224.05 250.92 223.83 251.25C223.56 251.69 223.23 252.09 222.86 252.44C222.48 252.8 222.07 253.1 221.62 253.35C221.16 253.6 220.68 253.79 220.19 253.92C219.69 254.04 219.17 254.11 218.66 254.1C217.5 254.1 216.37 253.78 215.39 253.16C215.26 253.07 215.18 253.02 215.11 252.97C212.46 251.1 211.75 247.47 213.49 244.71C213.59 244.56 213.69 244.42 213.8 244.28C211.13 239.63 201.64 230.6 199.03 229.96C195.63 229.11 193.67 229.18 191.18 229.27C189.73 229.32 188.08 229.39 185.97 229.27C182.89 229.11 181.2 227.19 179.71 225.49C178.15 223.71 176.65 222.12 173.36 221.82L173.36 217.82C178.5 218.2 180.92 220.79 182.72 222.85C184.08 224.39 184.85 225.2 186.18 225.27C188.12 225.37 189.6 225.32 191.03 225.27C192.77 225.2 194.36 225.15 196.32 225.38C202 225.29 203.92 224.04 205.96 222.72C207.58 221.66 209.41 220.48 212.78 219.99C212.82 219.85 212.87 219.71 212.92 219.58C212.97 219.44 213.02 219.31 213.08 219.17C213.14 219.04 213.2 218.91 213.27 218.78C213.34 218.66 213.41 218.53 213.49 218.41C213.54 218.34 213.59 218.27 213.64 218.19C213.69 218.12 213.74 218.05 213.79 217.98C213.84 217.92 213.9 217.85 213.95 217.78C214.01 217.71 214.07 217.65 214.12 217.58C214.26 217.44 214.41 217.32 214.55 217.19C213.44 213.09 213.24 207.29 214.59 202.77C214.56 202.75 214.54 202.73 214.51 202.71C213.99 202.23 213.56 201.66 213.23 201.03C212.9 200.4 212.69 199.72 212.59 199.01C212.5 198.31 212.53 197.59 212.68 196.9C212.84 196.21 213.11 195.55 213.49 194.95C213.76 194.51 214.09 194.11 214.46 193.76C214.84 193.4 215.26 193.1 215.71 192.85C216.16 192.6 216.64 192.41 217.14 192.28C217.64 192.16 218.15 192.09 218.66 192.1C218.95 192.1 219.24 192.12 219.52 192.16C219.81 192.2 220.09 192.26 220.36 192.34C220.64 192.42 220.91 192.52 221.17 192.63C221.43 192.75 221.69 192.89 221.93 193.04C222.27 193.25 222.59 193.5 222.88 193.78C223.17 194.06 223.44 194.36 223.67 194.69C223.9 195.02 224.1 195.37 224.26 195.74C224.42 196.11 224.55 196.49 224.64 196.88C224.73 197.27 224.78 197.67 224.79 198.07C224.8 198.47 224.77 198.87 224.7 199.27C224.63 199.66 224.52 200.05 224.38 200.42C224.23 200.79 224.05 201.15 223.83 201.49C223.56 201.92 223.23 202.32 222.86 202.68C222.48 203.03 222.07 203.33 221.62 203.58C221.16 203.83 220.68 204.02 220.19 204.15C219.69 204.27 219.17 204.34 218.66 204.34C218.55 204.34 218.44 204.32 218.32 204.31C217.37 207.81 217.58 212.42 218.29 215.58C218.41 215.57 218.54 215.56 218.66 215.56C218.95 215.56 219.24 215.58 219.52 215.62C219.81 215.66 220.09 215.72 220.36 215.8C220.64 215.88 220.91 215.98 221.17 216.1C221.43 216.21 221.69 216.35 221.93 216.5C222.27 216.72 222.59 216.96 222.88 217.24C223.17 217.52 223.44 217.82 223.67 218.15C223.9 218.48 224.1 218.83 224.26 219.2C224.42 219.57 224.55 219.95 224.64 220.35C224.73 220.74 224.78 221.14 224.79 221.54C224.8 221.94 224.77 222.34 224.7 222.73C224.63 223.12 224.52 223.51 224.38 223.88C224.23 224.26 224.05 224.61 223.83 224.95C223.56 225.39 223.23 225.79 222.86 226.14C222.48 226.49 222.07 226.8 221.62 227.05C221.16 227.29 220.68 227.48 220.19 227.61C219.69 227.74 219.17 227.8 218.66 227.8C218.34 227.8 218.03 227.78 217.72 227.73C217.4 227.68 217.1 227.6 216.8 227.51C216.49 227.41 216.2 227.29 215.92 227.15C215.64 227.01 215.37 226.84 215.11 226.66C214.88 226.5 214.65 226.31 214.45 226.12C214.24 225.92 214.04 225.71 213.87 225.49C213.69 225.26 213.52 225.03 213.38 224.78C213.24 224.53 213.11 224.28 213 224.01ZM216.88 197.09C216.74 197.31 216.64 197.56 216.59 197.83C216.54 198.09 216.54 198.36 216.59 198.62C216.64 198.88 216.74 199.14 216.89 199.36C217.03 199.59 217.22 199.78 217.44 199.94L217.53 200C218.51 200.62 219.85 200.3 220.44 199.34C220.52 199.23 220.58 199.11 220.63 198.98C220.68 198.85 220.72 198.72 220.74 198.58C220.77 198.44 220.78 198.31 220.78 198.17C220.77 198.03 220.76 197.89 220.73 197.76C220.6 197.2 220.27 196.73 219.79 196.43C219.45 196.22 219.06 196.1 218.66 196.1C218.49 196.1 218.31 196.13 218.14 196.17C217.97 196.21 217.8 196.28 217.64 196.36C217.49 196.45 217.35 196.55 217.22 196.68C217.09 196.8 216.97 196.93 216.88 197.09ZM216.88 220.55C216.74 220.77 216.64 221.03 216.59 221.29C216.54 221.55 216.54 221.82 216.59 222.09C216.64 222.35 216.74 222.6 216.89 222.82C217.03 223.05 217.22 223.24 217.44 223.4L217.53 223.46C218.51 224.08 219.85 223.76 220.44 222.81C220.52 222.69 220.58 222.57 220.63 222.44C220.68 222.31 220.72 222.18 220.74 222.04C220.77 221.91 220.78 221.77 220.78 221.63C220.77 221.49 220.76 221.36 220.72 221.22C220.6 220.67 220.27 220.2 219.79 219.89C219.45 219.68 219.06 219.57 218.66 219.57C218.49 219.57 218.31 219.59 218.14 219.63C217.97 219.68 217.8 219.74 217.64 219.83C217.49 219.91 217.35 220.02 217.22 220.14C217.09 220.26 216.97 220.4 216.88 220.55ZM216.88 246.85C216.74 247.08 216.64 247.33 216.59 247.59C216.54 247.86 216.54 248.13 216.59 248.39C216.64 248.65 216.74 248.9 216.89 249.13C217.03 249.35 217.22 249.55 217.44 249.7L217.53 249.76C218.51 250.38 219.85 250.06 220.44 249.11C220.52 249 220.58 248.87 220.63 248.74C220.68 248.62 220.72 248.48 220.74 248.35C220.77 248.21 220.78 248.07 220.78 247.94C220.77 247.8 220.76 247.66 220.72 247.53C220.6 246.97 220.27 246.5 219.79 246.2C219.45 245.98 219.06 245.87 218.66 245.87C218.49 245.87 218.31 245.89 218.14 245.94C217.97 245.98 217.8 246.05 217.64 246.13C217.49 246.22 217.35 246.32 217.22 246.44C217.09 246.56 216.97 246.7 216.88 246.85Z" />
+ </g>
+ </g>
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M206.53 261.93C206.79 262.23 207.02 262.56 207.22 262.91C207.42 263.26 207.58 263.63 207.71 264.01C207.83 264.39 207.92 264.78 207.96 265.18C208.01 265.58 208.02 265.98 207.99 266.38C207.96 266.78 207.89 267.17 207.78 267.56C207.67 267.95 207.53 268.32 207.35 268.68C207.17 269.04 206.95 269.38 206.7 269.69C206.45 270.01 206.17 270.3 205.87 270.56C205.59 270.79 205.3 271 204.99 271.19C204.68 271.37 204.35 271.52 204.01 271.65C203.67 271.78 203.32 271.87 202.96 271.94C202.61 272 202.25 272.03 201.89 272.03C201.49 272.03 201.1 271.99 200.71 271.92C200.32 271.84 199.94 271.73 199.57 271.58C199.21 271.43 198.85 271.24 198.52 271.02C198.19 270.81 197.88 270.56 197.6 270.28C195.75 270.98 192.69 272 190.58 272C190.48 272 190.37 272 190.27 272C188.3 271.89 187.03 271.03 186.01 270.34C184.44 269.28 182.95 268.27 177.6 269.63C175.24 270.71 173.63 270.79 173.36 270.82L173.36 266.82C173.86 266.72 174.73 266.55 175.91 266.01C175.94 266 175.97 265.98 176 265.97C176.03 265.95 176.06 265.94 176.09 265.92C176.12 265.91 176.15 265.89 176.18 265.88C176.21 265.87 176.24 265.86 176.27 265.85C179.62 264.24 184.79 260.38 188.84 251.16C188.56 250.95 188.29 250.72 188.05 250.47C187.8 250.22 187.58 249.94 187.39 249.65C187.19 249.36 187.02 249.05 186.88 248.73C186.74 248.41 186.62 248.07 186.54 247.73C186.44 247.34 186.38 246.95 186.36 246.55C186.33 246.15 186.35 245.74 186.41 245.35C186.47 244.95 186.57 244.56 186.7 244.18C186.84 243.8 187.01 243.44 187.22 243.1C187.49 242.64 187.82 242.23 188.19 241.86C188.57 241.49 188.99 241.17 189.45 240.91C189.91 240.65 190.4 240.45 190.91 240.32C191.42 240.18 191.95 240.11 192.48 240.11C192.75 240.11 193.02 240.13 193.3 240.17C193.57 240.2 193.84 240.26 194.1 240.33C194.37 240.4 194.62 240.5 194.88 240.6C195.13 240.71 195.37 240.83 195.61 240.97C198.51 242.71 199.46 246.47 197.73 249.37C197.47 249.8 197.16 250.21 196.79 250.56C196.43 250.92 196.03 251.23 195.59 251.49C195.15 251.75 194.68 251.95 194.2 252.1C193.71 252.24 193.2 252.32 192.69 252.34C190.12 258.35 187.05 262.41 184.11 265.18C185.84 265.51 187.09 266.23 188.26 267.02C189.18 267.65 189.66 267.95 190.48 267.99C191.55 268.03 193.86 267.36 195.81 266.66C195.75 266.16 195.75 265.66 195.81 265.16C195.87 264.66 196 264.17 196.18 263.7C196.36 263.23 196.6 262.79 196.89 262.38C197.18 261.97 197.52 261.59 197.9 261.26C198.51 260.74 199.22 260.34 199.98 260.09C200.74 259.84 201.55 259.74 202.35 259.8C203.15 259.87 203.94 260.08 204.65 260.45C205.37 260.81 206.01 261.32 206.53 261.93ZM190.66 245.15C190.59 245.27 190.53 245.4 190.48 245.53C190.43 245.66 190.4 245.79 190.38 245.93C190.36 246.07 190.35 246.2 190.36 246.34C190.37 246.48 190.39 246.62 190.42 246.75C190.46 246.89 190.5 247.02 190.56 247.14C190.62 247.27 190.69 247.39 190.78 247.5C190.86 247.61 190.95 247.71 191.05 247.8C191.16 247.89 191.27 247.98 191.39 248.05C191.72 248.24 192.09 248.35 192.47 248.35C192.65 248.35 192.84 248.33 193.01 248.28C193.19 248.23 193.36 248.16 193.52 248.07C193.68 247.98 193.82 247.87 193.95 247.75C194.08 247.62 194.2 247.47 194.29 247.32C194.58 246.83 194.66 246.26 194.52 245.71C194.38 245.17 194.04 244.7 193.56 244.42C193.07 244.13 192.5 244.05 191.95 244.18C191.41 244.32 190.94 244.67 190.66 245.15ZM203.26 267.51C203.36 267.42 203.46 267.32 203.55 267.22C203.63 267.11 203.71 266.99 203.77 266.87C203.83 266.74 203.88 266.62 203.92 266.48C203.96 266.35 203.98 266.21 203.99 266.07C204.01 265.78 203.98 265.49 203.88 265.22C203.78 264.94 203.63 264.69 203.43 264.47C203.24 264.26 203 264.09 202.73 263.97C202.46 263.86 202.17 263.8 201.88 263.8C201.76 263.8 201.63 263.81 201.51 263.83C201.39 263.85 201.27 263.88 201.15 263.93C201.03 263.97 200.92 264.02 200.81 264.09C200.7 264.15 200.6 264.23 200.51 264.31C200.3 264.49 200.13 264.71 200 264.96C199.87 265.2 199.8 265.47 199.78 265.75C199.76 266.03 199.79 266.31 199.87 266.57C199.96 266.83 200.1 267.08 200.28 267.29C200.46 267.5 200.68 267.67 200.93 267.8C201.18 267.92 201.45 268 201.72 268.02C202 268.04 202.28 268 202.54 267.92C202.8 267.83 203.05 267.69 203.26 267.51Z" />
+ <path id="Layer" class="shp2" d="" />
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M204.3 185.03C204.39 185.42 204.44 185.82 204.45 186.22C204.46 186.62 204.43 187.02 204.36 187.41C204.3 187.81 204.19 188.19 204.04 188.57C203.9 188.94 203.72 189.3 203.5 189.63C203.23 190.07 202.9 190.47 202.53 190.82C202.15 191.18 201.73 191.48 201.28 191.73C200.83 191.98 200.35 192.17 199.85 192.29C199.36 192.42 198.84 192.48 198.33 192.48C198.18 192.48 198.03 192.48 197.88 192.46C197.73 192.45 197.58 192.44 197.43 192.41C197.29 192.39 197.14 192.36 196.99 192.33C196.85 192.3 196.7 192.26 196.56 192.22C194.18 195.04 191.3 196.53 188.78 197.31C190.8 198.86 192.59 200.72 194.12 202.88C195.7 202.52 197.41 202.76 198.79 203.63C201.65 205.44 202.5 209.24 200.7 212.09C200.42 212.52 200.09 212.92 199.72 213.28C199.34 213.63 198.93 213.93 198.47 214.18C198.02 214.43 197.54 214.62 197.04 214.75C196.54 214.88 196.03 214.94 195.52 214.94C194.36 214.94 193.23 214.61 192.25 213.99C189.4 212.19 188.55 208.4 190.34 205.54C190.37 205.5 190.4 205.45 190.43 205.4C190.46 205.36 190.49 205.31 190.53 205.27C190.56 205.22 190.59 205.18 190.62 205.14C190.66 205.09 190.69 205.05 190.72 205C188.45 201.89 185.56 199.53 182.12 197.96C182.11 197.96 182.11 197.96 182.1 197.96C178.91 196.51 175.8 195.97 173.35 195.82L173.35 191.83C176.13 191.98 179.67 192.54 183.36 194.14C184.59 194.16 189.66 193.97 193.3 189.85C192.96 189.36 192.69 188.82 192.51 188.25C192.32 187.68 192.22 187.09 192.21 186.49C192.2 185.9 192.27 185.3 192.43 184.72C192.59 184.15 192.84 183.6 193.16 183.09C193.43 182.66 193.76 182.26 194.13 181.9C194.51 181.55 194.92 181.25 195.38 181C195.83 180.75 196.31 180.56 196.81 180.43C197.3 180.3 197.82 180.24 198.33 180.24C198.62 180.24 198.91 180.26 199.19 180.3C199.47 180.34 199.76 180.4 200.03 180.48C200.31 180.56 200.58 180.66 200.84 180.78C201.1 180.9 201.35 181.03 201.6 181.19C201.94 181.4 202.26 181.65 202.55 181.93C202.84 182.2 203.1 182.51 203.34 182.84C203.57 183.17 203.77 183.52 203.93 183.89C204.09 184.25 204.22 184.64 204.3 185.03ZM193.73 207.68C193.59 207.91 193.49 208.18 193.44 208.45C193.39 208.72 193.4 209 193.46 209.28C193.52 209.55 193.63 209.8 193.79 210.03C193.95 210.26 194.16 210.45 194.39 210.6C194.63 210.75 194.89 210.85 195.16 210.9C195.44 210.95 195.72 210.94 195.99 210.88C196.26 210.82 196.51 210.7 196.74 210.54C196.97 210.38 197.16 210.18 197.31 209.94C197.46 209.71 197.56 209.44 197.6 209.17C197.65 208.9 197.64 208.62 197.58 208.35C197.52 208.07 197.41 207.82 197.25 207.59C197.09 207.36 196.88 207.17 196.65 207.02C196.41 206.88 196.15 206.78 195.88 206.73C195.61 206.68 195.33 206.69 195.06 206.75C194.79 206.81 194.53 206.93 194.3 207.08C194.08 207.24 193.88 207.44 193.73 207.68ZM200.11 187.49C200.32 187.17 200.43 186.8 200.44 186.43C200.45 186.05 200.36 185.68 200.18 185.34C200 185.01 199.73 184.74 199.41 184.55C199.08 184.35 198.71 184.25 198.33 184.25C198.15 184.25 197.98 184.27 197.81 184.32C197.63 184.36 197.47 184.42 197.31 184.51C197.16 184.59 197.01 184.7 196.88 184.82C196.76 184.94 196.64 185.08 196.55 185.23C196.4 185.46 196.3 185.71 196.25 185.97C196.2 186.23 196.21 186.5 196.26 186.77C196.31 187.03 196.41 187.28 196.55 187.51C196.7 187.73 196.89 187.93 197.11 188.08L197.2 188.14C198.18 188.76 199.51 188.44 200.11 187.49Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M213 227.01C210.76 227.39 209.57 228.15 208.14 229.08C206.98 229.83 205.74 230.64 203.93 231.26C208.47 234.6 214.56 240.87 217.12 245.06C217.52 244.95 217.94 244.89 218.35 244.87C218.77 244.85 219.19 244.87 219.6 244.93C220.01 245 220.42 245.1 220.81 245.25C221.2 245.4 221.58 245.58 221.93 245.81C222.27 246.02 222.59 246.27 222.88 246.55C223.17 246.82 223.44 247.13 223.67 247.46C223.9 247.79 224.1 248.14 224.26 248.51C224.43 248.87 224.55 249.26 224.64 249.65C224.73 250.04 224.78 250.44 224.79 250.84C224.8 251.24 224.77 251.64 224.7 252.03C224.63 252.43 224.52 252.81 224.38 253.19C224.23 253.56 224.05 253.92 223.83 254.25C223.56 254.69 223.23 255.09 222.86 255.44C222.48 255.8 222.07 256.1 221.62 256.35C221.16 256.6 220.68 256.79 220.19 256.91C219.69 257.04 219.17 257.1 218.66 257.1C217.5 257.1 216.37 256.78 215.39 256.15C215.26 256.07 215.18 256.02 215.11 255.96C212.46 254.1 211.75 250.47 213.49 247.71C213.59 247.56 213.69 247.42 213.8 247.28C211.13 242.63 201.64 233.6 199.03 232.96C195.63 232.11 193.67 232.18 191.18 232.27C189.73 232.32 188.08 232.39 185.97 232.27C182.89 232.1 181.2 230.18 179.71 228.49C178.15 226.71 176.65 225.12 173.36 224.82L173.36 220.82C178.5 221.2 180.92 223.79 182.72 225.84C184.08 227.39 184.85 228.2 186.18 228.27C188.12 228.37 189.6 228.32 191.03 228.27C192.77 228.2 194.36 228.15 196.32 228.38C202 228.29 203.92 227.04 205.96 225.72C207.58 224.66 209.41 223.48 212.78 222.99C212.82 222.85 212.87 222.71 212.92 222.58C212.97 222.44 213.02 222.31 213.08 222.17C213.14 222.04 213.2 221.91 213.27 221.78C213.34 221.66 213.41 221.53 213.49 221.41C213.54 221.34 213.59 221.27 213.64 221.19C213.69 221.12 213.74 221.05 213.79 220.98C213.84 220.92 213.9 220.85 213.95 220.78C214.01 220.71 214.07 220.65 214.12 220.58C214.26 220.44 214.41 220.32 214.55 220.19C213.44 216.09 213.24 210.29 214.59 205.77C214.56 205.75 214.54 205.73 214.51 205.71C213.99 205.23 213.56 204.66 213.23 204.03C212.9 203.4 212.69 202.72 212.59 202.01C212.5 201.31 212.53 200.59 212.68 199.9C212.84 199.21 213.11 198.55 213.49 197.95C213.76 197.51 214.09 197.11 214.46 196.76C214.84 196.4 215.26 196.1 215.71 195.85C216.16 195.6 216.64 195.41 217.14 195.28C217.64 195.16 218.15 195.09 218.66 195.1C218.95 195.1 219.24 195.12 219.52 195.16C219.81 195.2 220.09 195.26 220.36 195.34C220.64 195.42 220.91 195.52 221.17 195.63C221.43 195.75 221.69 195.89 221.93 196.04C222.27 196.25 222.59 196.5 222.88 196.78C223.17 197.06 223.44 197.36 223.67 197.69C223.9 198.02 224.1 198.37 224.26 198.74C224.42 199.11 224.55 199.49 224.64 199.88C224.73 200.27 224.78 200.67 224.79 201.07C224.8 201.47 224.77 201.87 224.7 202.27C224.63 202.66 224.52 203.05 224.38 203.42C224.23 203.79 224.05 204.15 223.83 204.49C223.56 204.92 223.23 205.32 222.86 205.68C222.48 206.03 222.07 206.33 221.62 206.58C221.16 206.83 220.68 207.02 220.19 207.15C219.69 207.27 219.17 207.34 218.66 207.34C218.55 207.34 218.44 207.32 218.32 207.31C217.37 210.81 217.58 215.42 218.29 218.58C218.41 218.57 218.54 218.56 218.66 218.56C218.95 218.56 219.24 218.58 219.52 218.62C219.81 218.66 220.09 218.72 220.36 218.8C220.64 218.88 220.91 218.98 221.17 219.1C221.43 219.21 221.69 219.35 221.93 219.5C222.27 219.72 222.59 219.96 222.88 220.24C223.17 220.52 223.44 220.82 223.67 221.15C223.9 221.48 224.1 221.83 224.26 222.2C224.42 222.57 224.55 222.95 224.64 223.35C224.73 223.74 224.78 224.14 224.79 224.54C224.8 224.94 224.77 225.34 224.7 225.73C224.63 226.12 224.52 226.51 224.38 226.88C224.23 227.26 224.05 227.61 223.83 227.95C223.56 228.39 223.23 228.79 222.86 229.14C222.48 229.49 222.07 229.8 221.62 230.05C221.16 230.29 220.68 230.48 220.19 230.61C219.69 230.74 219.17 230.8 218.66 230.8C218.34 230.8 218.03 230.78 217.72 230.73C217.4 230.68 217.1 230.6 216.8 230.51C216.49 230.41 216.2 230.29 215.92 230.15C215.64 230.01 215.37 229.84 215.11 229.66C214.88 229.5 214.65 229.31 214.45 229.12C214.24 228.92 214.04 228.71 213.87 228.49C213.69 228.26 213.52 228.03 213.38 227.78C213.24 227.53 213.11 227.28 213 227.01ZM216.88 200.09C216.74 200.31 216.64 200.56 216.59 200.83C216.54 201.09 216.54 201.36 216.59 201.62C216.64 201.88 216.74 202.14 216.89 202.36C217.03 202.59 217.22 202.78 217.44 202.94L217.53 203C218.51 203.62 219.85 203.3 220.44 202.34C220.52 202.23 220.58 202.11 220.63 201.98C220.68 201.85 220.72 201.72 220.74 201.58C220.77 201.44 220.78 201.31 220.78 201.17C220.77 201.03 220.76 200.89 220.73 200.76C220.6 200.2 220.27 199.73 219.79 199.43C219.45 199.22 219.06 199.1 218.66 199.1C218.49 199.1 218.31 199.13 218.14 199.17C217.97 199.21 217.8 199.28 217.64 199.36C217.49 199.45 217.35 199.55 217.22 199.68C217.09 199.8 216.97 199.93 216.88 200.09ZM216.88 223.55C216.74 223.77 216.64 224.03 216.59 224.29C216.54 224.55 216.54 224.82 216.59 225.09C216.64 225.35 216.74 225.6 216.89 225.82C217.03 226.05 217.22 226.24 217.44 226.4L217.53 226.46C218.51 227.08 219.85 226.76 220.44 225.81C220.52 225.69 220.58 225.57 220.63 225.44C220.68 225.31 220.72 225.18 220.74 225.04C220.77 224.91 220.78 224.77 220.78 224.63C220.77 224.49 220.76 224.36 220.72 224.22C220.6 223.67 220.27 223.2 219.79 222.89C219.45 222.68 219.06 222.57 218.66 222.57C218.49 222.57 218.31 222.59 218.14 222.63C217.97 222.68 217.8 222.74 217.64 222.83C217.49 222.91 217.35 223.02 217.22 223.14C217.09 223.26 216.97 223.4 216.88 223.55ZM216.88 249.85C216.74 250.08 216.64 250.33 216.59 250.59C216.54 250.86 216.54 251.13 216.59 251.39C216.64 251.65 216.74 251.9 216.89 252.13C217.03 252.35 217.22 252.55 217.44 252.7L217.53 252.76C218.51 253.38 219.85 253.06 220.44 252.11C220.52 252 220.58 251.87 220.63 251.74C220.68 251.62 220.72 251.48 220.74 251.35C220.77 251.21 220.78 251.07 220.78 250.94C220.77 250.8 220.76 250.66 220.72 250.53C220.6 249.97 220.27 249.5 219.79 249.2C219.45 248.98 219.06 248.87 218.66 248.87C218.49 248.87 218.31 248.89 218.14 248.94C217.97 248.98 217.8 249.05 217.64 249.13C217.49 249.22 217.35 249.32 217.22 249.44C217.09 249.56 216.97 249.7 216.88 249.85Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M206.53 258.93C206.79 259.23 207.02 259.56 207.22 259.91C207.42 260.26 207.58 260.63 207.71 261.01C207.83 261.39 207.92 261.78 207.96 262.18C208.01 262.58 208.02 262.98 207.99 263.38C207.96 263.78 207.89 264.17 207.78 264.56C207.67 264.95 207.53 265.32 207.35 265.68C207.17 266.04 206.95 266.38 206.7 266.69C206.45 267.01 206.17 267.3 205.87 267.56C205.59 267.79 205.3 268 204.99 268.19C204.68 268.37 204.35 268.52 204.01 268.65C203.67 268.78 203.32 268.87 202.96 268.94C202.61 269 202.25 269.03 201.89 269.03C201.49 269.03 201.1 268.99 200.71 268.92C200.32 268.84 199.94 268.73 199.57 268.58C199.21 268.43 198.85 268.24 198.52 268.02C198.19 267.81 197.88 267.56 197.6 267.28C195.75 267.98 192.69 269 190.58 269C190.48 269 190.37 269 190.27 269C188.3 268.89 187.03 268.03 186.01 267.34C184.44 266.28 182.95 265.27 177.6 266.63C175.24 267.71 173.63 267.79 173.36 267.82L173.36 263.82C173.86 263.72 174.73 263.55 175.91 263.01C175.94 263 175.97 262.98 176 262.97C176.03 262.95 176.06 262.94 176.09 262.92C176.12 262.91 176.15 262.89 176.18 262.88C176.21 262.87 176.24 262.86 176.27 262.85C179.62 261.24 184.79 257.38 188.84 248.16C188.56 247.95 188.29 247.72 188.05 247.47C187.8 247.22 187.58 246.94 187.39 246.65C187.19 246.36 187.02 246.05 186.88 245.73C186.74 245.41 186.62 245.07 186.54 244.73C186.44 244.34 186.38 243.95 186.36 243.55C186.33 243.15 186.35 242.74 186.41 242.35C186.47 241.95 186.57 241.56 186.7 241.18C186.84 240.8 187.01 240.44 187.22 240.1C187.49 239.64 187.82 239.23 188.19 238.86C188.57 238.49 188.99 238.17 189.45 237.91C189.91 237.65 190.4 237.45 190.91 237.32C191.42 237.18 191.95 237.11 192.48 237.11C192.75 237.11 193.02 237.13 193.3 237.17C193.57 237.2 193.84 237.26 194.1 237.33C194.37 237.4 194.62 237.5 194.88 237.6C195.13 237.71 195.37 237.83 195.61 237.97C198.51 239.71 199.46 243.47 197.73 246.37C197.47 246.8 197.16 247.21 196.79 247.56C196.43 247.92 196.03 248.23 195.59 248.49C195.15 248.75 194.68 248.95 194.2 249.1C193.71 249.24 193.2 249.32 192.69 249.34C190.12 255.34 187.05 259.41 184.11 262.18C185.84 262.51 187.09 263.23 188.26 264.02C189.18 264.65 189.66 264.95 190.48 264.99C191.55 265.03 193.86 264.36 195.81 263.66C195.75 263.16 195.75 262.66 195.81 262.16C195.87 261.66 196 261.17 196.18 260.7C196.36 260.23 196.6 259.79 196.89 259.38C197.18 258.97 197.52 258.59 197.9 258.26C198.51 257.74 199.22 257.34 199.98 257.09C200.74 256.84 201.55 256.74 202.35 256.8C203.15 256.87 203.94 257.08 204.65 257.45C205.37 257.81 206.01 258.32 206.53 258.93ZM190.66 242.15C190.59 242.27 190.53 242.4 190.48 242.53C190.43 242.66 190.4 242.79 190.38 242.93C190.36 243.07 190.35 243.2 190.36 243.34C190.37 243.48 190.39 243.62 190.42 243.75C190.46 243.89 190.5 244.02 190.56 244.14C190.62 244.27 190.69 244.39 190.78 244.5C190.86 244.61 190.95 244.71 191.05 244.8C191.16 244.89 191.27 244.98 191.39 245.05C191.72 245.24 192.09 245.35 192.47 245.35C192.65 245.35 192.84 245.33 193.01 245.28C193.19 245.23 193.36 245.16 193.52 245.07C193.68 244.98 193.82 244.87 193.95 244.75C194.08 244.62 194.2 244.47 194.29 244.32C194.58 243.83 194.66 243.26 194.52 242.71C194.38 242.17 194.04 241.7 193.56 241.42C193.07 241.13 192.5 241.05 191.95 241.18C191.41 241.32 190.94 241.67 190.66 242.15ZM203.26 264.51C203.36 264.42 203.46 264.32 203.55 264.22C203.63 264.11 203.71 263.99 203.77 263.87C203.83 263.74 203.88 263.62 203.92 263.48C203.96 263.35 203.98 263.21 203.99 263.07C204.01 262.78 203.98 262.49 203.88 262.22C203.78 261.94 203.63 261.69 203.43 261.47C203.24 261.26 203 261.09 202.73 260.97C202.46 260.86 202.17 260.8 201.88 260.8C201.76 260.8 201.63 260.81 201.51 260.83C201.39 260.85 201.27 260.88 201.15 260.93C201.03 260.97 200.92 261.02 200.81 261.09C200.7 261.15 200.6 261.23 200.51 261.31C200.3 261.49 200.13 261.71 200 261.96C199.87 262.2 199.8 262.47 199.78 262.75C199.76 263.03 199.79 263.31 199.87 263.57C199.96 263.83 200.1 264.08 200.28 264.29C200.46 264.5 200.68 264.67 200.93 264.8C201.18 264.92 201.45 265 201.72 265.02C202 265.04 202.28 265 202.54 264.92C202.8 264.83 203.05 264.69 203.26 264.51ZM204.3 183.03C204.39 183.42 204.44 183.82 204.45 184.22C204.46 184.62 204.43 185.02 204.36 185.41C204.3 185.8 204.19 186.19 204.04 186.56C203.9 186.94 203.72 187.29 203.5 187.63C203.23 188.07 202.9 188.47 202.52 188.82C202.15 189.17 201.73 189.48 201.28 189.72C200.83 189.97 200.35 190.16 199.85 190.29C199.36 190.42 198.84 190.48 198.33 190.48C198.18 190.48 198.03 190.47 197.88 190.46C197.73 190.45 197.58 190.43 197.43 190.41C197.29 190.39 197.14 190.36 196.99 190.33C196.85 190.29 196.7 190.26 196.56 190.21C194.18 193.04 191.3 194.53 188.78 195.31C190.8 196.86 192.59 198.72 194.12 200.88C195.7 200.52 197.41 200.76 198.79 201.63C201.65 203.44 202.5 207.23 200.7 210.08C200.42 210.52 200.09 210.92 199.72 211.27C199.34 211.63 198.93 211.93 198.47 212.18C198.02 212.43 197.54 212.62 197.04 212.74C196.54 212.87 196.03 212.94 195.52 212.93C194.36 212.93 193.23 212.61 192.25 211.98C189.4 210.18 188.55 206.39 190.34 203.54C190.37 203.49 190.4 203.45 190.43 203.4C190.46 203.36 190.49 203.31 190.53 203.27C190.56 203.22 190.59 203.18 190.62 203.13C190.66 203.09 190.69 203.04 190.72 203C188.45 199.89 185.56 197.52 182.12 195.96C182.11 195.96 182.11 195.96 182.1 195.96C178.91 194.5 175.8 193.96 173.35 193.82L173.35 189.82C176.13 189.98 179.67 190.54 183.36 192.14C184.59 192.16 189.66 191.97 193.3 187.85C192.96 187.36 192.69 186.82 192.51 186.25C192.32 185.68 192.22 185.09 192.21 184.49C192.2 183.89 192.27 183.3 192.43 182.72C192.59 182.14 192.84 181.59 193.16 181.09C193.43 180.65 193.76 180.25 194.13 179.9C194.51 179.55 194.92 179.24 195.38 178.99C195.83 178.74 196.31 178.55 196.81 178.43C197.3 178.3 197.82 178.24 198.33 178.24C198.62 178.24 198.91 178.26 199.19 178.3C199.47 178.34 199.76 178.4 200.03 178.48C200.31 178.56 200.58 178.66 200.84 178.78C201.1 178.89 201.35 179.03 201.6 179.18C201.94 179.4 202.26 179.64 202.55 179.92C202.84 180.2 203.1 180.5 203.34 180.83C203.57 181.16 203.77 181.51 203.93 181.88C204.09 182.25 204.22 182.63 204.3 183.03ZM193.73 205.67C193.59 205.91 193.49 206.17 193.44 206.45C193.39 206.72 193.4 207 193.46 207.27C193.52 207.54 193.63 207.8 193.79 208.03C193.95 208.25 194.16 208.45 194.39 208.6C194.63 208.75 194.89 208.85 195.16 208.89C195.44 208.94 195.72 208.93 195.99 208.87C196.26 208.81 196.51 208.7 196.74 208.54C196.97 208.38 197.16 208.17 197.31 207.94C197.46 207.7 197.56 207.44 197.6 207.17C197.65 206.89 197.64 206.61 197.58 206.34C197.52 206.07 197.41 205.81 197.25 205.59C197.09 205.36 196.88 205.17 196.65 205.02C196.41 204.87 196.15 204.77 195.88 204.73C195.61 204.68 195.33 204.69 195.06 204.75C194.79 204.81 194.53 204.92 194.3 205.08C194.08 205.24 193.88 205.44 193.73 205.67ZM200.11 185.49C200.32 185.17 200.43 184.8 200.44 184.42C200.45 184.05 200.36 183.67 200.18 183.34C200 183.01 199.73 182.73 199.41 182.54C199.08 182.35 198.71 182.25 198.33 182.25C198.15 182.25 197.98 182.27 197.81 182.31C197.63 182.35 197.47 182.42 197.31 182.51C197.16 182.59 197.01 182.7 196.88 182.82C196.76 182.94 196.64 183.08 196.55 183.23C196.4 183.45 196.3 183.7 196.25 183.97C196.2 184.23 196.21 184.5 196.26 184.76C196.31 185.03 196.41 185.28 196.55 185.5C196.7 185.73 196.89 185.92 197.11 186.08L197.2 186.14C198.18 186.76 199.51 186.44 200.11 185.49Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M213 224.01C210.76 224.39 209.57 225.15 208.14 226.08C206.98 226.83 205.74 227.64 203.93 228.27C208.47 231.6 214.56 237.87 217.12 242.06C217.52 241.95 217.94 241.89 218.35 241.87C218.77 241.85 219.19 241.87 219.6 241.93C220.01 242 220.42 242.11 220.81 242.25C221.2 242.4 221.58 242.58 221.93 242.81C222.27 243.02 222.59 243.27 222.88 243.55C223.17 243.82 223.44 244.13 223.67 244.46C223.9 244.79 224.1 245.14 224.26 245.51C224.43 245.88 224.55 246.26 224.64 246.65C224.73 247.04 224.78 247.44 224.79 247.84C224.8 248.24 224.77 248.64 224.7 249.03C224.63 249.43 224.52 249.81 224.38 250.19C224.23 250.56 224.05 250.92 223.83 251.25C223.56 251.69 223.23 252.09 222.86 252.44C222.48 252.8 222.07 253.1 221.62 253.35C221.16 253.6 220.68 253.79 220.19 253.92C219.69 254.04 219.17 254.11 218.66 254.1C217.5 254.1 216.37 253.78 215.39 253.16C215.26 253.07 215.18 253.02 215.11 252.97C212.46 251.1 211.75 247.47 213.49 244.71C213.59 244.56 213.69 244.42 213.8 244.28C211.13 239.63 201.64 230.6 199.03 229.96C195.63 229.11 193.67 229.18 191.18 229.27C189.73 229.32 188.08 229.39 185.97 229.27C182.89 229.11 181.2 227.19 179.71 225.49C178.15 223.71 176.65 222.12 173.36 221.82L173.36 217.82C178.5 218.2 180.92 220.79 182.72 222.85C184.08 224.39 184.85 225.2 186.18 225.27C188.12 225.37 189.6 225.32 191.03 225.27C192.77 225.2 194.36 225.15 196.32 225.38C202 225.29 203.92 224.04 205.96 222.72C207.58 221.66 209.41 220.48 212.78 219.99C212.82 219.85 212.87 219.71 212.92 219.58C212.97 219.44 213.02 219.31 213.08 219.17C213.14 219.04 213.2 218.91 213.27 218.78C213.34 218.66 213.41 218.53 213.49 218.41C213.54 218.34 213.59 218.27 213.64 218.19C213.69 218.12 213.74 218.05 213.79 217.98C213.84 217.92 213.9 217.85 213.95 217.78C214.01 217.71 214.07 217.65 214.12 217.58C214.26 217.44 214.41 217.32 214.55 217.19C213.44 213.09 213.24 207.29 214.59 202.77C214.56 202.75 214.54 202.73 214.51 202.71C213.99 202.23 213.56 201.66 213.23 201.03C212.9 200.4 212.69 199.72 212.59 199.01C212.5 198.31 212.53 197.59 212.68 196.9C212.84 196.21 213.11 195.55 213.49 194.95C213.76 194.51 214.09 194.11 214.46 193.76C214.84 193.4 215.26 193.1 215.71 192.85C216.16 192.6 216.64 192.41 217.14 192.28C217.64 192.16 218.15 192.09 218.66 192.1C218.95 192.1 219.24 192.12 219.52 192.16C219.81 192.2 220.09 192.26 220.36 192.34C220.64 192.42 220.91 192.52 221.17 192.63C221.43 192.75 221.69 192.89 221.93 193.04C222.27 193.25 222.59 193.5 222.88 193.78C223.17 194.06 223.44 194.36 223.67 194.69C223.9 195.02 224.1 195.37 224.26 195.74C224.42 196.11 224.55 196.49 224.64 196.88C224.73 197.27 224.78 197.67 224.79 198.07C224.8 198.47 224.77 198.87 224.7 199.27C224.63 199.66 224.52 200.05 224.38 200.42C224.23 200.79 224.05 201.15 223.83 201.49C223.56 201.92 223.23 202.32 222.86 202.68C222.48 203.03 222.07 203.33 221.62 203.58C221.16 203.83 220.68 204.02 220.19 204.15C219.69 204.27 219.17 204.34 218.66 204.34C218.55 204.34 218.44 204.32 218.32 204.31C217.37 207.81 217.58 212.42 218.29 215.58C218.41 215.57 218.54 215.56 218.66 215.56C218.95 215.56 219.24 215.58 219.52 215.62C219.81 215.66 220.09 215.72 220.36 215.8C220.64 215.88 220.91 215.98 221.17 216.1C221.43 216.21 221.69 216.35 221.93 216.5C222.27 216.72 222.59 216.96 222.88 217.24C223.17 217.52 223.44 217.82 223.67 218.15C223.9 218.48 224.1 218.83 224.26 219.2C224.42 219.57 224.55 219.95 224.64 220.35C224.73 220.74 224.78 221.14 224.79 221.54C224.8 221.94 224.77 222.34 224.7 222.73C224.63 223.12 224.52 223.51 224.38 223.88C224.23 224.26 224.05 224.61 223.83 224.95C223.56 225.39 223.23 225.79 222.86 226.14C222.48 226.49 222.07 226.8 221.62 227.05C221.16 227.29 220.68 227.48 220.19 227.61C219.69 227.74 219.17 227.8 218.66 227.8C218.34 227.8 218.03 227.78 217.72 227.73C217.4 227.68 217.1 227.6 216.8 227.51C216.49 227.41 216.2 227.29 215.92 227.15C215.64 227.01 215.37 226.84 215.11 226.66C214.88 226.5 214.65 226.31 214.45 226.12C214.24 225.92 214.04 225.71 213.87 225.49C213.69 225.26 213.52 225.03 213.38 224.78C213.24 224.53 213.11 224.28 213 224.01ZM216.88 197.09C216.74 197.31 216.64 197.56 216.59 197.83C216.54 198.09 216.54 198.36 216.59 198.62C216.64 198.88 216.74 199.14 216.89 199.36C217.03 199.59 217.22 199.78 217.44 199.94L217.53 200C218.51 200.62 219.85 200.3 220.44 199.34C220.52 199.23 220.58 199.11 220.63 198.98C220.68 198.85 220.72 198.72 220.74 198.58C220.77 198.44 220.78 198.31 220.78 198.17C220.77 198.03 220.76 197.89 220.73 197.76C220.6 197.2 220.27 196.73 219.79 196.43C219.45 196.22 219.06 196.1 218.66 196.1C218.49 196.1 218.31 196.13 218.14 196.17C217.97 196.21 217.8 196.28 217.64 196.36C217.49 196.45 217.35 196.55 217.22 196.68C217.09 196.8 216.97 196.93 216.88 197.09ZM216.88 220.55C216.74 220.77 216.64 221.03 216.59 221.29C216.54 221.55 216.54 221.82 216.59 222.09C216.64 222.35 216.74 222.6 216.89 222.82C217.03 223.05 217.22 223.24 217.44 223.4L217.53 223.46C218.51 224.08 219.85 223.76 220.44 222.81C220.52 222.69 220.58 222.57 220.63 222.44C220.68 222.31 220.72 222.18 220.74 222.04C220.77 221.91 220.78 221.77 220.78 221.63C220.77 221.49 220.76 221.36 220.72 221.22C220.6 220.67 220.27 220.2 219.79 219.89C219.45 219.68 219.06 219.57 218.66 219.57C218.49 219.57 218.31 219.59 218.14 219.63C217.97 219.68 217.8 219.74 217.64 219.83C217.49 219.91 217.35 220.02 217.22 220.14C217.09 220.26 216.97 220.4 216.88 220.55ZM216.88 246.85C216.74 247.08 216.64 247.33 216.59 247.59C216.54 247.86 216.54 248.13 216.59 248.39C216.64 248.65 216.74 248.9 216.89 249.13C217.03 249.35 217.22 249.55 217.44 249.7L217.53 249.76C218.51 250.38 219.85 250.06 220.44 249.11C220.52 249 220.58 248.87 220.63 248.74C220.68 248.62 220.72 248.48 220.74 248.35C220.77 248.21 220.78 248.07 220.78 247.94C220.77 247.8 220.76 247.66 220.72 247.53C220.6 246.97 220.27 246.5 219.79 246.2C219.45 245.98 219.06 245.87 218.66 245.87C218.49 245.87 218.31 245.89 218.14 245.94C217.97 245.98 217.8 246.05 217.64 246.13C217.49 246.22 217.35 246.32 217.22 246.44C217.09 246.56 216.97 246.7 216.88 246.85Z" />
+ <g id="Layer" style="opacity: 0.251">
+ <path id="Layer" class="shp2" d="M151.78 249.54C151.54 249.54 151.3 249.47 151.09 249.32C150.96 249.23 150.85 249.11 150.77 248.98C150.68 248.84 150.63 248.69 150.6 248.54C150.57 248.38 150.58 248.22 150.61 248.06C150.65 247.91 150.71 247.76 150.8 247.63C151.07 247.25 151.32 246.84 151.53 246.41C151.88 245.71 152.14 244.96 152.3 244.2C152.46 243.43 152.52 242.64 152.47 241.86C152.43 241.08 152.28 240.3 152.04 239.56C151.8 238.81 151.46 238.1 151.03 237.45C150.86 237.18 150.8 236.85 150.87 236.54C150.93 236.22 151.12 235.95 151.39 235.78C151.66 235.6 151.99 235.54 152.3 235.61C152.62 235.68 152.89 235.87 153.06 236.14C155.24 239.53 155.48 243.88 153.7 247.48C153.63 247.61 153.56 247.75 153.49 247.88C153.42 248.01 153.34 248.14 153.27 248.27C153.19 248.4 153.11 248.53 153.03 248.65C152.95 248.78 152.86 248.9 152.78 249.03C152.72 249.11 152.66 249.18 152.58 249.24C152.51 249.3 152.43 249.36 152.34 249.4C152.26 249.45 152.16 249.48 152.07 249.5C151.98 249.53 151.88 249.54 151.78 249.54M157.34 252.41C157.12 252.41 156.9 252.35 156.71 252.23C156.52 252.12 156.37 251.95 156.27 251.75C156.17 251.55 156.12 251.33 156.14 251.11C156.16 250.88 156.24 250.67 156.37 250.49C156.82 249.88 157.22 249.21 157.57 248.52C158.11 247.43 158.51 246.26 158.73 245.06C158.96 243.86 159.02 242.64 158.91 241.42C158.8 240.2 158.52 239.01 158.08 237.87C157.64 236.73 157.05 235.65 156.32 234.67C156.13 234.42 156.05 234.09 156.09 233.78C156.14 233.46 156.31 233.18 156.57 232.98C156.82 232.79 157.15 232.71 157.46 232.76C157.78 232.8 158.06 232.98 158.25 233.23C159.12 234.39 159.82 235.66 160.34 237C160.86 238.35 161.18 239.76 161.31 241.2C161.44 242.64 161.37 244.09 161.11 245.5C160.84 246.92 160.38 248.3 159.73 249.59C159.33 250.41 158.85 251.19 158.32 251.92C158.26 252 158.2 252.07 158.13 252.13C158.05 252.19 157.97 252.24 157.89 252.28C157.8 252.33 157.71 252.36 157.62 252.38C157.53 252.4 157.43 252.41 157.34 252.41ZM146.34 246.49C146.13 246.48 145.93 246.43 145.75 246.32C145.57 246.22 145.41 246.06 145.31 245.88C145.2 245.7 145.15 245.49 145.15 245.28C145.14 245.07 145.2 244.87 145.3 244.68C145.49 244.35 145.63 244 145.74 243.64C145.84 243.27 145.9 242.9 145.92 242.52C145.93 242.14 145.9 241.76 145.83 241.39C145.76 241.02 145.64 240.66 145.48 240.31C145.36 240.03 145.36 239.7 145.47 239.41C145.58 239.12 145.81 238.88 146.09 238.75C146.37 238.62 146.7 238.61 146.99 238.71C147.29 238.81 147.53 239.03 147.67 239.31C147.91 239.82 148.09 240.37 148.2 240.92C148.31 241.48 148.35 242.05 148.33 242.62C148.31 243.19 148.21 243.76 148.06 244.3C147.9 244.85 147.68 245.38 147.4 245.88C147.35 245.97 147.28 246.05 147.21 246.13C147.13 246.2 147.05 246.27 146.96 246.32C146.86 246.38 146.76 246.42 146.66 246.45C146.56 246.47 146.45 246.49 146.34 246.49" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" class="shp0" d="M151.78 246.54C151.54 246.54 151.3 246.47 151.09 246.32C150.96 246.23 150.85 246.11 150.77 245.98C150.68 245.84 150.63 245.69 150.6 245.54C150.57 245.38 150.58 245.22 150.61 245.06C150.65 244.91 150.71 244.76 150.8 244.63C151.07 244.25 151.32 243.84 151.53 243.41C151.88 242.71 152.14 241.96 152.3 241.2C152.46 240.43 152.52 239.64 152.47 238.86C152.43 238.08 152.28 237.3 152.04 236.56C151.8 235.81 151.46 235.1 151.03 234.45C150.86 234.18 150.8 233.85 150.87 233.54C150.93 233.22 151.12 232.95 151.39 232.78C151.66 232.6 151.99 232.54 152.3 232.61C152.62 232.68 152.89 232.87 153.06 233.14C155.24 236.53 155.48 240.88 153.7 244.48C153.63 244.61 153.56 244.75 153.49 244.88C153.42 245.01 153.34 245.14 153.27 245.27C153.19 245.4 153.11 245.53 153.03 245.65C152.95 245.78 152.86 245.9 152.78 246.03C152.72 246.11 152.66 246.18 152.58 246.24C152.51 246.3 152.43 246.36 152.34 246.4C152.26 246.45 152.16 246.48 152.07 246.5C151.98 246.53 151.88 246.54 151.78 246.54M157.34 249.41C157.12 249.41 156.9 249.35 156.71 249.23C156.52 249.12 156.37 248.95 156.27 248.75C156.17 248.55 156.12 248.33 156.14 248.11C156.16 247.88 156.24 247.67 156.37 247.49C156.82 246.88 157.22 246.21 157.57 245.52C158.11 244.43 158.51 243.26 158.73 242.06C158.96 240.86 159.02 239.64 158.91 238.42C158.8 237.2 158.52 236.01 158.08 234.87C157.64 233.73 157.05 232.65 156.32 231.67C156.13 231.42 156.05 231.09 156.09 230.78C156.14 230.46 156.31 230.18 156.57 229.98C156.82 229.79 157.15 229.71 157.46 229.76C157.78 229.8 158.06 229.98 158.25 230.23C159.12 231.39 159.82 232.66 160.34 234C160.86 235.35 161.18 236.76 161.31 238.2C161.44 239.64 161.37 241.09 161.11 242.5C160.84 243.92 160.38 245.3 159.73 246.59C159.33 247.41 158.85 248.19 158.32 248.92C158.26 249 158.2 249.07 158.13 249.13C158.05 249.19 157.97 249.24 157.89 249.28C157.8 249.33 157.71 249.36 157.62 249.38C157.53 249.4 157.43 249.41 157.34 249.41ZM146.34 243.49C146.13 243.48 145.93 243.43 145.75 243.32C145.57 243.22 145.41 243.06 145.31 242.88C145.2 242.7 145.15 242.49 145.15 242.28C145.14 242.07 145.2 241.87 145.3 241.68C145.49 241.35 145.63 241 145.74 240.64C145.84 240.27 145.9 239.9 145.92 239.52C145.93 239.14 145.9 238.76 145.83 238.39C145.76 238.02 145.64 237.66 145.48 237.31C145.36 237.03 145.36 236.7 145.47 236.41C145.58 236.12 145.81 235.88 146.09 235.75C146.37 235.62 146.7 235.61 146.99 235.71C147.29 235.81 147.53 236.03 147.67 236.31C147.91 236.82 148.09 237.37 148.2 237.92C148.31 238.48 148.35 239.05 148.33 239.62C148.31 240.19 148.21 240.76 148.06 241.3C147.9 241.85 147.68 242.38 147.4 242.88C147.35 242.97 147.28 243.05 147.21 243.13C147.13 243.2 147.05 243.27 146.96 243.32C146.86 243.38 146.76 243.42 146.66 243.45C146.56 243.47 146.45 243.49 146.34 243.49" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp5" d="M164.08 192.24C165.2 192.24 167.16 192.28 168.36 192.39L168.36 195.88C167.32 195.78 165.12 195.74 164.08 195.74C154.95 195.74 145.38 199.12 139.72 204.35C135.15 208.57 132.19 214.61 131.03 221.84C130.8 223.29 130.66 225.08 130.6 226.94C130.89 225.07 132.31 223.65 134.03 223.65L135.93 223.65C137.86 223.65 139.42 225.44 139.42 227.65L139.42 257.32C139.42 259.53 137.86 261.32 135.93 261.32L134.03 261.32C132.1 261.32 130.53 259.53 130.53 257.32L130.53 255.72C130.24 255.79 129.94 255.83 129.62 255.83L127.59 255.83C127.06 255.83 126.54 255.73 126.06 255.53C125.57 255.33 125.13 255.03 124.76 254.66C124.39 254.29 124.09 253.85 123.89 253.36C123.69 252.88 123.59 252.36 123.59 251.83L123.59 233.71C123.59 233.24 123.67 232.77 123.84 232.32C124.01 231.88 124.25 231.47 124.56 231.11C124.87 230.75 125.24 230.45 125.66 230.22C126.08 229.99 126.53 229.84 127 229.77C126.82 218.03 130.46 208.14 137.35 201.78C143.72 195.9 153.96 192.24 164.08 192.24ZM129.62 251.43L130.54 251.43L130.54 234.12L129.62 234.12C129.27 234.12 128.93 234.18 128.61 234.32C128.29 234.45 127.99 234.65 127.75 234.89C127.5 235.14 127.31 235.43 127.17 235.75C127.04 236.07 126.97 236.42 126.97 236.77L126.97 248.78C126.97 249.13 127.04 249.47 127.17 249.79C127.31 250.11 127.5 250.41 127.75 250.65C128 250.9 128.29 251.09 128.61 251.23C128.93 251.36 129.27 251.43 129.62 251.43Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M164.08 189.24C165.2 189.24 167.16 189.28 168.36 189.39L168.36 192.88C167.32 192.78 165.12 192.74 164.08 192.74C154.95 192.74 145.38 196.12 139.72 201.35C135.15 205.57 132.19 211.61 131.03 218.84C130.8 220.29 130.66 222.08 130.6 223.94C130.89 222.07 132.31 220.65 134.03 220.65L135.93 220.65C137.86 220.65 139.42 222.44 139.42 224.65L139.42 254.32C139.42 256.53 137.86 258.32 135.93 258.32L134.03 258.32C132.1 258.32 130.53 256.53 130.53 254.32L130.53 252.72C130.24 252.79 129.94 252.83 129.62 252.83L127.59 252.83C127.06 252.83 126.54 252.73 126.06 252.53C125.57 252.33 125.13 252.03 124.76 251.66C124.39 251.29 124.09 250.85 123.89 250.36C123.69 249.88 123.59 249.36 123.59 248.83L123.59 230.71C123.59 230.24 123.67 229.77 123.84 229.32C124.01 228.88 124.25 228.47 124.56 228.11C124.87 227.75 125.24 227.45 125.66 227.22C126.08 226.99 126.53 226.84 127 226.77C126.82 215.03 130.46 205.14 137.35 198.78C143.72 192.9 153.96 189.24 164.08 189.24ZM129.62 248.43L130.54 248.43L130.54 231.12L129.62 231.12C129.27 231.12 128.93 231.18 128.61 231.32C128.29 231.45 127.99 231.65 127.75 231.89C127.5 232.14 127.31 232.43 127.17 232.75C127.04 233.07 126.97 233.42 126.97 233.77L126.97 245.78C126.97 246.13 127.04 246.47 127.17 246.79C127.31 247.11 127.5 247.41 127.75 247.65C128 247.9 128.29 248.09 128.61 248.23C128.93 248.36 129.27 248.43 129.62 248.43Z" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp1" d="M295.75 242.67L295.75 252.82L259.58 252.82L259.58 198.08L272.78 198.08L272.78 242.67L295.75 242.67ZM300.63 201.65C300.63 199.85 301.29 198.37 302.59 197.22C303.89 196.06 305.59 195.49 307.67 195.49C309.75 195.49 311.44 196.06 312.74 197.22C314.04 198.37 314.7 199.85 314.7 201.65C314.7 203.46 314.05 204.94 312.74 206.09C311.44 207.24 309.75 207.82 307.67 207.82C305.59 207.82 303.89 207.24 302.59 206.09C301.29 204.94 300.63 203.46 300.63 201.65ZM314.1 252.82L301.39 252.82L301.39 212.14L314.1 212.14L314.1 252.82ZM341.5 238.8C340.38 238.15 338.23 237.47 335.07 236.77C331.92 236.07 329.31 235.15 327.25 234.01C325.2 232.87 323.63 231.48 322.55 229.85C321.48 228.22 320.94 226.36 320.94 224.25C320.94 220.51 322.48 217.44 325.56 215.02C328.64 212.6 332.68 211.39 337.67 211.39C343.03 211.39 347.34 212.61 350.6 215.04C353.86 217.47 355.49 220.66 355.49 224.63L342.78 224.63C342.78 221.37 341.06 219.74 337.63 219.74C336.3 219.74 335.19 220.11 334.28 220.85C333.38 221.58 332.93 222.51 332.93 223.61C332.93 224.74 333.48 225.65 334.58 226.35C335.69 227.06 337.45 227.63 339.87 228.08C342.29 228.53 344.41 229.07 346.24 229.7C352.36 231.8 355.41 235.58 355.41 241.02C355.41 244.73 353.77 247.75 350.47 250.08C347.17 252.41 342.91 253.57 337.67 253.57C334.18 253.57 331.08 252.95 328.34 251.69C325.61 250.44 323.48 248.74 321.95 246.58C320.42 244.43 319.66 242.16 319.66 239.77L331.5 239.77C331.55 241.66 332.18 243.03 333.38 243.89C334.58 244.76 336.13 245.19 338.01 245.19C339.74 245.19 341.03 244.84 341.9 244.14C342.76 243.44 343.19 242.52 343.19 241.39C343.19 240.32 342.63 239.45 341.5 238.8ZM376.09 212.14L382.79 212.14L382.79 220.94L376.09 220.94L376.09 239.55C376.09 241.08 376.37 242.15 376.92 242.75C377.47 243.35 378.56 243.65 380.19 243.65C381.44 243.65 382.5 243.57 383.35 243.42L383.35 252.49C382.77 252.67 382.19 252.83 381.6 252.96C381.01 253.1 380.42 253.22 379.82 253.31C379.22 253.4 378.62 253.47 378.02 253.51C377.41 253.56 376.81 253.58 376.21 253.57C371.84 253.57 368.62 252.55 366.54 250.49C364.46 248.44 363.42 245.32 363.42 241.13L363.42 220.94L358.23 220.94L358.23 212.14L363.42 212.14L363.42 202.03L376.09 202.03L376.09 212.14ZM392.3 247.99C388.44 244.27 386.51 239.43 386.51 233.46L386.51 232.41C386.51 228.25 387.28 224.58 388.82 221.39C390.36 218.21 392.61 215.75 395.57 214C398.53 212.26 402.04 211.39 406.1 211.39C411.81 211.39 416.32 213.16 419.63 216.71C422.94 220.26 424.59 225.2 424.59 231.54L424.59 236.47L399.41 236.47C399.86 238.75 400.85 240.54 402.38 241.84C403.9 243.15 405.88 243.8 408.32 243.8C412.33 243.8 415.46 242.4 417.72 239.59L423.5 246.43C421.93 248.61 419.69 250.35 416.79 251.64C413.9 252.93 410.78 253.57 407.45 253.57C401.21 253.57 396.16 251.71 392.3 247.99ZM399.4 228.53L412.19 228.53L412.19 227.56C412.24 225.53 411.72 223.95 410.65 222.84C409.57 221.72 408.03 221.17 406.02 221.17C402.31 221.17 400.11 223.62 399.4 228.53ZM441.74 216.92C444.55 213.23 448.42 211.39 453.36 211.39C457.59 211.39 460.76 212.66 462.85 215.19C464.94 217.72 466.03 221.53 466.1 226.62L466.1 252.82L453.39 252.82L453.39 227.14C453.39 225.09 452.98 223.58 452.15 222.61C451.33 221.65 449.82 221.17 447.64 221.17C445.16 221.17 443.32 222.14 442.11 224.1L442.11 252.82L429.44 252.82L429.44 212.14L441.32 212.14L441.74 216.92Z" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp0" d="M473.64 198.08L493.3 198.08C500.34 198.08 505.7 199.37 509.37 201.95C513.05 204.54 514.88 208.28 514.88 213.2C514.88 216.03 514.23 218.45 512.93 220.45C511.62 222.46 509.71 223.94 507.18 224.89C510.03 225.64 512.23 227.05 513.75 229.1C515.28 231.15 516.05 233.66 516.05 236.62C516.05 241.98 514.35 246.01 510.95 248.71C507.56 251.4 502.52 252.77 495.86 252.82L473.64 252.82L473.64 198.08ZM486.83 220.9L493.72 220.9C496.6 220.88 498.65 220.35 499.88 219.32C501.11 218.29 501.72 216.77 501.72 214.76C501.72 212.44 501.06 210.78 499.73 209.76C498.4 208.74 496.26 208.23 493.3 208.23L486.83 208.23L486.83 220.9ZM486.83 229.55L486.83 242.67L495.48 242.67C497.86 242.67 499.69 242.13 500.97 241.04C502.25 239.95 502.89 238.41 502.89 236.43C502.89 231.87 500.62 229.58 496.08 229.55L486.83 229.55ZM547.33 223.61L543.15 223.31C539.17 223.31 536.61 224.56 535.48 227.07L535.48 252.82L522.81 252.82L522.81 212.14L534.69 212.14L535.11 217.37C537.24 213.38 540.21 211.39 544.02 211.39C545.37 211.39 546.55 211.54 547.55 211.84L547.33 223.61ZM573.73 252.82C573.28 252 572.88 250.78 572.53 249.18C570.2 252.11 566.94 253.57 562.76 253.57C558.92 253.57 555.66 252.42 552.98 250.1C550.3 247.78 548.96 244.87 548.96 241.36C548.96 236.94 550.59 233.61 553.85 231.35C557.11 229.1 561.84 227.97 568.06 227.97L571.97 227.97L571.97 225.82C571.97 222.06 570.35 220.19 567.12 220.19C564.11 220.19 562.61 221.67 562.61 224.65L549.94 224.65C549.94 220.72 551.61 217.52 554.96 215.07C558.3 212.62 562.57 211.39 567.76 211.39C572.95 211.39 577.04 212.66 580.05 215.19C583.06 217.72 584.6 221.19 584.68 225.6L584.68 243.61C584.73 247.34 585.3 250.2 586.41 252.18L586.41 252.82L573.73 252.82L573.73 252.82ZM569.73 243.54C570.77 242.86 571.52 242.1 571.97 241.24L571.97 234.74L568.28 234.74C563.87 234.74 561.67 236.72 561.67 240.68C561.67 241.83 562.05 242.76 562.83 243.48C563.61 244.19 564.6 244.55 565.8 244.55C567.38 244.55 568.69 244.21 569.73 243.54ZM591.59 201.65C591.59 199.85 592.25 198.37 593.55 197.22C594.85 196.06 596.54 195.49 598.63 195.49C600.7 195.49 602.4 196.06 603.7 197.22C605 198.37 605.65 199.85 605.65 201.65C605.65 203.46 605 204.94 603.7 206.09C602.4 207.24 600.7 207.82 598.63 207.82C596.54 207.82 594.85 207.24 593.55 206.09C592.25 204.94 591.59 203.46 591.59 201.65ZM605.05 252.82L592.35 252.82L592.35 212.14L605.05 212.14L605.05 252.82ZM624.49 212.14L624.91 216.92C627.71 213.23 631.58 211.39 636.52 211.39C640.76 211.39 643.92 212.66 646.02 215.19C648.11 217.72 649.19 221.53 649.27 226.62L649.27 252.82L636.56 252.82L636.56 227.14C636.56 225.09 636.15 223.58 635.32 222.61C634.49 221.65 632.99 221.17 630.81 221.17C628.33 221.17 626.48 222.14 625.28 224.1L625.28 252.82L612.61 252.82L612.61 212.14L624.49 212.14ZM689.76 243.05L689.76 252.82L655.21 252.82L655.21 245.75L673.26 221.92L656 221.92L656 212.14L689.35 212.14L689.35 218.99L671.23 243.05L689.76 243.05Z" />
+ </g>
+</svg> \ No newline at end of file
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md
new file mode 100644
index 0000000000..774e383f8b
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md
@@ -0,0 +1,23 @@
+# ListenBrainz logo attribution
+
+The file `ListenBrainz_logo.svg` shipped alongside this plugin is a derivative
+work used here under the terms of the Creative Commons Attribution-ShareAlike
+4.0 International license (CC BY-SA 4.0).
+
+## Attribution chain
+
+1. Original work: [ListenBrainz logo](https://github.com/metabrainz/metabrainz-logos/commit/10127d3e84e5bb7e1c8509f1da12223d19581e18)
+ by [MonkeyDo](https://github.com/metabrainz/metabrainz-logos/commits?author=MonkeyDo)
+ at the [MetaBrainz Foundation](https://github.com/metabrainz), licensed under
+ CC BY-SA 4.0.
+2. "ListenBrainz logo for Jellyfin plugin" — derivative by
+ [lyarenei](https://github.com/lyarenei), distributed in
+ [jellyfin-plugin-listenbrainz](https://github.com/lyarenei/jellyfin-plugin-listenbrainz/tree/main/res/listenbrainz)
+ under CC BY-SA 4.0.
+3. This redistribution within Jellyfin retains the work unmodified and remains
+ licensed under CC BY-SA 4.0 per the license's ShareAlike requirement.
+
+## License
+
+A full copy of the CC BY-SA 4.0 license is available at
+<https://creativecommons.org/licenses/by-sa/4.0/legalcode>.
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs
new file mode 100644
index 0000000000..6f60d18c33
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs
@@ -0,0 +1,65 @@
+using MediaBrowser.Model.Plugins;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// ListenBrainz plugin configuration.
+/// </summary>
+public class PluginConfiguration : BasePluginConfiguration
+{
+ /// <summary>
+ /// The default Labs API server URL.
+ /// </summary>
+ public const string DefaultLabsServer = "https://labs.api.listenbrainz.org";
+
+ /// <summary>
+ /// The default rate limit in seconds.
+ /// </summary>
+ public const double DefaultRateLimit = 1.0;
+
+ private string _labsServer = DefaultLabsServer;
+ private double _rateLimit = DefaultRateLimit;
+
+ /// <summary>
+ /// Gets or sets the Labs API server URL.
+ /// </summary>
+ public string LabsServer
+ {
+ get => _labsServer;
+ set => _labsServer = string.IsNullOrWhiteSpace(value) ? DefaultLabsServer : value.TrimEnd('/');
+ }
+
+ /// <summary>
+ /// Gets or sets the similarity algorithm.
+ /// </summary>
+ public SimilarityAlgorithm Algorithm { get; set; } = SimilarityAlgorithm.SessionBased1825Days;
+
+ /// <summary>
+ /// Gets or sets the rate limit in seconds.
+ /// </summary>
+ public double RateLimit
+ {
+ get => _rateLimit;
+ set
+ {
+ if (value < DefaultRateLimit && _labsServer == DefaultLabsServer)
+ {
+ _rateLimit = DefaultRateLimit;
+ }
+ else
+ {
+ _rateLimit = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the cache duration in days for similar item results. A value of 0 disables caching.
+ /// </summary>
+ public int SimilarItemsCacheDays { get; set; } = 14;
+
+ /// <summary>
+ /// Gets the algorithm string for the API call.
+ /// </summary>
+ public string AlgorithmString => Algorithm.ToApiString();
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs
new file mode 100644
index 0000000000..f297d99f6d
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs
@@ -0,0 +1,37 @@
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// Available similarity algorithms for ListenBrainz Labs API.
+/// </summary>
+public enum SimilarityAlgorithm
+{
+ /// <summary>
+ /// Session-based algorithm analyzing ~5 years of listening data.
+ /// </summary>
+ SessionBased1825Days = 0,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~5 years of listening data (alternate).
+ /// </summary>
+ SessionBased1800Days = 1,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~20 years of listening data.
+ /// </summary>
+ SessionBased7500Days = 2,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~20 years with higher contribution threshold.
+ /// </summary>
+ SessionBased7500DaysHighContribution = 3,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~25 years of listening data.
+ /// </summary>
+ SessionBased9000Days = 4,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~75 days of recent listening data.
+ /// </summary>
+ SessionBased75Days = 5
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs
new file mode 100644
index 0000000000..f7874dbae8
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs
@@ -0,0 +1,23 @@
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// Extension methods for <see cref="SimilarityAlgorithm"/>.
+/// </summary>
+public static class SimilarityAlgorithmExtensions
+{
+ /// <summary>
+ /// Gets the API string value for the algorithm.
+ /// </summary>
+ /// <param name="algorithm">The algorithm.</param>
+ /// <returns>The API string value.</returns>
+ public static string ToApiString(this SimilarityAlgorithm algorithm) => algorithm switch
+ {
+ SimilarityAlgorithm.SessionBased1825Days => "session_based_days_1825_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased1800Days => "session_based_days_1800_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased7500Days => "session_based_days_7500_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased7500DaysHighContribution => "session_based_days_7500_session_300_contribution_5_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased9000Days => "session_based_days_9000_session_300_contribution_5_threshold_15_limit_50_skip_30",
+ SimilarityAlgorithm.SessionBased75Days => "session_based_days_75_session_300_contribution_5_threshold_10_limit_100_filter_True_skip_30",
+ _ => "session_based_days_1825_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30"
+ };
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html
new file mode 100644
index 0000000000..dec21d1b42
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>ListenBrainz</title>
+</head>
+<body>
+ <div id="configPage" data-role="page" class="page type-interior pluginConfigurationPage configPage" data-require="emby-input,emby-button,emby-select">
+ <div data-role="content">
+ <div class="content-primary">
+ <img id="listenBrainzLogo" alt="ListenBrainz" style="max-width:240px;display:block;margin:0 auto 1em;" />
+ <h1>ListenBrainz</h1>
+ <p>Get similar artist recommendations from ListenBrainz Labs.</p>
+ <form class="configForm">
+ <div class="inputContainer">
+ <input is="emby-input" type="text" id="labsServer" required label="Labs API Server" />
+ <div class="fieldDescription">The ListenBrainz Labs API server URL. Default: https://labs.api.listenbrainz.org</div>
+ </div>
+ <div class="selectContainer">
+ <label class="selectLabel" for="algorithm">Similarity Algorithm</label>
+ <select is="emby-select" id="algorithm" class="emby-select-withcolor">
+ <option value="0" selected>~5 years / 1825 days (Recommended)</option>
+ <option value="1">~5 years / 1800 days</option>
+ <option value="2">~20 years / 7500 days</option>
+ <option value="3">~20 years / 7500 days (high contribution)</option>
+ <option value="4">~25 years / 9000 days</option>
+ <option value="5">~75 days (recent)</option>
+ </select>
+ <div class="fieldDescription">The algorithm used for artist similarity calculation.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="rateLimit" required pattern="[0-9]*" min="0" max="10" step=".01" label="Rate Limit (seconds)" />
+ <div class="fieldDescription">Span of time between requests in seconds. The official server is rate limited to one request per second.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="similarItemsCacheDays" required pattern="[0-9]*" min="0" max="365" label="Cache duration (days)" />
+ <div class="fieldDescription">Number of days to cache similar artist results from ListenBrainz. Set to 0 to disable caching.</div>
+ </div>
+ <br />
+ <div>
+ <button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
+ </div>
+ </form>
+ <div class="verticalSection" style="margin-top:2em;font-size:0.85em;opacity:0.8;">
+ <p>The ListenBrainz logo is &copy; the MetaBrainz Foundation (by MonkeyDo),
+ adapted for Jellyfin plugin use by
+ <a href="https://github.com/lyarenei" target="_blank" rel="noopener">lyarenei</a>,
+ and redistributed here under
+ <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener">CC BY-SA 4.0</a>.
+ Full attribution notice is shipped alongside the plugin in <code>NOTICE.md</code>.</p>
+ </div>
+ </div>
+ </div>
+ <script type="text/javascript">
+ var ListenBrainzPluginConfig = {
+ uniquePluginId: "a5b2e8c1-9d4f-4a3b-8c7e-6f1a2b3c4d5e"
+ };
+
+ document.querySelector('.configPage')
+ .addEventListener('pageshow', function () {
+ Dashboard.showLoadingMsg();
+ document.querySelector('#listenBrainzLogo').src = ApiClient.getUrl('web/ConfigurationPage', { name: 'ListenBrainzLogo' });
+ ApiClient.getPluginConfiguration(ListenBrainzPluginConfig.uniquePluginId).then(function (config) {
+ var labsServer = document.querySelector('#labsServer');
+ labsServer.value = config.LabsServer;
+ labsServer.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ document.querySelector('#algorithm').value = config.Algorithm;
+
+ var rateLimit = document.querySelector('#rateLimit');
+ rateLimit.value = config.RateLimit;
+ rateLimit.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ var similarItemsCacheDays = document.querySelector('#similarItemsCacheDays');
+ similarItemsCacheDays.value = config.SimilarItemsCacheDays;
+ similarItemsCacheDays.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ Dashboard.hideLoadingMsg();
+ });
+ });
+
+ document.querySelector('.configForm')
+ .addEventListener('submit', function (e) {
+ Dashboard.showLoadingMsg();
+
+ ApiClient.getPluginConfiguration(ListenBrainzPluginConfig.uniquePluginId).then(function (config) {
+ config.LabsServer = document.querySelector('#labsServer').value;
+ config.Algorithm = parseInt(document.querySelector('#algorithm').value, 10);
+ config.RateLimit = document.querySelector('#rateLimit').value;
+ config.SimilarItemsCacheDays = parseInt(document.querySelector('#similarItemsCacheDays').value, 10);
+
+ ApiClient.updatePluginConfiguration(ListenBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
+ });
+
+ e.preventDefault();
+ return false;
+ });
+ </script>
+ </div>
+</body>
+</html>
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs
new file mode 100644
index 0000000000..efac93f94e
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz;
+
+/// <summary>
+/// ListenBrainz plugin instance.
+/// </summary>
+public class ListenBrainzPlugin : BasePlugin<PluginConfiguration>, IHasWebPages
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzPlugin"/> class.
+ /// </summary>
+ /// <param name="applicationPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
+ /// <param name="xmlSerializer">Instance of the <see cref="IXmlSerializer"/> interface.</param>
+ public ListenBrainzPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
+ : base(applicationPaths, xmlSerializer)
+ {
+ Instance = this;
+ }
+
+ /// <summary>
+ /// Gets the current plugin instance.
+ /// </summary>
+ public static ListenBrainzPlugin? Instance { get; private set; }
+
+ /// <inheritdoc />
+ public override Guid Id => new("a5b2e8c1-9d4f-4a3b-8c7e-6f1a2b3c4d5e");
+
+ /// <inheritdoc />
+ public override string Name => "ListenBrainz Similarity Provider";
+
+ /// <inheritdoc />
+ public override string Description => "Get similar artist recommendations from ListenBrainz Labs.";
+
+ /// <inheritdoc />
+ public override string ConfigurationFileName => "Jellyfin.Plugin.ListenBrainz.xml";
+
+ /// <inheritdoc />
+ public IEnumerable<PluginPageInfo> GetPages()
+ {
+ var resourcePrefix = GetType().Namespace + ".Configuration.";
+ yield return new PluginPageInfo
+ {
+ Name = Name,
+ EmbeddedResourcePath = resourcePrefix + "config.html"
+ };
+ yield return new PluginPageInfo
+ {
+ Name = Name + "Logo",
+ EmbeddedResourcePath = resourcePrefix + "ListenBrainz_logo.svg"
+ };
+ yield return new PluginPageInfo
+ {
+ Name = Name + "Notice",
+ EmbeddedResourcePath = resourcePrefix + "NOTICE.md"
+ };
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs
new file mode 100644
index 0000000000..3dca748d06
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Api;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz;
+
+/// <summary>
+/// ListenBrainz-based similar items provider for music artists.
+/// </summary>
+public class ListenBrainzSimilarArtistProvider : IRemoteSimilarItemsProvider<MusicArtist>
+{
+ private readonly ListenBrainzLabsClient _labsClient;
+ private readonly ILogger<ListenBrainzSimilarArtistProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzSimilarArtistProvider"/> class.
+ /// </summary>
+ /// <param name="labsClient">The ListenBrainz Labs API client.</param>
+ /// <param name="logger">The logger.</param>
+ public ListenBrainzSimilarArtistProvider(
+ ListenBrainzLabsClient labsClient,
+ ILogger<ListenBrainzSimilarArtistProvider> logger)
+ {
+ _labsClient = labsClient;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "ListenBrainz";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = ListenBrainzPlugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ MusicArtist item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ ArgumentNullException.ThrowIfNull(item);
+ ArgumentNullException.ThrowIfNull(query);
+
+ if (!item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var mbidStr) || !Guid.TryParse(mbidStr, out var mbid))
+ {
+ _logger.LogDebug("No MusicBrainz Artist ID found for {ArtistName}", item.Name);
+ yield break;
+ }
+
+ IReadOnlyList<Guid> similarMbids;
+ try
+ {
+ similarMbids = await _labsClient.GetSimilarArtistsAsync(mbid, cancellationToken).ConfigureAwait(false);
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogWarning(ex, "Failed to fetch similar artists from ListenBrainz for {ArtistMbid}", mbid);
+ yield break;
+ }
+
+ var providerName = MetadataProvider.MusicBrainzArtist.ToString();
+
+ foreach (var similarMbid in similarMbids)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similarMbid.ToString()
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
index f11b1d95aa..78405c21fc 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
@@ -77,5 +77,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// Gets or sets a value indicating the still image size to fetch.
/// </summary>
public string? StillSize { get; set; }
+
+ /// <summary>
+ /// Gets or sets the cache duration in days for similar item results. A value of 0 disables caching.
+ /// </summary>
+ public int SimilarItemsCacheDays { get; set; } = 7;
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
index 89d380ec1f..4048fc1655 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
@@ -44,6 +44,13 @@
<span>Hide crew members without profile images.</span>
</label>
</div>
+ <div class="verticalSection">
+ <h2>Similar Items</h2>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="similarItemsCacheDays" pattern="[0-9]*" required min="0" max="365" label="Cache duration (days)" />
+ <div class="fieldDescription">Number of days to cache similar item results from TMDb. Set to 0 to disable caching.</div>
+ </div>
+ </div>
<div class="verticalSection verticalSection-extrabottompadding">
<h2>Image Scaling</h2>
<div class="selectContainer">
@@ -161,6 +168,13 @@
cancelable: false
}));
+ var similarItemsCacheDays = document.querySelector('#similarItemsCacheDays');
+ similarItemsCacheDays.value = config.SimilarItemsCacheDays;
+ similarItemsCacheDays.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
pluginConfig = config;
configureImageScaling();
});
@@ -179,6 +193,7 @@
config.MaxCrewMembers = document.querySelector('#maxCrewMembers').value;
config.HideMissingCastMembers = document.querySelector('#hideMissingCastMembers').checked;
config.HideMissingCrewMembers = document.querySelector('#hideMissingCrewMembers').checked;
+ config.SimilarItemsCacheDays = parseInt(document.querySelector('#similarItemsCacheDays').value, 10);
config.PosterSize = document.querySelector('#selectPosterSize').value;
config.BackdropSize = document.querySelector('#selectBackdropSize').value;
config.LogoSize = document.querySelector('#selectLogoSize').value;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs
new file mode 100644
index 0000000000..5206de78ce
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using Microsoft.Extensions.Logging;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb.Movies;
+
+/// <summary>
+/// TMDb-based similar items provider for movies.
+/// </summary>
+public class TmdbMovieSimilarProvider : IRemoteSimilarItemsProvider<Movie>
+{
+ private readonly TmdbClientManager _tmdbClientManager;
+ private readonly ILogger<TmdbMovieSimilarProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TmdbMovieSimilarProvider"/> class.
+ /// </summary>
+ /// <param name="tmdbClientManager">The TMDb client manager.</param>
+ /// <param name="logger">The logger.</param>
+ public TmdbMovieSimilarProvider(TmdbClientManager tmdbClientManager, ILogger<TmdbMovieSimilarProvider> logger)
+ {
+ _tmdbClientManager = tmdbClientManager;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => TmdbUtils.ProviderName;
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = Plugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ Movie item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ if (!item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbIdStr) || !int.TryParse(tmdbIdStr, CultureInfo.InvariantCulture, out var tmdbId))
+ {
+ yield break;
+ }
+
+ var providerName = MetadataProvider.Tmdb.ToString();
+ var page = 0;
+ var totalPages = 1;
+
+ while (page <= totalPages && !cancellationToken.IsCancellationRequested)
+ {
+ IReadOnlyList<TMDbLib.Objects.Search.SearchMovie> pageResults;
+ try
+ {
+ (pageResults, totalPages) = await _tmdbClientManager
+ .GetMovieSimilarPageAsync(tmdbId, page, TmdbUtils.GetImageLanguagesParam(string.Empty), cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to get similar movies from TMDb for {TmdbId} page {Page}", tmdbId, page);
+ yield break;
+ }
+
+ if (pageResults.Count == 0)
+ {
+ yield break;
+ }
+
+ foreach (var similar in pageResults)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similar.Id.ToString(CultureInfo.InvariantCulture)
+ };
+ }
+
+ page++;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs
new file mode 100644
index 0000000000..c85718b993
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb.TV;
+
+/// <summary>
+/// TMDb-based similar items provider for TV series.
+/// </summary>
+public class TmdbSeriesSimilarProvider : IRemoteSimilarItemsProvider<Series>
+{
+ private readonly TmdbClientManager _tmdbClientManager;
+ private readonly ILogger<TmdbSeriesSimilarProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TmdbSeriesSimilarProvider"/> class.
+ /// </summary>
+ /// <param name="tmdbClientManager">The TMDb client manager.</param>
+ /// <param name="logger">The logger.</param>
+ public TmdbSeriesSimilarProvider(TmdbClientManager tmdbClientManager, ILogger<TmdbSeriesSimilarProvider> logger)
+ {
+ _tmdbClientManager = tmdbClientManager;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => TmdbUtils.ProviderName;
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = Plugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ Series item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ if (!item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbIdStr) || !int.TryParse(tmdbIdStr, CultureInfo.InvariantCulture, out var tmdbId))
+ {
+ yield break;
+ }
+
+ var providerName = MetadataProvider.Tmdb.ToString();
+ var page = 1;
+ var totalPages = 1;
+
+ while (page <= totalPages && !cancellationToken.IsCancellationRequested)
+ {
+ IReadOnlyList<TMDbLib.Objects.Search.SearchTv> pageResults;
+ try
+ {
+ (pageResults, totalPages) = await _tmdbClientManager
+ .GetSeriesSimilarPageAsync(tmdbId, page, TmdbUtils.GetImageLanguagesParam(string.Empty), cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to get similar TV shows from TMDb for {TmdbId} page {Page}", tmdbId, page);
+ yield break;
+ }
+
+ if (pageResults.Count == 0)
+ {
+ yield break;
+ }
+
+ foreach (var similar in pageResults)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similar.Id.ToString(CultureInfo.InvariantCulture)
+ };
+ }
+
+ page++;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 274db347ba..174f1546a7 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -505,6 +505,54 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
}
/// <summary>
+ /// Gets a single page of similar movies for a movie from the TMDb API.
+ /// </summary>
+ /// <param name="tmdbId">The TMDb id of the movie.</param>
+ /// <param name="page">The page number to fetch (1-based).</param>
+ /// <param name="language">The language for results.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A tuple containing the list of similar movies and the total number of pages available.</returns>
+ public async Task<(IReadOnlyList<SearchMovie> Results, int TotalPages)> GetMovieSimilarPageAsync(int tmdbId, int page, string? language, CancellationToken cancellationToken)
+ {
+ await EnsureClientConfigAsync().ConfigureAwait(false);
+
+ var searchResults = await _tmDbClient
+ .GetMovieSimilarAsync(tmdbId, language, page, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (searchResults?.Results is null || searchResults.Results.Count == 0)
+ {
+ return ([], 0);
+ }
+
+ return (searchResults.Results, searchResults.TotalPages);
+ }
+
+ /// <summary>
+ /// Gets a single page of similar TV shows for a series from the TMDb API.
+ /// </summary>
+ /// <param name="tmdbId">The TMDb id of the TV show.</param>
+ /// <param name="page">The page number to fetch (1-based).</param>
+ /// <param name="language">The language for results.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A tuple containing the list of similar TV shows and the total number of pages available.</returns>
+ public async Task<(IReadOnlyList<SearchTv> Results, int TotalPages)> GetSeriesSimilarPageAsync(int tmdbId, int page, string? language, CancellationToken cancellationToken)
+ {
+ await EnsureClientConfigAsync().ConfigureAwait(false);
+
+ var searchResults = await _tmDbClient
+ .GetTvShowSimilarAsync(tmdbId, language, page, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (searchResults?.Results is null || searchResults.Results.Count == 0)
+ {
+ return ([], 0);
+ }
+
+ return (searchResults.Results, searchResults.TotalPages);
+ }
+
+ /// <summary>
/// Handles bad path checking and builds the absolute url.
/// </summary>
/// <param name="size">The image size to fetch.</param>
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
index 43e6a8bc00..88a2c684ff 100644
--- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
+++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
@@ -111,7 +111,9 @@ public static class DescendantQueryHelper
private static HashSet<Guid> GetMatchingMediaStreamItemIds(JellyfinDbContext context, HasMediaStreamType criteria)
{
var query = context.MediaStreamInfos
- .Where(ms => ms.StreamType == criteria.StreamType && ms.Language == criteria.Language);
+ .Where(ms => ms.StreamType == criteria.StreamType
+ && (criteria.Language.Contains(ms.Language)
+ || (criteria.Language.Contains("und") && string.IsNullOrEmpty(ms.Language)))); // und = undetermined
if (criteria.IsExternal.HasValue)
{
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs
index 83c15aa647..b0c12bf592 100644
--- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs
+++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/JellyfinDbContext.cs
@@ -299,6 +299,11 @@ public class JellyfinDbContext(DbContextOptions<JellyfinDbContext> options, ILog
});
return result;
}
+ catch (DbUpdateConcurrencyException)
+ {
+ // a concurrency exception is supposed to be always handled by the invoker of the method, logging it here is only causing log bloat.
+ throw;
+ }
catch (Exception e)
{
logger.LogError(e, "Error trying to save changes.");
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs
index 68f2ca2786..c1f6ab16a9 100644
--- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs
+++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs
@@ -1,3 +1,6 @@
+#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
+
+using System.Collections.Generic;
using Jellyfin.Database.Implementations.Entities;
namespace Jellyfin.Database.Implementations.MatchCriteria;
@@ -6,9 +9,23 @@ namespace Jellyfin.Database.Implementations.MatchCriteria;
/// Matches folders containing descendants with a specific media stream type and language.
/// </summary>
/// <param name="StreamType">The type of media stream to match (Audio, Subtitle, etc.).</param>
-/// <param name="Language">The language to match.</param>
+/// <param name="Language">List of languages to match.</param>
/// <param name="IsExternal">If not null, filters by internal (false) or external (true) streams. Only applicable to subtitles.</param>
public sealed record HasMediaStreamType(
MediaStreamTypeEntity StreamType,
- string Language,
- bool? IsExternal = null) : FolderMatchCriteria;
+ IReadOnlyCollection<string> Language,
+ bool? IsExternal = null) : FolderMatchCriteria
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HasMediaStreamType"/> class.
+ /// </summary>
+ /// <param name="StreamType">The type of media stream to match (Audio, Subtitle, etc.).</param>
+ /// <param name="Language">The language to match.</param>
+ /// <param name="IsExternal">If not null, filters by internal (false) or external (true) streams. Only applicable to subtitles.</param>
+ public HasMediaStreamType(
+ MediaStreamTypeEntity StreamType,
+ string Language,
+ bool? IsExternal = null) : this(StreamType, [Language], IsExternal)
+ {
+ }
+}
diff --git a/src/Jellyfin.LiveTv/Channels/RefreshChannelsScheduledTask.cs b/src/Jellyfin.LiveTv/Channels/RefreshChannelsScheduledTask.cs
index 71e46764ad..bb4238a2ac 100644
--- a/src/Jellyfin.LiveTv/Channels/RefreshChannelsScheduledTask.cs
+++ b/src/Jellyfin.LiveTv/Channels/RefreshChannelsScheduledTask.cs
@@ -40,10 +40,10 @@ namespace Jellyfin.LiveTv.Channels
}
/// <inheritdoc />
- public string Name => _localization.GetLocalizedString("TasksRefreshChannels");
+ public string Name => _localization.GetLocalizedString("TaskRefreshChannels");
/// <inheritdoc />
- public string Description => _localization.GetLocalizedString("TasksRefreshChannelsDescription");
+ public string Description => _localization.GetLocalizedString("TaskRefreshChannelsDescription");
/// <inheritdoc />
public string Category => _localization.GetLocalizedString("TasksChannelsCategory");
diff --git a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
index 2fb45600b1..b29c64f50d 100644
--- a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using Emby.Naming.Common;
using Emby.Naming.Video;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Model.Entities;
using Xunit;
namespace Jellyfin.Naming.Tests.Video
@@ -10,6 +12,12 @@ namespace Jellyfin.Naming.Tests.Video
public class MultiVersionTests
{
private readonly NamingOptions _namingOptions = new NamingOptions();
+ private readonly VideoListResolver _videoListResolver;
+
+ public MultiVersionTests()
+ {
+ _videoListResolver = new VideoListResolver(_namingOptions);
+ }
[Fact]
public void TestMultiEdition1()
@@ -22,9 +30,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/X-Men Days of Future Past/X-Men Days of Future Past [hsbs].mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result, v => v.ExtraType is null);
Assert.Single(result, v => v.ExtraType is not null);
@@ -41,9 +48,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/X-Men Days of Future Past/X-Men Days of Future Past [banana].mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result, v => v.ExtraType is null);
Assert.Single(result, v => v.ExtraType is not null);
@@ -59,9 +65,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/The Phantom of the Opera (1925)/The Phantom of the Opera (1925) - 1929 version.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Single(result[0].AlternateVersions);
@@ -81,9 +86,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/M/Movie 7.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(7, result.Count);
Assert.Empty(result[0].AlternateVersions);
@@ -104,9 +108,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Movie/Movie-8.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal(7, result[0].AlternateVersions.Count);
@@ -128,9 +131,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Mo/Movie 9.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(9, result.Count);
Assert.Empty(result[0].AlternateVersions);
@@ -148,9 +150,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Movie/Movie 5.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(5, result.Count);
Assert.Empty(result[0].AlternateVersions);
@@ -170,9 +171,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man (2011).mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(5, result.Count);
Assert.Empty(result[0].AlternateVersions);
@@ -192,19 +192,18 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man[test].mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
Assert.Equal(6, result[0].AlternateVersions.Count);
- Assert.Equal("/movies/Iron Man/Iron Man-720p.mkv", result[0].AlternateVersions[0].Path);
- Assert.Equal("/movies/Iron Man/Iron Man-3d.mkv", result[0].AlternateVersions[1].Path);
- Assert.Equal("/movies/Iron Man/Iron Man-3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
- Assert.Equal("/movies/Iron Man/Iron Man-bluray.mkv", result[0].AlternateVersions[3].Path);
- Assert.Equal("/movies/Iron Man/Iron Man-test.mkv", result[0].AlternateVersions[4].Path);
- Assert.Equal("/movies/Iron Man/Iron Man[test].mkv", result[0].AlternateVersions[5].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man-720p.mkv", result[0].AlternateVersions[0].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man-3d.mkv", result[0].AlternateVersions[1].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man-3d-hsbs.mkv", result[0].AlternateVersions[2].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man-bluray.mkv", result[0].AlternateVersions[3].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man-test.mkv", result[0].AlternateVersions[4].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man[test].mkv", result[0].AlternateVersions[5].Files[0].Path);
}
[Fact]
@@ -221,19 +220,18 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man [test].mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
Assert.Equal(6, result[0].AlternateVersions.Count);
- Assert.Equal("/movies/Iron Man/Iron Man - 720p.mkv", result[0].AlternateVersions[0].Path);
- Assert.Equal("/movies/Iron Man/Iron Man - 3d.mkv", result[0].AlternateVersions[1].Path);
- Assert.Equal("/movies/Iron Man/Iron Man - 3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
- Assert.Equal("/movies/Iron Man/Iron Man - bluray.mkv", result[0].AlternateVersions[3].Path);
- Assert.Equal("/movies/Iron Man/Iron Man - test.mkv", result[0].AlternateVersions[4].Path);
- Assert.Equal("/movies/Iron Man/Iron Man [test].mkv", result[0].AlternateVersions[5].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man - 720p.mkv", result[0].AlternateVersions[0].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man - 3d.mkv", result[0].AlternateVersions[1].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man - 3d-hsbs.mkv", result[0].AlternateVersions[2].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man - bluray.mkv", result[0].AlternateVersions[3].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man - test.mkv", result[0].AlternateVersions[4].Files[0].Path);
+ Assert.Equal("/movies/Iron Man/Iron Man [test].mkv", result[0].AlternateVersions[5].Files[0].Path);
}
[Fact]
@@ -245,9 +243,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man - C (2007).mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
}
@@ -266,17 +263,16 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man_3d.hsbs.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal(6, result[0].AlternateVersions.Count);
// Verify 3D recognition is preserved on alternate versions
- var hsbs = result[0].AlternateVersions.First(v => v.Path.Contains("3d-hsbs", StringComparison.Ordinal));
- Assert.True(hsbs.Is3D);
- Assert.Equal("hsbs", hsbs.Format3D);
+ var hsbs = result[0].AlternateVersions.First(v => v.Files[0].Path.Contains("3d-hsbs", StringComparison.Ordinal));
+ Assert.True(hsbs.Files[0].Is3D);
+ Assert.Equal("hsbs", hsbs.Files[0].Format3D);
}
[Fact]
@@ -293,9 +289,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Iron Man/Iron Man (2011).mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(5, result.Count);
Assert.Empty(result[0].AlternateVersions);
@@ -310,9 +305,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Blade Runner (1982)/Blade Runner (1982) [EE by ADM] [480p HEVC AAC,AAC,AAC].mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Single(result[0].AlternateVersions);
@@ -327,9 +321,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) [2160p] Blu-ray.x265.AAC.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Single(result[0].AlternateVersions);
@@ -348,18 +341,17 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv",
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
Assert.Equal(5, result[0].AlternateVersions.Count);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[1].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[2].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[3].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[4].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[1].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[2].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[3].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[4].Files[0].Path);
}
[Fact]
@@ -381,24 +373,23 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv",
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
Assert.Equal(11, result[0].AlternateVersions.Count);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p Remux.mkv", result[0].AlternateVersions[1].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[2].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Directors Cut.mkv", result[0].AlternateVersions[3].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p High Bitrate.mkv", result[0].AlternateVersions[4].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Remux.mkv", result[0].AlternateVersions[5].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Theatrical Release.mkv", result[0].AlternateVersions[6].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[7].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p Directors Cut.mkv", result[0].AlternateVersions[8].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[9].Path);
- Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[10].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p Remux.mkv", result[0].AlternateVersions[1].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[2].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Directors Cut.mkv", result[0].AlternateVersions[3].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p High Bitrate.mkv", result[0].AlternateVersions[4].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Remux.mkv", result[0].AlternateVersions[5].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Theatrical Release.mkv", result[0].AlternateVersions[6].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[7].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p Directors Cut.mkv", result[0].AlternateVersions[8].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[9].Files[0].Path);
+ Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[10].Files[0].Path);
}
[Fact]
@@ -410,9 +401,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 2.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Single(result[0].AlternateVersions);
@@ -427,9 +417,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 2.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
}
@@ -437,7 +426,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
public void TestEmptyList()
{
- var result = VideoListResolver.Resolve(new List<VideoFileInfo>(), _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(new List<VideoFileInfo>()).ToList();
Assert.Empty(result);
}
@@ -451,9 +440,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Movie (2020)/Movie (2020)_1080p.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
Assert.Single(result[0].AlternateVersions);
@@ -468,11 +456,678 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Movie (2020)/Movie (2020).1080p.mkv"
};
- var result = VideoListResolver.Resolve(
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].AlternateVersions);
+ }
+
+ // Episode multi-version tests
+
+ [Fact]
+ public void TestMultiVersionEpisodeInOwnFolder()
+ {
+ // Two versions of S01E01 in their own subfolder should merge
+ var files = new[]
+ {
+ "/TV/Dexter/Dexter - S01E01/Dexter - S01E01 - 1080p.mkv",
+ "/TV/Dexter/Dexter - S01E01/Dexter - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].AlternateVersions);
+ // 1080p should be primary (higher resolution)
+ Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeMixedSeasonFolder()
+ {
+ // Multiple episodes in season folder, some with versions
+ var files = new[]
+ {
+ "/TV/Dexter/Season 1/Dexter - S01E01 - 1080p.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E01 - 720p.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E02.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E03 - 1080p.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E03 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(3, result.Count);
+
+ // S01E01 - should have one alternate version
+ var e01 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E01", StringComparison.Ordinal));
+ Assert.NotNull(e01);
+ Assert.Single(e01!.AlternateVersions);
+ Assert.Contains("1080p", e01.Files[0].Path, StringComparison.Ordinal);
+
+ // S01E02 - standalone, no alternates
+ var e02 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E02", StringComparison.Ordinal));
+ Assert.NotNull(e02);
+ Assert.Empty(e02!.AlternateVersions);
+
+ // S01E03 - should have one alternate version
+ var e03 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E03", StringComparison.Ordinal));
+ Assert.NotNull(e03);
+ Assert.Single(e03!.AlternateVersions);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeDontCollapse()
+ {
+ // Different episodes should NOT collapse into versions
+ var files = new[]
+ {
+ "/TV/Dexter/Season 1/Dexter - S01E01.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E02.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E03.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E04.mkv",
+ "/TV/Dexter/Season 1/Dexter - S01E05.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(5, result.Count);
+ Assert.All(result, r => Assert.Empty(r.AlternateVersions));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithVersionSuffix()
+ {
+ // Episodes with named versions (like Aired/Uncensored)
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Aired.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Uncensored.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - Aired.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - Uncensored.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(2, result.Count);
+ Assert.All(result, r => Assert.Single(r.AlternateVersions));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeFourVersions()
+ {
+ // Four versions of the same episode
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - VersionA.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - VersionB.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - VersionC.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - VersionD.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(3, result[0].AlternateVersions.Count);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithResolutions()
+ {
+ // Resolution sorting should work for episodes too
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 2160p.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].AlternateVersions.Count);
+ // Primary should be 2160p (highest resolution)
+ Assert.Contains("2160p", result[0].Files[0].Path, StringComparison.Ordinal);
+ // Next should be 1080p, then 720p
+ Assert.Contains("1080p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ Assert.Contains("720p", result[0].AlternateVersions[1].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeDifferentSeasons()
+ {
+ // Same episode number but different seasons should NOT group
+ var files = new[]
+ {
+ "/TV/Show/Show - S01E01.mkv",
+ "/TV/Show/Show - S02E01.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(2, result.Count);
+ Assert.All(result, r => Assert.Empty(r.AlternateVersions));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeDisabledByDefault()
+ {
+ // Without collectionType: CollectionType.tvshows, episodes should NOT group
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ // Without the tvshows collection type, these fall through the movie path
+ // (folder-name eligibility fails) and are treated as separate items.
+ Assert.Equal(2, result.Count);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeSameNumberDifferentTitle()
+ {
+ // Two files parse to the same S01E01 but carry distinct episode titles.
+ // Current behavior: they are grouped as alternate versions because
+ // grouping keys only on season + episode number, not on episode title.
+ // This documents the trade-off: users with mis-numbered episodes will
+ // see one of the files collapsed into AlternateVersions of the other.
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Completely Different Title.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].AlternateVersions);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithTitle()
+ {
+ // Episodes with an episode title AND a version suffix should group
+ var files = new[]
+ {
+ "/TV/Show/Show - S01E01/Show - S01E01 - Episode Title - 1080p.mkv",
+ "/TV/Show/Show - S01E01/Show - S01E01 - Episode Title - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithTitleMixedFolder()
+ {
+ // Multiple different episodes with titles and resolution variants in a season folder
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 1080p.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 720p.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - Second Episode - 1080p.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - Second Episode - 720p.mkv",
+ "/TV/Show/Season 1/Show - S01E03 - Third Episode.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(3, result.Count);
+
+ var e01 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E01", StringComparison.Ordinal));
+ Assert.NotNull(e01);
+ Assert.Single(e01!.AlternateVersions);
+
+ var e02 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E02", StringComparison.Ordinal));
+ Assert.NotNull(e02);
+ Assert.Single(e02!.AlternateVersions);
+
+ var e03 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E03", StringComparison.Ordinal));
+ Assert.NotNull(e03);
+ Assert.Empty(e03!.AlternateVersions);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeInSeasonSubfolder()
+ {
+ // Two versions of S01E01 in their own subfolder under a season folder
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01/Show - S01E01 - 1080p.mkv",
+ "/TV/Show/Season 1/Show - S01E01/Show - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithTitleAndVersionSuffix()
+ {
+ // Episodes with episode title AND a named version suffix
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - Aired.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - Uncensored.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - The Getaway - Aired.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - The Getaway - Uncensored.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(2, result.Count);
+ Assert.All(result, r => Assert.Single(r.AlternateVersions));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsCd()
+ {
+ // Stacked episode (cd1/cd2) with higher resolution alongside a single-file lower-res version
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p cd1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p cd2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsDashPart()
+ {
+ // Stacked episode using "- part1" / "- part2" separator
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p - part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p - part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsPt()
+ {
+ // Stacked episode using "pt1" / "pt2" short form
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p.pt1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p.pt2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsAndTitle()
+ {
+ // Stacked episode with episode title in filename
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 1080p part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 1080p part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ // Primary should be the stacked 1080p version with 2 files
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsAndTitleDashSeparator()
+ {
+ // Stacked episode with episode title using "- part1" separator
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 1080p - part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 1080p - part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot - 720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ // Primary should be the stacked 1080p version with 2 files
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeWithAdditionalPartsAndMultipleEpisodes()
+ {
+ // Stacked episode alongside single-file version, plus a different episode
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p cd1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p cd2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv",
+ "/TV/Show/Season 1/Show - S01E02 - Other.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(2, result.Count);
+
+ // S01E01: stacked (cd1+cd2) primary with 720p alternate
+ var e01 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E01", StringComparison.Ordinal));
+ Assert.NotNull(e01);
+ Assert.Equal(2, e01!.Files.Count);
+ Assert.Single(e01.AlternateVersions);
+
+ // S01E02: standalone
+ var e02 = result.FirstOrDefault(r => r.Files[0].Path.Contains("S01E02", StringComparison.Ordinal));
+ Assert.NotNull(e02);
+ Assert.Empty(e02!.AlternateVersions);
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodePartStackAlongsideSingleFileResolutions()
+ {
+ // A part-stacked episode (3 parts, no resolution suffix) alongside single-file 720p and 1080p versions.
+ // The multi-part stack is preferred as primary.
+ var files = new[]
+ {
+ "/TV/Show/Season 1/S01E01 - 720p.mkv",
+ "/TV/Show/Season 1/S01E01 - 1080p.mkv",
+ "/TV/Show/Season 1/S01E01 - Part 1.mkv",
+ "/TV/Show/Season 1/S01E01 - Part 2.mkv",
+ "/TV/Show/Season 1/S01E01 - Part 3.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(3, result[0].Files.Count);
+ Assert.All(result[0].Files, f => Assert.Contains("Part", f.Path, StringComparison.Ordinal));
+ Assert.Equal(2, result[0].AlternateVersions.Count);
+ Assert.Contains(result[0].AlternateVersions, f => f.Files[0].Path.Contains("1080p", StringComparison.Ordinal));
+ Assert.Contains(result[0].AlternateVersions, f => f.Files[0].Path.Contains("720p", StringComparison.Ordinal));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodeTwoPartStacks()
+ {
+ // Two part-suffixed stacks of the same episode at different resolutions.
+ // The 1080p stack is primary, the 720p stack is preserved as a multi-file alternate.
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p - part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p - part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p - part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p - part2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
+
+ Assert.Single(result[0].AlternateVersions);
+ var alt = result[0].AlternateVersions[0];
+ Assert.Equal(2, alt.Files.Count);
+ Assert.All(alt.Files, f => Assert.Contains("720p", f.Path, StringComparison.Ordinal));
+ }
+
+ [Fact]
+ public void TestMultiVersionEpisodePartStackWithTrailer()
+ {
+ // A part-stacked multi-version episode alongside a trailer must not pull the trailer into the version group
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - 1080p part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 1080p part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - 720p.mkv",
+ "/TV/Show/Season 1/Show - S01E01-trailer.mp4"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Equal(2, result.Count);
+
+ var episode = result.FirstOrDefault(r => r.ExtraType is null);
+ Assert.NotNull(episode);
+ Assert.Equal(2, episode!.Files.Count);
+ Assert.Single(episode.AlternateVersions);
+ Assert.Contains("720p", episode.AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
+
+ var trailer = result.FirstOrDefault(r => r.ExtraType is not null);
+ Assert.NotNull(trailer);
+ Assert.Equal(ExtraType.Trailer, trailer!.ExtraType);
+ }
+
+ [Fact]
+ public void TestMovieStackingWithPartNaming()
+ {
+ // Movie stacking with "part1"/"part2" naming
+ var files = new[]
+ {
+ "/movies/Movie/Movie part1.mkv",
+ "/movies/Movie/Movie part2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ }
+
+ [Fact]
+ public void TestMovieStackingWithDashPartNaming()
+ {
+ // Movie stacking with "- part1" / "- part2" dash separator
+ var files = new[]
+ {
+ "/movies/Movie/Movie - part1.mkv",
+ "/movies/Movie/Movie - part2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ }
+
+ [Fact]
+ public void TestMovieStackingWithPtNaming()
+ {
+ // Movie stacking with "pt1"/"pt2" short form
+ var files = new[]
+ {
+ "/movies/Movie/Movie.pt1.mkv",
+ "/movies/Movie/Movie.pt2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ }
+
+ [Fact]
+ public void TestMovieStackingWithHyphenNoSpaces()
+ {
+ // Movie stacking with hyphen directly adjacent to "part" (no spaces)
+ var files = new[]
+ {
+ "/movies/Movie/Movie-part1.mkv",
+ "/movies/Movie/Movie-part2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Equal(2, result[0].Files.Count);
+ }
+
+ [Fact]
+ public void TestMovieStackingWithHyphenNoSpacesAndVersion()
+ {
+ // Movie stacking with hyphen-no-space separators plus a version alternate
+ var files = new[]
+ {
+ "/movies/Movie/Movie-1080p-part1.mkv",
+ "/movies/Movie/Movie-1080p-part2.mkv",
+ "/movies/Movie/Movie-720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ // Stacked 1080p (2 files) should be primary, 720p is alternate
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ }
+
+ [Fact]
+ public void TestMovieMultiVersionWithStackedAlternate()
+ {
+ // Movie folder where the folder-named file is the primary (single file via primaryOverride)
+ // and an alternate version is itself a stack. The stacked alternate must keep all its files.
+ var files = new[]
+ {
+ "/movies/Inception (2010)/Inception (2010).mkv",
+ "/movies/Inception (2010)/Inception (2010) - 4k part1.mkv",
+ "/movies/Inception (2010)/Inception (2010) - 4k part2.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
+
+ Assert.Single(result);
+ Assert.Single(result[0].Files);
+ Assert.Equal("/movies/Inception (2010)/Inception (2010).mkv", result[0].Files[0].Path);
+
+ Assert.Single(result[0].AlternateVersions);
+ var stackedAlternate = result[0].AlternateVersions[0];
+ Assert.Equal(2, stackedAlternate.Files.Count);
+ Assert.All(stackedAlternate.Files, f => Assert.Contains("4k part", f.Path, StringComparison.Ordinal));
+ }
+
+ [Fact]
+ public void TestEpisodeStackingWithHyphenNoSpaces()
+ {
+ // Episode stacking with hyphen-no-space separators plus version alternate
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01-1080p-cd1.mkv",
+ "/TV/Show/Season 1/Show - S01E01-1080p-cd2.mkv",
+ "/TV/Show/Season 1/Show - S01E01-720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ collectionType: CollectionType.tvshows).ToList();
+
+ Assert.Single(result);
+ // Stacked 1080p (2 files) should be primary, 720p is alternate
+ Assert.Equal(2, result[0].Files.Count);
+ Assert.Single(result[0].AlternateVersions);
+ }
+
+ [Fact]
+ public void TestEpisodeStackingWithHyphenNoSpacesAndTitle()
+ {
+ // Episode stacking with title and hyphen-no-space separators
+ var files = new[]
+ {
+ "/TV/Show/Season 1/Show - S01E01 - Pilot-1080p-part1.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot-1080p-part2.mkv",
+ "/TV/Show/Season 1/Show - S01E01 - Pilot-720p.mkv"
+ };
+
+ var result = _videoListResolver.Resolve(
files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ collectionType: CollectionType.tvshows).ToList();
Assert.Single(result);
+ // Stacked 1080p (2 files) should be primary, 720p is alternate
+ Assert.Equal(2, result[0].Files.Count);
Assert.Single(result[0].AlternateVersions);
}
}
diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
index d3164ba9c9..53f16b92d6 100644
--- a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
@@ -10,6 +10,12 @@ namespace Jellyfin.Naming.Tests.Video
public class VideoListResolverTests
{
private readonly NamingOptions _namingOptions = new NamingOptions();
+ private readonly VideoListResolver _videoListResolver;
+
+ public VideoListResolverTests()
+ {
+ _videoListResolver = new VideoListResolver(_namingOptions);
+ }
[Fact]
public void TestStackAndExtras()
@@ -40,9 +46,8 @@ namespace Jellyfin.Naming.Tests.Video
"WillyWonka-trailer.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(11, result.Count);
var batman = result.FirstOrDefault(x => string.Equals(x.Name, "Batman", StringComparison.Ordinal));
@@ -74,9 +79,8 @@ namespace Jellyfin.Naming.Tests.Video
"300.nfo"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
}
@@ -90,9 +94,8 @@ namespace Jellyfin.Naming.Tests.Video
"300 - trailer.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -108,9 +111,8 @@ namespace Jellyfin.Naming.Tests.Video
"X-Men Days of Future Past-trailer.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -127,9 +129,8 @@ namespace Jellyfin.Naming.Tests.Video
"X-Men Days of Future Past-trailer2.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(3, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -147,9 +148,8 @@ namespace Jellyfin.Naming.Tests.Video
"Looper.2012.bluray.720p.x264.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(3, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -166,9 +166,8 @@ namespace Jellyfin.Naming.Tests.Video
"/movies/Looper (2012)/Looper.bluray.720p.x264.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -188,9 +187,8 @@ namespace Jellyfin.Naming.Tests.Video
"My video 5.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(5, result.Count);
}
@@ -204,9 +202,8 @@ namespace Jellyfin.Naming.Tests.Video
"M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 2"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
}
@@ -221,9 +218,8 @@ namespace Jellyfin.Naming.Tests.Video
"My movie #2.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
}
@@ -239,9 +235,8 @@ namespace Jellyfin.Naming.Tests.Video
"No (2012)-trailer.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(3, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -260,9 +255,8 @@ namespace Jellyfin.Naming.Tests.Video
"/Movies/trailer.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(4, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -282,9 +276,8 @@ namespace Jellyfin.Naming.Tests.Video
"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd2.avi"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
}
@@ -297,9 +290,8 @@ namespace Jellyfin.Naming.Tests.Video
"/nas-markrobbo78/Videos/INDEX HTPC/Movies/Watched/3 - ACTION/Argo (2012)/movie.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
}
@@ -312,9 +304,8 @@ namespace Jellyfin.Naming.Tests.Video
"The Colony.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Single(result);
}
@@ -328,9 +319,8 @@ namespace Jellyfin.Naming.Tests.Video
"Four Sisters and a Wedding - B.avi"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
// The result should contain two individual movies
// Version grouping should not work here, because the files are not in a directory with the name 'Four Sisters and a Wedding'
@@ -346,9 +336,8 @@ namespace Jellyfin.Naming.Tests.Video
"Four Rooms - A.mp4"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
}
@@ -362,9 +351,8 @@ namespace Jellyfin.Naming.Tests.Video
"/Server/Despicable Me/trailer.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -380,9 +368,8 @@ namespace Jellyfin.Naming.Tests.Video
"/Server/Despicable Me/trailers/some title.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
@@ -398,9 +385,8 @@ namespace Jellyfin.Naming.Tests.Video
"/Movies/Despicable Me/trailers/trailer.mkv"
};
- var result = VideoListResolver.Resolve(
- files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
- _namingOptions).ToList();
+ var result = _videoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
Assert.Equal(2, result.Count);
Assert.False(result[0].ExtraType.HasValue);
diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs
index 87e7a4b564..5749944fcd 100644
--- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs
+++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs
@@ -576,7 +576,8 @@ namespace Jellyfin.Providers.Tests.Manager
baseItemManager!,
Mock.Of<ILyricManager>(),
Mock.Of<IMemoryCache>(),
- Mock.Of<IMediaSegmentManager>());
+ Mock.Of<IMediaSegmentManager>(),
+ Mock.Of<ISimilarItemsManager>());
return providerManager;
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs
index aed584355c..e1346a8436 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs
@@ -1,7 +1,13 @@
+using System.Collections.Generic;
using Emby.Naming.Common;
+using Emby.Naming.Video;
using Emby.Server.Implementations.Library.Resolvers.Movies;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
@@ -14,11 +20,12 @@ namespace Jellyfin.Server.Implementations.Tests.Library;
public class MovieResolverTests
{
private static readonly NamingOptions _namingOptions = new();
+ private static readonly VideoListResolver _videoListResolver = new(_namingOptions);
[Fact]
public void Resolve_GivenLocalAlternateVersion_ResolvesToVideo()
{
- var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), Mock.Of<ILogger<MovieResolver>>(), _namingOptions, Mock.Of<IDirectoryService>());
+ var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), Mock.Of<ILogger<MovieResolver>>(), _namingOptions, Mock.Of<IDirectoryService>(), _videoListResolver);
var itemResolveArgs = new ItemResolveArgs(
Mock.Of<IServerApplicationPaths>(),
null)
@@ -32,4 +39,54 @@ public class MovieResolverTests
Assert.NotNull(movieResolver.Resolve(itemResolveArgs));
}
+
+ [Fact]
+ public void ResolveMultiple_GivenTvShowsCollection_CreatesEpisodeItems()
+ {
+ // For a tvshows collection, the multi-version grouping must still produce
+ // Episode BaseItems (not generic Video) so downstream metadata fetching
+ // and series-aware logic apply.
+ var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), Mock.Of<ILogger<MovieResolver>>(), _namingOptions, Mock.Of<IDirectoryService>(), _videoListResolver);
+
+ var parent = new Folder { Path = "/TV/Show/Season 1" };
+ var files = new List<FileSystemMetadata>
+ {
+ new() { FullName = "/TV/Show/Season 1/Show - S01E01 - 1080p.mkv", Name = "Show - S01E01 - 1080p.mkv", IsDirectory = false },
+ new() { FullName = "/TV/Show/Season 1/Show - S01E01 - 720p.mkv", Name = "Show - S01E01 - 720p.mkv", IsDirectory = false },
+ new() { FullName = "/TV/Show/Season 1/Show - S01E02.mkv", Name = "Show - S01E02.mkv", IsDirectory = false }
+ };
+
+ var result = movieResolver.ResolveMultiple(parent, files, CollectionType.tvshows, Mock.Of<IDirectoryService>());
+
+ Assert.NotNull(result);
+ Assert.Equal(2, result.Items.Count);
+ Assert.All(result.Items, item => Assert.IsType<Episode>(item));
+
+ // The S01E01 item should have one alternate version
+ var s01e01 = result.Items.Find(i => i.Path.Contains("S01E01", System.StringComparison.Ordinal));
+ Assert.NotNull(s01e01);
+ Assert.Single(((Video)s01e01).LocalAlternateVersions);
+ }
+
+ [Fact]
+ public void ResolveMultiple_GivenMoviesCollection_CreatesMovieItems()
+ {
+ // For a movies collection, the multi-version grouping must produce Movie
+ // BaseItems (not generic Video) so downstream movie-specific logic applies.
+ var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), Mock.Of<ILogger<MovieResolver>>(), _namingOptions, Mock.Of<IDirectoryService>(), _videoListResolver);
+
+ var parent = new Folder { Path = "/movies/Inception (2010)" };
+ var files = new List<FileSystemMetadata>
+ {
+ new() { FullName = "/movies/Inception (2010)/Inception (2010) - 1080p.mkv", Name = "Inception (2010) - 1080p.mkv", IsDirectory = false },
+ new() { FullName = "/movies/Inception (2010)/Inception (2010) - 720p.mkv", Name = "Inception (2010) - 720p.mkv", IsDirectory = false }
+ };
+
+ var result = movieResolver.ResolveMultiple(parent, files, CollectionType.movies, Mock.Of<IDirectoryService>());
+
+ Assert.NotNull(result);
+ Assert.Single(result.Items);
+ Assert.All(result.Items, item => Assert.IsType<Movie>(item));
+ Assert.Single(((Video)result.Items[0]).LocalAlternateVersions);
+ }
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
index acabaf3acb..3b8fe5ca60 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using BitFaster.Caching;
@@ -305,6 +306,98 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
Assert.Equal(key, translated);
}
+ [Fact]
+ public void GetLocalizedString_WithCulture_ReturnsTranslation()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ var translated = localizationManager.GetLocalizedString("Artists", "de");
+ Assert.Equal("Interpreten", translated);
+ }
+
+ [Fact]
+ public void GetLocalizedString_WithCulture_FallsBackToEnUs()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ // A culture with no translation file should fall back to en-US
+ var translated = localizationManager.GetLocalizedString("Artists", "zz");
+ Assert.Equal("Artists", translated);
+ }
+
+ [Fact]
+ public void GetLocalizedString_WithBcp47Normalization_ReturnsTranslation()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ // es-419 is stored as es_419 in Jellyfin
+ var translated = localizationManager.GetLocalizedString("Default", "es-419");
+ Assert.NotEqual("Default", translated);
+ }
+
+ [Fact]
+ public void GetServerLocalizedString_UsesServerCulture()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "de"
+ });
+
+ // Even if CurrentUICulture is fr, GetServerLocalizedString should use the server's "de"
+ var previousCulture = CultureInfo.CurrentUICulture;
+ try
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("fr");
+ var translated = localizationManager.GetServerLocalizedString("Artists");
+ Assert.Equal("Interpreten", translated);
+ }
+ finally
+ {
+ CultureInfo.CurrentUICulture = previousCulture;
+ }
+ }
+
+ [Fact]
+ public void GetLocalizedString_UsesCurrentUICulture()
+ {
+ var localizationManager = Setup(new ServerConfiguration
+ {
+ UICulture = "en-US"
+ });
+
+ var previousCulture = CultureInfo.CurrentUICulture;
+ try
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("de");
+ var translated = localizationManager.GetLocalizedString("Artists");
+ Assert.Equal("Interpreten", translated);
+ }
+ finally
+ {
+ CultureInfo.CurrentUICulture = previousCulture;
+ }
+ }
+
+ [Fact]
+ public void GetSupportedUICultures_IncludesCommonCultures()
+ {
+ var supported = LocalizationManager.GetSupportedUICultures();
+ Assert.Contains(supported, c => c.Name.Equals("de", StringComparison.OrdinalIgnoreCase));
+ Assert.Contains(supported, c => c.Name.Equals("en-US", StringComparison.OrdinalIgnoreCase));
+ Assert.Contains(supported, c => c.Name.Equals("fr", StringComparison.OrdinalIgnoreCase));
+ // Underscore variants get normalized to BCP-47 hyphen form for CultureInfo compatibility.
+ Assert.Contains(supported, c => c.Name.Equals("es-419", StringComparison.OrdinalIgnoreCase));
+ }
+
private LocalizationManager Setup(ServerConfiguration config)
{
var mockConfiguration = new Mock<IServerConfigurationManager>();