mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-17 23:56:44 +00:00
Merge branch 'master' into baseitemkind-fixes
This commit is contained in:
@@ -880,7 +880,7 @@ namespace Emby.Server.Implementations.Channels
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CacheResponse(object result, string path)
|
||||
private async Task CacheResponse(ChannelItemResult result, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -63,13 +61,13 @@ namespace Emby.Server.Implementations.Collections
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
|
||||
public event EventHandler<CollectionCreatedEventArgs>? CollectionCreated;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
|
||||
public event EventHandler<CollectionModifiedEventArgs>? ItemsAddedToCollection;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
|
||||
public event EventHandler<CollectionModifiedEventArgs>? ItemsRemovedFromCollection;
|
||||
|
||||
private IEnumerable<Folder> FindFolders(string path)
|
||||
{
|
||||
@@ -80,7 +78,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
.Where(i => _fileSystem.AreEqual(path, i.Path) || _fileSystem.ContainsSubPath(i.Path, path));
|
||||
}
|
||||
|
||||
internal async Task<Folder> EnsureLibraryFolder(string path, bool createIfNeeded)
|
||||
internal async Task<Folder?> EnsureLibraryFolder(string path, bool createIfNeeded)
|
||||
{
|
||||
var existingFolder = FindFolders(path).FirstOrDefault();
|
||||
if (existingFolder != null)
|
||||
@@ -114,7 +112,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
return Path.Combine(_appPaths.DataPath, "collections");
|
||||
}
|
||||
|
||||
private Task<Folder> GetCollectionsFolder(bool createIfNeeded)
|
||||
private Task<Folder?> GetCollectionsFolder(bool createIfNeeded)
|
||||
{
|
||||
return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded);
|
||||
}
|
||||
@@ -203,8 +201,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
|
||||
private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
if (collection == null)
|
||||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
@@ -256,9 +253,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
/// <inheritdoc />
|
||||
public async Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
|
||||
if (collection == null)
|
||||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
@@ -312,11 +307,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is not ISupportsBoxSetGrouping)
|
||||
{
|
||||
results[item.Id] = item;
|
||||
}
|
||||
else
|
||||
if (item is ISupportsBoxSetGrouping)
|
||||
{
|
||||
var itemId = item.Id;
|
||||
|
||||
@@ -340,6 +331,7 @@ namespace Emby.Server.Implementations.Collections
|
||||
}
|
||||
|
||||
var alreadyInResults = false;
|
||||
|
||||
// this is kind of a performance hack because only Video has alternate versions that should be in a box set?
|
||||
if (item is Video video)
|
||||
{
|
||||
@@ -355,11 +347,13 @@ namespace Emby.Server.Implementations.Collections
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyInResults)
|
||||
if (alreadyInResults)
|
||||
{
|
||||
results[itemId] = item;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
results[item.Id] = item;
|
||||
}
|
||||
|
||||
return results.Values;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.9" />
|
||||
<PackageReference Include="Mono.Nat" Version="3.0.1" />
|
||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.1.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.28.3" />
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
||||
}
|
||||
|
||||
// Temporary. TODO - allow clients to specify that the token has been shared with a casting device
|
||||
var allowTokenInfoUpdate = authInfo.Client == null || authInfo.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1;
|
||||
var allowTokenInfoUpdate = authInfo.Client == null || !authInfo.Client.Contains("chromecast", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(authInfo.Device))
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@ using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -44,22 +43,29 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
|
||||
public async Task<Stream> GetListingsStream(TunerHostInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
if (info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
if (info == null)
|
||||
{
|
||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, info.Url);
|
||||
if (!string.IsNullOrEmpty(info.UserAgent))
|
||||
{
|
||||
requestMessage.Headers.UserAgent.TryParseAdd(info.UserAgent);
|
||||
}
|
||||
|
||||
var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
||||
.SendAsync(requestMessage, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
return File.OpenRead(info.Url);
|
||||
if (!info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return File.OpenRead(info.Url);
|
||||
}
|
||||
|
||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, info.Url);
|
||||
if (!string.IsNullOrEmpty(info.UserAgent))
|
||||
{
|
||||
requestMessage.Headers.UserAgent.TryParseAdd(info.UserAgent);
|
||||
}
|
||||
|
||||
// Set HttpCompletionOption.ResponseHeadersRead to prevent timeouts on larger files
|
||||
var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
||||
.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<List<ChannelInfo>> GetChannelsAsync(TextReader reader, string channelIdPrefix, string tunerHostId)
|
||||
@@ -83,7 +89,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
if (trimmedLine.StartsWith(ExtInfPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
extInf = trimmedLine.Substring(ExtInfPrefix.Length).Trim();
|
||||
_logger.LogInformation("Found m3u channel: {0}", extInf);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(extInf) && !trimmedLine.StartsWith('#'))
|
||||
{
|
||||
@@ -99,6 +104,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
|
||||
channel.Path = trimmedLine;
|
||||
channels.Add(channel);
|
||||
_logger.LogInformation("Parsed channel: {ChannelName}", channel.Name);
|
||||
extInf = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
"Artists": "Kunstenare",
|
||||
"Channels": "Kanale",
|
||||
"Folders": "Lêergidse",
|
||||
"Favorites": "Gunstellinge",
|
||||
"Favorites": "Gunstelinge",
|
||||
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
||||
"ValueSpecialEpisodeName": "Spesiale - {0}",
|
||||
"HeaderAlbumArtists": "Album Kunstenaars",
|
||||
"HeaderAlbumArtists": "Kunstenaars se Album",
|
||||
"Books": "Boeke",
|
||||
"HeaderNextUp": "Volgende",
|
||||
"Movies": "Flieks",
|
||||
"Shows": "Televisie Reekse",
|
||||
"HeaderContinueWatching": "Kyk Verder",
|
||||
"HeaderFavoriteEpisodes": "Gunsteling Episodes",
|
||||
"Photos": "Fotos",
|
||||
"Photos": "Foto's",
|
||||
"Playlists": "Snitlyste",
|
||||
"HeaderFavoriteArtists": "Gunsteling Kunstenaars",
|
||||
"HeaderFavoriteAlbums": "Gunsteling Albums",
|
||||
"Sync": "Sinkroniseer",
|
||||
"HeaderFavoriteSongs": "Gunsteling Liedjies",
|
||||
"Songs": "Liedjies",
|
||||
"DeviceOnlineWithName": "{0} gekoppel is",
|
||||
"DeviceOnlineWithName": "{0} is gekoppel",
|
||||
"DeviceOfflineWithName": "{0} is ontkoppel",
|
||||
"Collections": "Versamelings",
|
||||
"Inherit": "Ontvang",
|
||||
@@ -71,7 +71,7 @@
|
||||
"NameSeasonUnknown": "Seisoen Onbekend",
|
||||
"NameSeasonNumber": "Seisoen {0}",
|
||||
"NameInstallFailed": "{0} installering het misluk",
|
||||
"MusicVideos": "Musiek videos",
|
||||
"MusicVideos": "Musiek Videos",
|
||||
"Music": "Musiek",
|
||||
"MixedContent": "Gemengde inhoud",
|
||||
"MessageServerConfigurationUpdated": "Bediener konfigurasie is opgedateer",
|
||||
@@ -79,15 +79,15 @@
|
||||
"MessageApplicationUpdatedTo": "Jellyfin Bediener is opgedateer na {0}",
|
||||
"MessageApplicationUpdated": "Jellyfin Bediener is opgedateer",
|
||||
"Latest": "Nuutste",
|
||||
"LabelRunningTimeValue": "Lopende tyd: {0}",
|
||||
"LabelRunningTimeValue": "Werktyd: {0}",
|
||||
"LabelIpAddressValue": "IP adres: {0}",
|
||||
"ItemRemovedWithName": "{0} is uit versameling verwyder",
|
||||
"ItemAddedWithName": "{0} is in die versameling",
|
||||
"HomeVideos": "Tuis opnames",
|
||||
"ItemAddedWithName": "{0} is by die versameling gevoeg",
|
||||
"HomeVideos": "Tuis Videos",
|
||||
"HeaderRecordingGroups": "Groep Opnames",
|
||||
"Genres": "Genres",
|
||||
"FailedLoginAttemptWithUserName": "Mislukte aansluiting van {0}",
|
||||
"ChapterNameValue": "Hoofstuk",
|
||||
"ChapterNameValue": "Hoofstuk {0}",
|
||||
"CameraImageUploadedFrom": "'n Nuwe kamera photo opgelaai van {0}",
|
||||
"AuthenticationSucceededWithUserName": "{0} suksesvol geverifieer",
|
||||
"Albums": "Albums",
|
||||
@@ -117,5 +117,7 @@
|
||||
"Forced": "Geforseer",
|
||||
"Default": "Oorspronklik",
|
||||
"TaskCleanActivityLogDescription": "Verwyder aktiwiteitsaantekeninge ouer as die opgestelde ouderdom.",
|
||||
"TaskCleanActivityLog": "Maak Aktiwiteitsaantekeninge Skoon"
|
||||
"TaskCleanActivityLog": "Maak Aktiwiteitsaantekeninge Skoon",
|
||||
"TaskOptimizeDatabaseDescription": "Komprimeer databasis en verkort vrye ruimte. As hierdie taak uitgevoer word nadat die media versameling geskandeer is of ander veranderings aangebring is wat databasisaanpassings impliseer, kan dit die prestasie verbeter.",
|
||||
"TaskOptimizeDatabase": "Optimaliseer databasis"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"Artists": "Artistes",
|
||||
"AuthenticationSucceededWithUserName": "{0} s'ha autenticat correctament",
|
||||
"Books": "Llibres",
|
||||
"CameraImageUploadedFrom": "Una nova imatge de la càmera ha estat pujada des de {0}",
|
||||
"CameraImageUploadedFrom": "S'ha pujat una nova imatge des de la camera desde {0}",
|
||||
"Channels": "Canals",
|
||||
"ChapterNameValue": "Capítol {0}",
|
||||
"Collections": "Col·leccions",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Albums": "Άλμπουμς",
|
||||
"Albums": "Άλμπουμ",
|
||||
"AppDeviceValues": "Εφαρμογή: {0}, Συσκευή: {1}",
|
||||
"Application": "Εφαρμογή",
|
||||
"Artists": "Καλλιτέχνες",
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Αγαπημένα",
|
||||
"Folders": "Φάκελοι",
|
||||
"Genres": "Είδη",
|
||||
"HeaderAlbumArtists": "Καλλιτέχνες του Άλμπουμ",
|
||||
"HeaderAlbumArtists": "Άλμπουμ Καλλιτέχνη",
|
||||
"HeaderContinueWatching": "Συνεχίστε την παρακολούθηση",
|
||||
"HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ",
|
||||
"HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες",
|
||||
@@ -39,7 +39,7 @@
|
||||
"MixedContent": "Ανάμεικτο Περιεχόμενο",
|
||||
"Movies": "Ταινίες",
|
||||
"Music": "Μουσική",
|
||||
"MusicVideos": "Μουσικά βίντεο",
|
||||
"MusicVideos": "Μουσικά Βίντεο",
|
||||
"NameInstallFailed": "{0} η εγκατάσταση απέτυχε",
|
||||
"NameSeasonNumber": "Κύκλος {0}",
|
||||
"NameSeasonUnknown": "Άγνωστος Κύκλος",
|
||||
@@ -62,7 +62,7 @@
|
||||
"NotificationOptionVideoPlaybackStopped": "Η αναπαραγωγή βίντεο σταμάτησε",
|
||||
"Photos": "Φωτογραφίες",
|
||||
"Playlists": "Λίστες αναπαραγωγής",
|
||||
"Plugin": "Plugin",
|
||||
"Plugin": "Πρόσθετο",
|
||||
"PluginInstalledWithName": "{0} εγκαταστήθηκε",
|
||||
"PluginUninstalledWithName": "{0} έχει απεγκατασταθεί",
|
||||
"PluginUpdatedWithName": "{0} έχει αναβαθμιστεί",
|
||||
@@ -118,5 +118,7 @@
|
||||
"TaskCleanActivityLog": "Καθαρό Αρχείο Καταγραφής Δραστηριοτήτων",
|
||||
"Undefined": "Απροσδιόριστο",
|
||||
"Forced": "Εξαναγκασμένο",
|
||||
"Default": "Προεπιλογή"
|
||||
"Default": "Προεπιλογή",
|
||||
"TaskOptimizeDatabaseDescription": "Συμπιέζει τη βάση δεδομένων και δημιουργεί ελεύθερο χώρο. Η εκτέλεση αυτής της εργασίας μετά τη σάρωση της βιβλιοθήκης ή την πραγματοποίηση άλλων αλλαγών που συνεπάγονται τροποποιήσεις της βάσης δεδομένων μπορεί να βελτιώσει την απόδοση.",
|
||||
"TaskOptimizeDatabase": "Βελτιστοποίηση βάσης δεδομένων"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"Folders": "Folders",
|
||||
"Forced": "Forced",
|
||||
"Genres": "Genres",
|
||||
"HeaderAlbumArtists": "Album Artists",
|
||||
"HeaderAlbumArtists": "Artist's Album",
|
||||
"HeaderContinueWatching": "Continue Watching",
|
||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||
"HeaderFavoriteArtists": "Favorite Artists",
|
||||
@@ -27,7 +27,7 @@
|
||||
"HeaderLiveTV": "Live TV",
|
||||
"HeaderNextUp": "Next Up",
|
||||
"HeaderRecordingGroups": "Recording Groups",
|
||||
"HomeVideos": "Home videos",
|
||||
"HomeVideos": "Home Videos",
|
||||
"Inherit": "Inherit",
|
||||
"ItemAddedWithName": "{0} was added to the library",
|
||||
"ItemRemovedWithName": "{0} was removed from the library",
|
||||
@@ -41,7 +41,7 @@
|
||||
"MixedContent": "Mixed content",
|
||||
"Movies": "Movies",
|
||||
"Music": "Music",
|
||||
"MusicVideos": "Music videos",
|
||||
"MusicVideos": "Music Videos",
|
||||
"NameInstallFailed": "{0} installation failed",
|
||||
"NameSeasonNumber": "Season {0}",
|
||||
"NameSeasonUnknown": "Season Unknown",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Favoritos",
|
||||
"Folders": "Carpetas",
|
||||
"Genres": "Géneros",
|
||||
"HeaderAlbumArtists": "Artistas del álbum",
|
||||
"HeaderAlbumArtists": "Artistas del Álbum",
|
||||
"HeaderContinueWatching": "Continuar viendo",
|
||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||
@@ -25,7 +25,7 @@
|
||||
"HeaderLiveTV": "TV en vivo",
|
||||
"HeaderNextUp": "A continuación",
|
||||
"HeaderRecordingGroups": "Grupos de grabación",
|
||||
"HomeVideos": "Videos caseros",
|
||||
"HomeVideos": "Videos Caseros",
|
||||
"Inherit": "Heredar",
|
||||
"ItemAddedWithName": "{0} fue agregado a la biblioteca",
|
||||
"ItemRemovedWithName": "{0} fue removido de la biblioteca",
|
||||
@@ -39,7 +39,7 @@
|
||||
"MixedContent": "Contenido mezclado",
|
||||
"Movies": "Películas",
|
||||
"Music": "Música",
|
||||
"MusicVideos": "Videos musicales",
|
||||
"MusicVideos": "Videos Musicales",
|
||||
"NameInstallFailed": "Falló la instalación de {0}",
|
||||
"NameSeasonNumber": "Temporada {0}",
|
||||
"NameSeasonUnknown": "Temporada desconocida",
|
||||
@@ -49,7 +49,7 @@
|
||||
"NotificationOptionAudioPlayback": "Reproducción de audio iniciada",
|
||||
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida",
|
||||
"NotificationOptionCameraImageUploaded": "Imagen de la cámara subida",
|
||||
"NotificationOptionInstallationFailed": "Falla de instalación",
|
||||
"NotificationOptionInstallationFailed": "Fallo en la instalación",
|
||||
"NotificationOptionNewLibraryContent": "Nuevo contenido agregado",
|
||||
"NotificationOptionPluginError": "Falla de complemento",
|
||||
"NotificationOptionPluginInstalled": "Complemento instalado",
|
||||
@@ -69,7 +69,7 @@
|
||||
"ProviderValue": "Proveedor: {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} falló",
|
||||
"ScheduledTaskStartedWithName": "{0} iniciado",
|
||||
"ServerNameNeedsToBeRestarted": "{0} debe ser reiniciado",
|
||||
"ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
|
||||
"Shows": "Programas",
|
||||
"Songs": "Canciones",
|
||||
"StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo pronto.",
|
||||
@@ -94,9 +94,9 @@
|
||||
"VersionNumber": "Versión {0}",
|
||||
"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.",
|
||||
"TaskRefreshChannelsDescription": "Actualiza la información de los canales de Internet.",
|
||||
"TaskRefreshChannels": "Actualizar canales",
|
||||
"TaskCleanTranscodeDescription": "Elimina archivos transcodificados que tengan más de un día.",
|
||||
"TaskCleanTranscodeDescription": "Elimina archivos transcodificados que tengan más de un día de antigüedad.",
|
||||
"TaskCleanTranscode": "Limpiar directorio de transcodificado",
|
||||
"TaskUpdatePluginsDescription": "Descarga e instala actualizaciones para complementos que están configurados para actualizarse automáticamente.",
|
||||
"TaskUpdatePlugins": "Actualizar complementos",
|
||||
@@ -118,5 +118,7 @@
|
||||
"TaskCleanActivityLog": "Limpiar registro de actividades",
|
||||
"Undefined": "Sin definir",
|
||||
"Forced": "Forzado",
|
||||
"Default": "Predeterminado"
|
||||
"Default": "Predeterminado",
|
||||
"TaskOptimizeDatabase": "Optimizar base de datos",
|
||||
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y trunca el espacio libre. Puede mejorar el rendimiento si se realiza esta tarea después de escanear la biblioteca o después de realizar otros cambios que impliquen modificar la base de datos."
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Favoritos",
|
||||
"Folders": "Carpetas",
|
||||
"Genres": "Géneros",
|
||||
"HeaderAlbumArtists": "Artistas del álbum",
|
||||
"HeaderAlbumArtists": "Artista del álbum",
|
||||
"HeaderContinueWatching": "Continuar viendo",
|
||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Kedvencek",
|
||||
"Folders": "Könyvtárak",
|
||||
"Genres": "Műfajok",
|
||||
"HeaderAlbumArtists": "Album előadók",
|
||||
"HeaderAlbumArtists": "Előadó albumai",
|
||||
"HeaderContinueWatching": "Megtekintés folytatása",
|
||||
"HeaderFavoriteAlbums": "Kedvenc albumok",
|
||||
"HeaderFavoriteArtists": "Kedvenc előadók",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Preferiti",
|
||||
"Folders": "Cartelle",
|
||||
"Genres": "Generi",
|
||||
"HeaderAlbumArtists": "Artisti degli Album",
|
||||
"HeaderAlbumArtists": "Artisti dell'Album",
|
||||
"HeaderContinueWatching": "Continua a guardare",
|
||||
"HeaderFavoriteAlbums": "Album Preferiti",
|
||||
"HeaderFavoriteArtists": "Artisti Preferiti",
|
||||
@@ -25,7 +25,7 @@
|
||||
"HeaderLiveTV": "Diretta TV",
|
||||
"HeaderNextUp": "Prossimo",
|
||||
"HeaderRecordingGroups": "Gruppi di Registrazione",
|
||||
"HomeVideos": "Video personali",
|
||||
"HomeVideos": "Video Personali",
|
||||
"Inherit": "Eredita",
|
||||
"ItemAddedWithName": "{0} è stato aggiunto alla libreria",
|
||||
"ItemRemovedWithName": "{0} è stato rimosso dalla libreria",
|
||||
@@ -39,7 +39,7 @@
|
||||
"MixedContent": "Contenuto misto",
|
||||
"Movies": "Film",
|
||||
"Music": "Musica",
|
||||
"MusicVideos": "Video musicali",
|
||||
"MusicVideos": "Video Musicali",
|
||||
"NameInstallFailed": "{0} installazione fallita",
|
||||
"NameSeasonNumber": "Stagione {0}",
|
||||
"NameSeasonUnknown": "Stagione sconosciuta",
|
||||
@@ -70,7 +70,7 @@
|
||||
"ScheduledTaskFailedWithName": "{0} fallito",
|
||||
"ScheduledTaskStartedWithName": "{0} avviati",
|
||||
"ServerNameNeedsToBeRestarted": "{0} deve essere riavviato",
|
||||
"Shows": "Programmi",
|
||||
"Shows": "Serie TV",
|
||||
"Songs": "Canzoni",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.",
|
||||
"SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Favorites": "Tañdaulylar",
|
||||
"Folders": "Qaltalar",
|
||||
"Genres": "Janrlar",
|
||||
"HeaderAlbumArtists": "Älbom oryndauşylary",
|
||||
"HeaderAlbumArtists": "Oryndauşynyñ älbomy",
|
||||
"HeaderContinueWatching": "Qaraudy jalğastyru",
|
||||
"HeaderFavoriteAlbums": "Tañdauly älbomdar",
|
||||
"HeaderFavoriteArtists": "Tañdauly oryndauşylar",
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
"ValueSpecialEpisodeName": "പ്രത്യേക - {0}",
|
||||
"Collections": "ശേഖരങ്ങൾ",
|
||||
"Folders": "ഫോൾഡറുകൾ",
|
||||
"HeaderAlbumArtists": "ആൽബം ആർട്ടിസ്റ്റുകൾ",
|
||||
"HeaderAlbumArtists": "കലാകാരന്റെ ആൽബം",
|
||||
"Sync": "സമന്വയിപ്പിക്കുക",
|
||||
"Movies": "സിനിമകൾ",
|
||||
"Photos": "ഫോട്ടോകൾ",
|
||||
|
||||
1
Emby.Server.Implementations/Localization/Core/pr.json
Normal file
1
Emby.Server.Implementations/Localization/Core/pr.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -25,7 +25,7 @@
|
||||
"HeaderLiveTV": "Эфир",
|
||||
"HeaderNextUp": "Очередное",
|
||||
"HeaderRecordingGroups": "Группы записей",
|
||||
"HomeVideos": "Домашнее видео",
|
||||
"HomeVideos": "Домашние видео",
|
||||
"Inherit": "Наследуемое",
|
||||
"ItemAddedWithName": "{0} - добавлено в медиатеку",
|
||||
"ItemRemovedWithName": "{0} - изъято из медиатеки",
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"MixedContent": "Zmiešaný obsah",
|
||||
"Movies": "Filmy",
|
||||
"Music": "Hudba",
|
||||
"MusicVideos": "Hudobné videoklipy",
|
||||
"MusicVideos": "Hudobné videá",
|
||||
"NameInstallFailed": "Inštalácia {0} zlyhala",
|
||||
"NameSeasonNumber": "Séria {0}",
|
||||
"NameSeasonUnknown": "Neznáma séria",
|
||||
|
||||
@@ -118,5 +118,6 @@
|
||||
"TaskCleanActivityLog": "Rensa Aktivitets Logg",
|
||||
"Undefined": "odefinierad",
|
||||
"Forced": "Tvingad",
|
||||
"Default": "Standard"
|
||||
"Default": "Standard",
|
||||
"TaskOptimizeDatabase": "Optimera databasen"
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"NameInstallFailed": "{0} kurulumu başarısız",
|
||||
"NameSeasonNumber": "Sezon {0}",
|
||||
"NameSeasonUnknown": "Bilinmeyen Sezon",
|
||||
"NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir versiyonu indirmek için hazır.",
|
||||
"NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir sürümü indirmek için hazır.",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Uygulama güncellemesi mevcut",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Uygulama güncellemesi yüklendi",
|
||||
"NotificationOptionAudioPlayback": "Ses çalma başladı",
|
||||
@@ -75,7 +75,7 @@
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Sunucusu yükleniyor. Lütfen kısa süre sonra tekrar deneyin.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "{1} için alt yazılar {0} 'dan indirilemedi",
|
||||
"Sync": "Eşitle",
|
||||
"Sync": "Eşzamanlama",
|
||||
"System": "Sistem",
|
||||
"TvShows": "Diziler",
|
||||
"User": "Kullanıcı",
|
||||
@@ -89,34 +89,36 @@
|
||||
"UserPolicyUpdatedWithName": "Kullanıcı politikası {0} için güncellendi",
|
||||
"UserStartedPlayingItemWithValues": "{0}, {2} cihazında {1} izliyor",
|
||||
"UserStoppedPlayingItemWithValues": "{0}, {2} cihazında {1} izlemeyi bitirdi",
|
||||
"ValueHasBeenAddedToLibrary": "Medya kitaplığınıza {0} eklendi",
|
||||
"ValueHasBeenAddedToLibrary": "Medya kütüphanenize {0} eklendi",
|
||||
"ValueSpecialEpisodeName": "Özel - {0}",
|
||||
"VersionNumber": "Versiyon {0}",
|
||||
"VersionNumber": "Sürüm {0}",
|
||||
"TaskCleanCache": "Geçici dosya klasörünü temizle",
|
||||
"TasksChannelsCategory": "İnternet kanalları",
|
||||
"TasksApplicationCategory": "Uygulama",
|
||||
"TasksLibraryCategory": "Kütüphane",
|
||||
"TasksMaintenanceCategory": "Onarım",
|
||||
"TasksMaintenanceCategory": "Bakım",
|
||||
"TaskRefreshPeopleDescription": "Medya kütüphanenizdeki videoların oyuncu ve yönetmen bilgilerini günceller.",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Metadata ayarlarını baz alarak eksik altyazıları internette arar.",
|
||||
"TaskDownloadMissingSubtitles": "Eksik altyazıları indir",
|
||||
"TaskRefreshChannelsDescription": "Internet kanal bilgilerini yenile.",
|
||||
"TaskRefreshChannels": "Kanalları Yenile",
|
||||
"TaskCleanTranscodeDescription": "Bir günü dolmuş dönüştürme bilgisi içeren dosyaları siler.",
|
||||
"TaskCleanTranscodeDescription": "Bir günden daha eski dönüştürme dosyalarını siler.",
|
||||
"TaskCleanTranscode": "Dönüşüm Dizinini Temizle",
|
||||
"TaskUpdatePluginsDescription": "Otomatik güncellenmeye ayarlanmış eklentilerin güncellemelerini indirir ve kurar.",
|
||||
"TaskUpdatePlugins": "Eklentileri Güncelle",
|
||||
"TaskRefreshPeople": "Kullanıcıları Yenile",
|
||||
"TaskCleanLogsDescription": "{0} günden eski log dosyalarını siler.",
|
||||
"TaskCleanLogs": "Log Dizinini Temizle",
|
||||
"TaskRefreshLibraryDescription": "Medya kütüphanenize eklenen yeni dosyaları arar ve bilgileri yeniler.",
|
||||
"TaskCleanLogsDescription": "{0} günden eski günlük dosyalarını siler.",
|
||||
"TaskCleanLogs": "Günlük Dizinini Temizle",
|
||||
"TaskRefreshLibraryDescription": "Medya kütüphanenize eklenen yeni dosyaları arar ve ortam bilgilerini yeniler.",
|
||||
"TaskRefreshLibrary": "Medya Kütüphanesini Tara",
|
||||
"TaskRefreshChapterImagesDescription": "Sahnelere ayrılmış videolar için küçük resimler oluştur.",
|
||||
"TaskRefreshChapterImages": "Bölüm Resimlerini Çıkar",
|
||||
"TaskCleanCacheDescription": "Sistem tarafından artık ihtiyaç duyulmayan önbellek dosyalarını siler.",
|
||||
"TaskCleanActivityLog": "İşlem Günlüğünü Temizle",
|
||||
"TaskCleanActivityLogDescription": "Belirtilen sureden daha eski etkinlik log kayıtları silindi.",
|
||||
"TaskCleanActivityLog": "Etkinlik Günlüğünü Temizle",
|
||||
"TaskCleanActivityLogDescription": "Yapılandırılan tarihten daha eski olan etkinlik günlüğü girişlerini siler.",
|
||||
"Undefined": "Bilinmeyen",
|
||||
"Default": "Varsayılan",
|
||||
"Forced": "Zorla"
|
||||
"Forced": "Zorla",
|
||||
"TaskOptimizeDatabaseDescription": "Veritabanını sıkıştırır ve boş alanı keser. Kitaplığı taradıktan sonra veya veritabanında değişiklik anlamına gelen diğer işlemleri yaptıktan sonra bu görevi çalıştırmak performansı artırabilir.",
|
||||
"TaskOptimizeDatabase": "Veritabanını optimize et"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Favorites": "Yêu Thích",
|
||||
"Folders": "Thư Mục",
|
||||
"Genres": "Thể Loại",
|
||||
"HeaderAlbumArtists": "Tuyển Tập Nghệ sĩ",
|
||||
"HeaderAlbumArtists": "Album Nghệ sĩ",
|
||||
"HeaderContinueWatching": "Xem Tiếp",
|
||||
"HeaderLiveTV": "TV Trực Tiếp",
|
||||
"Movies": "Phim",
|
||||
@@ -82,7 +82,7 @@
|
||||
"NameSeasonUnknown": "Không Rõ Mùa",
|
||||
"NameSeasonNumber": "Phần {0}",
|
||||
"NameInstallFailed": "{0} cài đặt thất bại",
|
||||
"MusicVideos": "Video Nhạc",
|
||||
"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",
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -23,6 +21,9 @@ namespace Emby.Server.Implementations.Localization
|
||||
public class LocalizationManager : ILocalizationManager
|
||||
{
|
||||
private const string DefaultCulture = "en-US";
|
||||
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 static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
|
||||
private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
|
||||
|
||||
@@ -35,10 +36,10 @@ namespace Emby.Server.Implementations.Localization
|
||||
private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries =
|
||||
new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private List<CultureDto> _cultures;
|
||||
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
|
||||
private List<CultureDto> _cultures = new List<CultureDto>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
|
||||
/// </summary>
|
||||
@@ -58,43 +59,39 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// <returns><see cref="Task" />.</returns>
|
||||
public async Task LoadAll()
|
||||
{
|
||||
const string RatingsResource = "Emby.Server.Implementations.Localization.Ratings.";
|
||||
|
||||
// Extract from the assembly
|
||||
foreach (var resource in _assembly.GetManifestResourceNames())
|
||||
{
|
||||
if (!resource.StartsWith(RatingsResource, StringComparison.Ordinal))
|
||||
if (!resource.StartsWith(RatingsPath, StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string countryCode = resource.Substring(RatingsResource.Length, 2);
|
||||
string countryCode = resource.Substring(RatingsPath.Length, 2);
|
||||
var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
using (var str = _assembly.GetManifestResourceStream(resource))
|
||||
using (var reader = new StreamReader(str))
|
||||
await using var stream = _assembly.GetManifestResourceStream(resource);
|
||||
using var reader = new StreamReader(stream!); // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] parts = line.Split(',');
|
||||
if (parts.Length == 2
|
||||
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||
{
|
||||
var name = parts[0];
|
||||
dict.Add(name, new ParentalRating(name, value));
|
||||
}
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] parts = line.Split(',');
|
||||
if (parts.Length == 2
|
||||
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||
{
|
||||
var name = parts[0];
|
||||
dict.Add(name, new ParentalRating(name, value));
|
||||
}
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_allParentalRatings[countryCode] = dict;
|
||||
@@ -114,52 +111,49 @@ namespace Emby.Server.Implementations.Localization
|
||||
{
|
||||
List<CultureDto> list = new List<CultureDto>();
|
||||
|
||||
const string ResourcePath = "Emby.Server.Implementations.Localization.iso6392.txt";
|
||||
|
||||
using (var stream = _assembly.GetManifestResourceStream(ResourcePath))
|
||||
using (var reader = new StreamReader(stream))
|
||||
await using var stream = _assembly.GetManifestResourceStream(CulturesPath)
|
||||
?? throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'");
|
||||
using var reader = new StreamReader(stream);
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
}
|
||||
|
||||
var parts = line.Split('|');
|
||||
|
||||
if (parts.Length == 5)
|
||||
{
|
||||
string name = parts[3];
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var parts = line.Split('|');
|
||||
|
||||
if (parts.Length == 5)
|
||||
string twoCharName = parts[2];
|
||||
if (string.IsNullOrWhiteSpace(twoCharName))
|
||||
{
|
||||
string name = parts[3];
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string twoCharName = parts[2];
|
||||
if (string.IsNullOrWhiteSpace(twoCharName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] threeletterNames;
|
||||
if (string.IsNullOrWhiteSpace(parts[1]))
|
||||
{
|
||||
threeletterNames = new[] { parts[0] };
|
||||
}
|
||||
else
|
||||
{
|
||||
threeletterNames = new[] { parts[0], parts[1] };
|
||||
}
|
||||
|
||||
list.Add(new CultureDto
|
||||
{
|
||||
DisplayName = name,
|
||||
Name = name,
|
||||
ThreeLetterISOLanguageNames = threeletterNames,
|
||||
TwoLetterISOLanguageName = twoCharName
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] threeletterNames;
|
||||
if (string.IsNullOrWhiteSpace(parts[1]))
|
||||
{
|
||||
threeletterNames = new[] { parts[0] };
|
||||
}
|
||||
else
|
||||
{
|
||||
threeletterNames = new[] { parts[0], parts[1] };
|
||||
}
|
||||
|
||||
list.Add(new CultureDto
|
||||
{
|
||||
DisplayName = name,
|
||||
Name = name,
|
||||
ThreeLetterISOLanguageNames = threeletterNames,
|
||||
TwoLetterISOLanguageName = twoCharName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +161,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CultureDto FindLanguageInfo(string language)
|
||||
public CultureDto? FindLanguageInfo(string language)
|
||||
{
|
||||
// TODO language should ideally be a ReadOnlySpan but moq cannot mock ref structs
|
||||
for (var i = 0; i < _cultures.Count; i++)
|
||||
@@ -188,9 +182,10 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<CountryInfo> GetCountries()
|
||||
{
|
||||
using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json"));
|
||||
|
||||
return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions);
|
||||
using StreamReader reader = new StreamReader(
|
||||
_assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"));
|
||||
return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions)
|
||||
?? throw new InvalidOperationException($"Resource contains invalid data: '{CountriesPath}'");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -210,7 +205,9 @@ namespace Emby.Server.Implementations.Localization
|
||||
countryCode = "us";
|
||||
}
|
||||
|
||||
return GetRatings(countryCode) ?? GetRatings("us");
|
||||
return GetRatings(countryCode)
|
||||
?? GetRatings("us")
|
||||
?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -218,7 +215,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// </summary>
|
||||
/// <param name="countryCode">The country code.</param>
|
||||
/// <returns>The ratings.</returns>
|
||||
private Dictionary<string, ParentalRating> GetRatings(string countryCode)
|
||||
private Dictionary<string, ParentalRating>? GetRatings(string countryCode)
|
||||
{
|
||||
_allParentalRatings.TryGetValue(countryCode, out var value);
|
||||
|
||||
@@ -243,7 +240,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
|
||||
var ratingsDictionary = GetParentalRatingsDictionary();
|
||||
|
||||
if (ratingsDictionary.TryGetValue(rating, out ParentalRating value))
|
||||
if (ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
@@ -273,20 +270,6 @@ namespace Emby.Server.Implementations.Localization
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasUnicodeCategory(string value, UnicodeCategory category)
|
||||
{
|
||||
foreach (var chr in value)
|
||||
{
|
||||
if (char.GetUnicodeCategory(chr) == category)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetLocalizedString(string phrase)
|
||||
{
|
||||
@@ -350,22 +333,23 @@ namespace Emby.Server.Implementations.Localization
|
||||
|
||||
private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath)
|
||||
{
|
||||
using (var stream = _assembly.GetManifestResourceStream(resourcePath))
|
||||
await using var stream = _assembly.GetManifestResourceStream(resourcePath);
|
||||
// If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain
|
||||
if (stream == null)
|
||||
{
|
||||
// If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain
|
||||
if (stream != null)
|
||||
{
|
||||
var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false);
|
||||
_logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var key in dict.Keys)
|
||||
{
|
||||
dictionary[key] = dict[key];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath);
|
||||
}
|
||||
var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false);
|
||||
if (dict == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Resource contains invalid data: '{stream}'");
|
||||
}
|
||||
|
||||
foreach (var key in dict.Keys)
|
||||
{
|
||||
dictionary[key] = dict[key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,19 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
||||
_localization = localization;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the triggers that define when the task will run.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => "RefreshChapterImages";
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[]
|
||||
@@ -162,26 +172,5 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => "RefreshChapterImages";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsHidden => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnabled => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLogged => true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user