aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs8
-rw-r--r--Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs18
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/ca.json72
-rw-r--r--Emby.Server.Implementations/Localization/Core/eu.json70
-rw-r--r--Emby.Server.Implementations/Localization/Core/ht.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/lb.json139
-rw-r--r--Emby.Server.Implementations/Session/WebSocketController.cs98
8 files changed, 321 insertions, 92 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 19fb43bfc..3c2b62239 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1812,11 +1812,11 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc />
public void CreateItem(BaseItem item, BaseItem? parent)
{
- CreateOrUpdateItems(new[] { item }, parent, CancellationToken.None);
+ CreateItems(new[] { item }, parent, CancellationToken.None);
}
/// <inheritdoc />
- public void CreateOrUpdateItems(IReadOnlyList<BaseItem> items, BaseItem? parent, CancellationToken cancellationToken)
+ public void CreateItems(IReadOnlyList<BaseItem> items, BaseItem? parent, CancellationToken cancellationToken)
{
_itemRepository.SaveItems(items, cancellationToken);
@@ -2973,11 +2973,11 @@ namespace Emby.Server.Implementations.Library
{
if (createEntity)
{
- CreateOrUpdateItems([personEntity], null, CancellationToken.None);
+ CreateItems([personEntity], null, CancellationToken.None);
}
await RunMetadataSavers(personEntity, itemUpdateType).ConfigureAwait(false);
- CreateOrUpdateItems([personEntity], null, CancellationToken.None);
+ CreateItems([personEntity], null, CancellationToken.None);
}
}
}
diff --git a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
index 320685b1f..76e564d53 100644
--- a/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/SplashscreenPostScanTask.cs
@@ -43,14 +43,26 @@ public class SplashscreenPostScanTask : ILibraryPostScanTask
/// <inheritdoc />
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var posters = GetItemsWithImageType(ImageType.Primary).Select(x => x.GetImages(ImageType.Primary).First().Path).ToList();
- var backdrops = GetItemsWithImageType(ImageType.Thumb).Select(x => x.GetImages(ImageType.Thumb).First().Path).ToList();
+ var posters = GetItemsWithImageType(ImageType.Primary)
+ .Select(x => x.GetImages(ImageType.Primary).FirstOrDefault()?.Path)
+ .Where(path => !string.IsNullOrEmpty(path))
+ .Select(path => path!)
+ .ToList();
+ var backdrops = GetItemsWithImageType(ImageType.Thumb)
+ .Select(x => x.GetImages(ImageType.Thumb).FirstOrDefault()?.Path)
+ .Where(path => !string.IsNullOrEmpty(path))
+ .Select(path => path!)
+ .ToList();
if (backdrops.Count == 0)
{
// Thumb images fit better because they include the title in the image but are not provided with TMDb.
// Using backdrops as a fallback to generate an image at all
_logger.LogDebug("No thumb images found. Using backdrops to generate splashscreen");
- backdrops = GetItemsWithImageType(ImageType.Backdrop).Select(x => x.GetImages(ImageType.Backdrop).First().Path).ToList();
+ backdrops = GetItemsWithImageType(ImageType.Backdrop)
+ .Select(x => x.GetImages(ImageType.Backdrop).FirstOrDefault()?.Path)
+ .Where(path => !string.IsNullOrEmpty(path))
+ .Select(path => path!)
+ .ToList();
}
_imageEncoder.CreateSplashscreen(posters, backdrops);
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 5388f6f9a..2d29eb5bf 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -134,5 +134,7 @@
"TaskDownloadMissingLyrics": "تنزيل عبارات القصيدة",
"TaskDownloadMissingLyricsDescription": "كلمات",
"TaskExtractMediaSegments": "فحص مقاطع الوسائط",
- "TaskExtractMediaSegmentsDescription": "وسائط"
+ "TaskExtractMediaSegmentsDescription": "يستخرج مقاطع وسائط من إضافات MediaSegment المُفعّلة.",
+ "TaskMoveTrickplayImages": "تغيير مكان صور المعاينة السريعة",
+ "TaskMoveTrickplayImagesDescription": "تُنقل ملفات التشغيل السريع الحالية بناءً على إعدادات المكتبة."
}
diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json
index 2cbc594b0..6cce0e019 100644
--- a/Emby.Server.Implementations/Localization/Core/ca.json
+++ b/Emby.Server.Implementations/Localization/Core/ca.json
@@ -16,7 +16,7 @@
"Folders": "Carpetes",
"Genres": "Gèneres",
"HeaderAlbumArtists": "Artistes de l'àlbum",
- "HeaderContinueWatching": "Continuar veient",
+ "HeaderContinueWatching": "Continua veient",
"HeaderFavoriteAlbums": "Àlbums preferits",
"HeaderFavoriteArtists": "Artistes preferits",
"HeaderFavoriteEpisodes": "Episodis preferits",
@@ -24,13 +24,13 @@
"HeaderFavoriteSongs": "Cançons preferides",
"HeaderLiveTV": "TV en directe",
"HeaderNextUp": "A continuació",
- "HeaderRecordingGroups": "Grups d'enregistrament",
+ "HeaderRecordingGroups": "Grups Musicals",
"HomeVideos": "Vídeos domèstics",
- "Inherit": "Hereta",
- "ItemAddedWithName": "{0} ha sigut afegit a la biblioteca",
- "ItemRemovedWithName": "{0} ha sigut eliminat de la biblioteca",
+ "Inherit": "Heretat",
+ "ItemAddedWithName": "{0} s'ha afegit a la biblioteca",
+ "ItemRemovedWithName": "{0} s'ha eliminat de la biblioteca",
"LabelIpAddressValue": "Adreça IP: {0}",
- "LabelRunningTimeValue": "Temps en funcionament: {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}",
@@ -44,8 +44,8 @@
"NameSeasonNumber": "Temporada {0}",
"NameSeasonUnknown": "Temporada desconeguda",
"NewVersionIsAvailable": "Una nova versió del servidor de Jellyfin està disponible per a descarregar.",
- "NotificationOptionApplicationUpdateAvailable": "Actualització de l'aplicació disponible",
- "NotificationOptionApplicationUpdateInstalled": "Actualització de l'aplicació instal·lada",
+ "NotificationOptionApplicationUpdateAvailable": "Actualització de l'aplicatiu disponible",
+ "NotificationOptionApplicationUpdateInstalled": "Actualització de l'aplicatiu instal·lada",
"NotificationOptionAudioPlayback": "Reproducció d'àudio iniciada",
"NotificationOptionAudioPlaybackStopped": "Reproducció d'àudio aturada",
"NotificationOptionCameraImageUploaded": "Imatge de càmera pujada",
@@ -54,8 +54,8 @@
"NotificationOptionPluginError": "Un complement ha fallat",
"NotificationOptionPluginInstalled": "Complement instal·lat",
"NotificationOptionPluginUninstalled": "Complement desinstal·lat",
- "NotificationOptionPluginUpdateInstalled": "Actualització de complement instal·lada",
- "NotificationOptionServerRestartRequired": "Reinici del servidor requerit",
+ "NotificationOptionPluginUpdateInstalled": "Actualització del complement instal·lada",
+ "NotificationOptionServerRestartRequired": "El servidor s'ha de reiniciar",
"NotificationOptionTaskFailed": "Tasca programada fallida",
"NotificationOptionUserLockedOut": "Usuari expulsat",
"NotificationOptionVideoPlayback": "Reproducció de vídeo iniciada",
@@ -64,15 +64,15 @@
"Playlists": "Llistes de reproducció",
"Plugin": "Complement",
"PluginInstalledWithName": "{0} ha estat instal·lat",
- "PluginUninstalledWithName": "{0} ha estat desinstal·lat",
- "PluginUpdatedWithName": "{0} ha estat actualitzat",
+ "PluginUninstalledWithName": "S'ha instalat {0}",
+ "PluginUpdatedWithName": "S'ha actualitzat {0}",
"ProviderValue": "Proveïdor: {0}",
"ScheduledTaskFailedWithName": "{0} ha fallat",
- "ScheduledTaskStartedWithName": "{0} s'ha iniciat",
- "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciat",
+ "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 altre cop aviat.",
+ "StartupEmbyServerIsLoading": "El servidor de Jellyfin s'està carregant. Proveu de nou en una estona.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"SubtitleDownloadFailureFromForItem": "Els subtítols per a {1} no s'han pogut baixar de {0}",
"Sync": "Sincronitzar",
@@ -80,41 +80,41 @@
"TvShows": "Sèries de TV",
"User": "Usuari",
"UserCreatedWithName": "S'ha creat l'usuari {0}",
- "UserDeletedWithName": "L'usuari {0} ha estat eliminat",
+ "UserDeletedWithName": "S'ha eliminat l'usuari {0}",
"UserDownloadingItemWithValues": "{0} està descarregant {1}",
- "UserLockedOutWithName": "L'usuari {0} ha sigut expulsat",
+ "UserLockedOutWithName": "S'ha expulsat a l'usuari {0}",
"UserOfflineFromDevice": "{0} s'ha desconnectat de {1}",
"UserOnlineFromDevice": "{0} està connectat des de {1}",
- "UserPasswordChangedWithName": "La contrasenya ha estat canviada per a l'usuari {0}",
+ "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}",
- "UserStoppedPlayingItemWithValues": "{0} ha parat de reproduir {1}",
- "ValueHasBeenAddedToLibrary": "{0} ha sigut afegit a la teva biblioteca",
+ "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 teva biblioteca",
"ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versió {0}",
"TaskDownloadMissingSubtitlesDescription": "Cerca a internet els subtítols que faltin a partir de la configuració de metadades.",
"TaskDownloadMissingSubtitles": "Descarrega els subtítols que faltin",
- "TaskRefreshChannelsDescription": "Actualitza la informació dels canals d'internet.",
+ "TaskRefreshChannelsDescription": "Actualitza la informació dels canals per internet.",
"TaskRefreshChannels": "Actualitza els canals",
"TaskCleanTranscodeDescription": "Elimina els arxius de transcodificacions que tinguin més d'un dia.",
"TaskCleanTranscode": "Neteja les transcodificacions",
- "TaskUpdatePluginsDescription": "Actualitza els connectors que estan configurats per a actualitzar-se automàticament.",
- "TaskUpdatePlugins": "Actualitza els connectors",
- "TaskRefreshPeopleDescription": "Actualitza les metadades dels actors i directors de la teva mediateca.",
+ "TaskUpdatePluginsDescription": "Actualitza els complements que estan configurats per a actualitzar-se automàticament.",
+ "TaskUpdatePlugins": "Actualitza els complements",
+ "TaskRefreshPeopleDescription": "Actualitza les metadades dels actors i directors de la teva biblioteca de mitjans.",
"TaskRefreshPeople": "Actualitza les persones",
"TaskCleanLogsDescription": "Esborra els logs que tinguin més de {0} dies.",
"TaskCleanLogs": "Neteja els registres",
- "TaskRefreshLibraryDescription": "Escaneja la mediateca buscant fitxers nous i refresca les metadades.",
+ "TaskRefreshLibraryDescription": "Escaneja la biblioteca de mitjans buscant fitxers nous i refresca les metadades.",
"TaskRefreshLibrary": "Escaneja la biblioteca de mitjans",
"TaskRefreshChapterImagesDescription": "Crea les miniatures dels vídeos que tinguin capítols.",
"TaskRefreshChapterImages": "Extreure les imatges dels capítols",
- "TaskCleanCacheDescription": "Elimina els arxius temporals que ja no són necessaris per al servidor.",
- "TaskCleanCache": "Elimina arxius temporals",
- "TasksChannelsCategory": "Canals d'internet",
- "TasksApplicationCategory": "Aplicació",
+ "TaskCleanCacheDescription": "Elimina la memòria cau no necessària per al servidor.",
+ "TaskCleanCache": "Elimina la memòria cau",
+ "TasksChannelsCategory": "Canals per internet",
+ "TasksApplicationCategory": "Aplicatiu",
"TasksLibraryCategory": "Biblioteca",
"TasksMaintenanceCategory": "Manteniment",
- "TaskCleanActivityLogDescription": "Eliminat entrades del registre d'activitats mes antigues que l'antiguitat configurada.",
+ "TaskCleanActivityLogDescription": "Eliminades les entrades del registre d'activitats més antigues que l'antiguitat configurada.",
"TaskCleanActivityLog": "Buidar el registre d'activitat",
"Undefined": "Indefinit",
"Forced": "Forçat",
@@ -128,11 +128,11 @@
"TaskRefreshTrickplayImages": "Generar miniatures de línia de temps",
"TaskRefreshTrickplayImagesDescription": "Crear miniatures de línia de temps per vídeos en les biblioteques habilitades.",
"TaskCleanCollectionsAndPlaylistsDescription": "Esborra elements de col·leccions i llistes de reproducció que ja no existeixen.",
- "TaskCleanCollectionsAndPlaylists": "Neteja col·leccions i llistes de reproducció",
- "TaskAudioNormalization": "Normalització d'Àudio",
- "TaskAudioNormalizationDescription": "Escaneja arxius per dades de normalització d'àudio.",
- "TaskDownloadMissingLyricsDescription": "Baixar lletres de les cançons",
- "TaskDownloadMissingLyrics": "Baixar lletres que falten",
+ "TaskCleanCollectionsAndPlaylists": "Neteja les col·leccions i llistes de reproducció",
+ "TaskAudioNormalization": "Estabilització d'Àudio",
+ "TaskAudioNormalizationDescription": "Escaneja arxius per dades d'estabilització d'àudio.",
+ "TaskDownloadMissingLyricsDescription": "Baixar les lletres de les cançons",
+ "TaskDownloadMissingLyrics": "Baixar les lletres que falten",
"TaskExtractMediaSegments": "Escaneig de segments multimèdia",
"TaskExtractMediaSegmentsDescription": "Extreu o obté segments multimèdia usant els connectors MediaSegment activats.",
"TaskMoveTrickplayImages": "Migra la ubicació de la imatge de Trickplay",
diff --git a/Emby.Server.Implementations/Localization/Core/eu.json b/Emby.Server.Implementations/Localization/Core/eu.json
index 114c76c54..4df4b90d3 100644
--- a/Emby.Server.Implementations/Localization/Core/eu.json
+++ b/Emby.Server.Implementations/Localization/Core/eu.json
@@ -19,25 +19,25 @@
"Artists": "Artistak",
"Albums": "Albumak",
"TaskOptimizeDatabase": "Datu basea optimizatu",
- "TaskDownloadMissingSubtitlesDescription": "Metadataren konfigurazioan oinarrituta falta diren azpitituluak bilatzen ditu interneten.",
+ "TaskDownloadMissingSubtitlesDescription": "Falta diren azpitituluak bilatzen ditu interneten metadatuen konfigurazioaren arabera.",
"TaskDownloadMissingSubtitles": "Falta diren azpitituluak deskargatu",
"TaskRefreshChannelsDescription": "Internet kanalen informazioa eguneratu.",
"TaskRefreshChannels": "Kanalak eguneratu",
- "TaskCleanTranscodeDescription": "Egun bat baino zaharragoak diren transcode fitxategiak ezabatzen ditu.",
- "TaskCleanTranscode": "Transcode direktorioa garbitu",
- "TaskUpdatePluginsDescription": "Automatikoki eguneratzeko konfiguratutako pluginen eguneraketak deskargatu eta instalatzen ditu.",
+ "TaskCleanTranscodeDescription": "Egun bat baino zaharragoak diren transkodifikazio fitxategiak ezabatzen ditu.",
+ "TaskCleanTranscode": "Transkodifikazio direktorioa garbitu",
+ "TaskUpdatePluginsDescription": "Automatikoki deskargatu eta instalatu eguneraketak konfiguratutako pluginetarako.",
"TaskUpdatePlugins": "Pluginak eguneratu",
- "TaskRefreshPeopleDescription": "Zure liburutegiko aktore eta zuzendarien metadata eguneratzen du.",
+ "TaskRefreshPeopleDescription": "Zure liburutegiko aktore eta zuzendarien metadatuak eguneratzen ditu.",
"TaskRefreshPeople": "Jendea eguneratu",
"TaskCleanLogsDescription": "{0} egun baino zaharragoak diren log fitxategiak ezabatzen ditu.",
"TaskCleanLogs": "Log direktorioa garbitu",
- "TaskRefreshLibraryDescription": "Zure multimedia liburutegia eskaneatzen du fitxategi berriak eta metadatak eguneratzeko.",
- "TaskRefreshLibrary": "Multimedia Liburutegia eskaneatu",
+ "TaskRefreshLibraryDescription": "Zure multimedia liburutegia eskaneatzen du fitxategi berriak eta metadatuak eguneratzeko.",
+ "TaskRefreshLibrary": "Multimedia liburutegia eskaneatu",
"TaskRefreshChapterImagesDescription": "Kapituluak dituzten bideoen miniaturak sortzen ditu.",
"TaskRefreshChapterImages": "Kapituluen irudiak erauzi",
"TaskCleanCacheDescription": "Sistemak behar ez dituen cache fitxategiak ezabatzen ditu.",
- "TaskCleanCache": "Cache Directorioa garbitu",
- "TaskCleanActivityLogDescription": "Konfiguratuta data baino zaharragoak diren log-ak ezabatu.",
+ "TaskCleanCache": "Cache direktorioa garbitu",
+ "TaskCleanActivityLogDescription": "Konfiguratutako baino zaharragoak diren jarduera-log sarrerak ezabatzen ditu.",
"TaskCleanActivityLog": "Erabilera Log-a garbitu",
"TasksChannelsCategory": "Internet Kanalak",
"TasksApplicationCategory": "Aplikazioa",
@@ -45,22 +45,22 @@
"TasksMaintenanceCategory": "Mantenua",
"VersionNumber": "Bertsioa {0}",
"ValueHasBeenAddedToLibrary": "{0} zure multimedia liburutegian gehitu da",
- "UserStoppedPlayingItemWithValues": "{0}-ek {1} ikusteaz bukatu du {2}-(a)n",
- "UserStartedPlayingItemWithValues": "{0} {1} ikusten ari da {2}-(a)n",
- "UserPolicyUpdatedWithName": "{0} Erabiltzailearen politikak aldatu dira",
- "UserPasswordChangedWithName": "{0} Erabiltzailearen pasahitza aldatu da",
- "UserOnlineFromDevice": "{0} online dago {1}-tik",
- "UserOfflineFromDevice": "{0} {1}-tik deskonektatu da",
- "UserLockedOutWithName": "{0} Erabiltzailea blokeatu da",
- "UserDownloadingItemWithValues": "{1} {0}-tik deskargatzen",
+ "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",
+ "UserLockedOutWithName": "{0} erabiltzailea blokeatu da",
+ "UserDownloadingItemWithValues": "{0} {1} deskargatzen ari da",
"UserDeletedWithName": "{0} Erabiltzailea ezabatu da",
"UserCreatedWithName": "{0} Erabiltzailea sortu da",
"User": "Erabiltzailea",
"Undefined": "Ezezaguna",
- "TvShows": "TB showak",
+ "TvShows": "TB serieak",
"System": "Sistema",
- "SubtitleDownloadFailureFromForItem": "{1}-en azpitutuluak {0} deskargatzean huts egin du",
- "StartupEmbyServerIsLoading": "Jellyfin zerbitzaria kargatzen. Saiatu berriro beranduxeago.",
+ "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",
@@ -89,26 +89,26 @@
"NameSeasonNumber": "{0} Denboraldia",
"NameInstallFailed": "{0} instalazioak huts egin du",
"Music": "Musika",
- "MixedContent": "Denetariko edukia",
+ "MixedContent": "Eduki mistoa",
"MessageServerConfigurationUpdated": "Zerbitzariaren konfigurazioa eguneratu da",
- "MessageNamedServerConfigurationUpdatedWithValue": "Zerbitzariaren konfigurazio {0} atala eguneratu da",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Zerbitzariaren {0} konfigurazio atala eguneratu da",
"MessageApplicationUpdatedTo": "Jellyfin zerbitzaria {0}-ra eguneratu da",
"MessageApplicationUpdated": "Jellyfin zerbitzaria eguneratu da",
"Latest": "Azkena",
- "LabelRunningTimeValue": "Denbora martxan: {0}",
+ "LabelRunningTimeValue": "Iraupena: {0}",
"LabelIpAddressValue": "IP helbidea: {0}",
- "ItemRemovedWithName": "{0} liburutegitik ezabatu da",
+ "ItemRemovedWithName": "{0} liburutegitik kendu da",
"ItemAddedWithName": "{0} liburutegira gehitu da",
"HomeVideos": "Etxeko bideoak",
- "HeaderNextUp": "Nobedadeak",
+ "HeaderNextUp": "Hurrengoa",
"HeaderLiveTV": "Zuzeneko TB",
"HeaderFavoriteSongs": "Gogoko abestiak",
- "HeaderFavoriteShows": "Gogoko showak",
+ "HeaderFavoriteShows": "Gogoko serieak",
"HeaderFavoriteEpisodes": "Gogoko atalak",
"HeaderFavoriteArtists": "Gogoko artistak",
"HeaderFavoriteAlbums": "Gogoko albumak",
"Forced": "Behartuta",
- "FailedLoginAttemptWithUserName": "Login egiten akatsa, saiatu hemen {0}",
+ "FailedLoginAttemptWithUserName": "{0}-tik saioa hasteak huts egin du",
"External": "Kanpokoa",
"DeviceOnlineWithName": "{0} konektatu da",
"DeviceOfflineWithName": "{0} deskonektatu da",
@@ -117,13 +117,23 @@
"AuthenticationSucceededWithUserName": "{0} ongi autentifikatu da",
"Application": "Aplikazioa",
"AppDeviceValues": "App: {0}, Gailua: {1}",
- "HearingImpaired": "Entzunaldia aldatua",
+ "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",
- "TaskRefreshTrickplayImages": "\"Trickplay Irudiak Sortu",
- "TaskRefreshTrickplayImagesDescription": "Bideoentzako trickplay aurrebistak sortzen ditu gaitutako liburutegietan."
+ "TaskRefreshTrickplayImages": "Trickplay irudiak sortu",
+ "TaskRefreshTrickplayImagesDescription": "Bideoentzako trickplay aurrebistak sortzen ditu gaitutako liburutegietan.",
+ "TaskAudioNormalization": "Audio normalizazioa",
+ "TaskDownloadMissingLyrics": "Deskargatu falta diren letrak",
+ "TaskDownloadMissingLyricsDescription": "Deskargatu abestientzako letrak",
+ "TaskExtractMediaSegments": "Multimedia segmentuen eskaneoa",
+ "TaskCleanCollectionsAndPlaylistsDescription": "Jada existitzen ez diren bildumak eta erreprodukzio-zerrendak kentzen ditu.",
+ "TaskCleanCollectionsAndPlaylists": "Garbitu bildumak eta erreprodukzio-zerrendak",
+ "TaskExtractMediaSegmentsDescription": "Media segmentuak atera edo lortzen ditu MediaSegment gaituta duten pluginetik.",
+ "TaskMoveTrickplayImages": "Aldatu Trickplay irudien kokalekua",
+ "TaskMoveTrickplayImagesDescription": "Lehendik dauden trickplay fitxategiak liburutegiaren ezarpenen arabera mugitzen dira.",
+ "TaskAudioNormalizationDescription": "Audio normalizazio datuak lortzeko fitxategiak eskaneatzen ditu."
}
diff --git a/Emby.Server.Implementations/Localization/Core/ht.json b/Emby.Server.Implementations/Localization/Core/ht.json
index 0967ef424..4fcba99e9 100644
--- a/Emby.Server.Implementations/Localization/Core/ht.json
+++ b/Emby.Server.Implementations/Localization/Core/ht.json
@@ -1 +1,3 @@
-{}
+{
+ "Books": "liv"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/lb.json b/Emby.Server.Implementations/Localization/Core/lb.json
new file mode 100644
index 000000000..176f2ba2b
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/lb.json
@@ -0,0 +1,139 @@
+{
+ "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",
+ "NameSeasonNumber": "Staffel {0}",
+ "NameSeasonUnknown": "Staffel Onbekannt",
+ "MusicVideos": "Museksvideoen",
+ "NotificationOptionApplicationUpdateAvailable": "Applikatiouns Update verfügbar",
+ "NotificationOptionApplicationUpdateInstalled": "Applikatiouns Update nët Installéiert",
+ "NotificationOptionAudioPlayback": "Audio ofspillen gestart",
+ "NotificationOptionAudioPlaybackStopped": "Audio ofspillen gestoppt",
+ "NotificationOptionCameraImageUploaded": "Kamera Bild eropgelueden",
+ "NotificationOptionInstallationFailed": "Installatioun net gelongen",
+ "NotificationOptionNewLibraryContent": "Neien Bibliothéik Inhalt",
+ "NotificationOptionPluginError": "Plugin Feeler",
+ "NotificationOptionPluginInstalled": "Plugin installéiert",
+ "NotificationOptionPluginUninstalled": "Plugin desinstalléiert",
+ "NotificationOptionPluginUpdateInstalled": "Plugin Update installéiert",
+ "Photos": "Fotoen",
+ "NotificationOptionTaskFailed": "Aufgab net gelongen",
+ "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",
+ "UserDownloadingItemWithValues": "{0} luet {1} erof",
+ "UserOfflineFromDevice": "{0} Benotzer Offline um Gerät {1}",
+ "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.",
+ "TaskCleanCache": "Aufgab Cache Botzen",
+ "TaskRefreshChapterImages": "Kapitel Biller erstellen",
+ "TaskRefreshChapterImagesDescription": "Erstellt Miniaturbiller fir Videoen, déi Kapitelen hunn.",
+ "TaskAudioNormalization": "Audio Normaliséierung",
+ "TaskRefreshLibrary": "Bibliothéik aktualiséieren",
+ "TaskRefreshLibraryDescription": "Scannt deng Mediebibliothéik no neien Dateien a frëscht d’Metadata op.",
+ "TaskCleanLogs": "Log Dateien botzen",
+ "TaskRefreshPeople": "Persounen aktualiséieren",
+ "TaskRefreshPeopleDescription": "Aktualiséiert Metadata fir Schauspiller a Regisseuren an denger Mediebibliothéik.",
+ "TaskRefreshTrickplayImagesDescription": "Erstellt Trickplay-Viraussiichten fir Videoen an aktivéierte Bibliothéiken.",
+ "TaskCleanTranscode": "Transkodéieren botzen",
+ "TaskCleanTranscodeDescription": "Läscht Transkodéierungsdateien, déi méi al wéi een Dag sinn.",
+ "TaskRefreshChannels": "Kanäl aktualiséieren",
+ "TaskDownloadMissingLyrics": "Fehlend Liddertexter eroflueden",
+ "TaskDownloadMissingLyricsDescription": "Lued Liddertexter fir Lidder erof",
+ "TaskDownloadMissingSubtitles": "Fehlend Ënnertitelen eroflueden",
+ "TaskOptimizeDatabase": "Datebank optiméieren",
+ "TaskKeyframeExtractor": "Schlësselbild Extrakter",
+ "TaskCleanCollectionsAndPlaylists": "Sammlungen a Playlisten botzen",
+ "TaskCleanCollectionsAndPlaylistsDescription": "Ewechhuele vun Elementer aus Sammlungen a Playlisten, déi net méi existéieren.",
+ "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",
+ "UserDeletedWithName": "Benotzer {0} geläscht",
+ "TasksApplicationCategory": "Applikatioun",
+ "TaskCleanCacheDescription": "Läscht Cache-Dateien, déi net méi vum System gebraucht ginn.",
+ "UserStoppedPlayingItemWithValues": "{0} ass mat {1} op {2} fäerdeg",
+ "TaskAudioNormalizationDescription": "Scannt Dateien no Donnéeën fir d’Audio-Normaliséierung.",
+ "TaskRefreshTrickplayImages": "Trickplay-Biller generéieren",
+ "TaskDownloadMissingSubtitlesDescription": "Sicht am Internet no fehlenden Ënnertitelen op Basis vun der Metadata-Konfiguratioun.",
+ "TaskMoveTrickplayImages": "Trickplay-Biller-Plaz migréieren",
+ "TaskUpdatePluginsDescription": "Lued Aktualiséierungen erof a installéiert se fir Plugins, déi fir automatesch Updates konfiguréiert sinn.",
+ "TaskKeyframeExtractorDescription": "Extrahéiert Schlësselbiller aus Videodateien, fir méi präzis HLS-Playlisten ze erstellen. Dës Aufgab kann eng längere Zäit daueren.",
+ "TaskRefreshChannelsDescription": "Aktualiséiert Informatiounen iwwer Internetkanäl.",
+ "TaskExtractMediaSegmentsDescription": "Extrahéiert oder kritt Mediesegmenter aus Plugins, déi MediaSegment ënnerstëtzen.",
+ "TaskOptimizeDatabaseDescription": "Kompriméiert d’Datebank a schneit de fräie Speicherplatz zou. Dës Aufgab no engem Bibliothéik-Scan oder anere Ännerungen, déi Datebankmodifikatioune mat sech bréngen, auszeféieren, kann d’Performance verbesseren."
+}
diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs
index cf8e0fb00..c45a4a60f 100644
--- a/Emby.Server.Implementations/Session/WebSocketController.cs
+++ b/Emby.Server.Implementations/Session/WebSocketController.cs
@@ -21,6 +21,7 @@ namespace Emby.Server.Implementations.Session
private readonly SessionInfo _session;
private readonly List<IWebSocketConnection> _sockets;
+ private readonly ReaderWriterLockSlim _socketsLock;
private bool _disposed = false;
public WebSocketController(
@@ -31,10 +32,26 @@ namespace Emby.Server.Implementations.Session
_logger = logger;
_session = session;
_sessionManager = sessionManager;
- _sockets = new List<IWebSocketConnection>();
+ _sockets = new();
+ _socketsLock = new();
}
- private bool HasOpenSockets => GetActiveSockets().Any();
+ private bool HasOpenSockets
+ {
+ get
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ try
+ {
+ _socketsLock.EnterReadLock();
+ return _sockets.Any(i => i.State == WebSocketState.Open);
+ }
+ finally
+ {
+ _socketsLock.ExitReadLock();
+ }
+ }
+ }
/// <inheritdoc />
public bool SupportsMediaControl => HasOpenSockets;
@@ -42,23 +59,38 @@ namespace Emby.Server.Implementations.Session
/// <inheritdoc />
public bool IsSessionActive => HasOpenSockets;
- private IEnumerable<IWebSocketConnection> GetActiveSockets()
- => _sockets.Where(i => i.State == WebSocketState.Open);
-
public void AddWebSocket(IWebSocketConnection connection)
{
_logger.LogDebug("Adding websocket to session {Session}", _session.Id);
- _sockets.Add(connection);
-
- connection.Closed += OnConnectionClosed;
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ try
+ {
+ _socketsLock.EnterWriteLock();
+ _sockets.Add(connection);
+ connection.Closed += OnConnectionClosed;
+ }
+ finally
+ {
+ _socketsLock.ExitWriteLock();
+ }
}
private async void OnConnectionClosed(object? sender, EventArgs e)
{
var connection = sender as IWebSocketConnection ?? throw new ArgumentException($"{nameof(sender)} is not of type {nameof(IWebSocketConnection)}", nameof(sender));
_logger.LogDebug("Removing websocket from session {Session}", _session.Id);
- _sockets.Remove(connection);
- connection.Closed -= OnConnectionClosed;
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ try
+ {
+ _socketsLock.EnterWriteLock();
+ _sockets.Remove(connection);
+ connection.Closed -= OnConnectionClosed;
+ }
+ finally
+ {
+ _socketsLock.ExitWriteLock();
+ }
+
await _sessionManager.CloseIfNeededAsync(_session).ConfigureAwait(false);
}
@@ -69,7 +101,17 @@ namespace Emby.Server.Implementations.Session
T data,
CancellationToken cancellationToken)
{
- var socket = GetActiveSockets().MaxBy(i => i.LastActivityDate);
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ IWebSocketConnection? socket;
+ try
+ {
+ _socketsLock.EnterReadLock();
+ socket = _sockets.Where(i => i.State == WebSocketState.Open).MaxBy(i => i.LastActivityDate);
+ }
+ finally
+ {
+ _socketsLock.ExitReadLock();
+ }
if (socket is null)
{
@@ -94,12 +136,23 @@ namespace Emby.Server.Implementations.Session
return;
}
- foreach (var socket in _sockets)
+ try
+ {
+ _socketsLock.EnterWriteLock();
+ foreach (var socket in _sockets)
+ {
+ socket.Closed -= OnConnectionClosed;
+ socket.Dispose();
+ }
+
+ _sockets.Clear();
+ }
+ finally
{
- socket.Closed -= OnConnectionClosed;
- socket.Dispose();
+ _socketsLock.ExitWriteLock();
}
+ _socketsLock.Dispose();
_disposed = true;
}
@@ -110,12 +163,23 @@ namespace Emby.Server.Implementations.Session
return;
}
- foreach (var socket in _sockets)
+ try
+ {
+ _socketsLock.EnterWriteLock();
+ foreach (var socket in _sockets)
+ {
+ socket.Closed -= OnConnectionClosed;
+ await socket.DisposeAsync().ConfigureAwait(false);
+ }
+
+ _sockets.Clear();
+ }
+ finally
{
- socket.Closed -= OnConnectionClosed;
- await socket.DisposeAsync().ConfigureAwait(false);
+ _socketsLock.ExitWriteLock();
}
+ _socketsLock.Dispose();
_disposed = true;
}
}