Merge branch 'master' into network-rewrite

This commit is contained in:
Shadowghost
2022-10-01 19:59:00 +02:00
225 changed files with 1532 additions and 1035 deletions

View File

@@ -365,11 +365,7 @@ namespace Emby.Server.Implementations.AppBase
validatingStore.Validate(currentConfiguration, configuration);
}
NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
});
NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration));
_configurations.AddOrUpdate(key, configuration, (_, _) => configuration);
@@ -391,11 +387,7 @@ namespace Emby.Server.Implementations.AppBase
/// <param name="configuration">The old configuration.</param>
protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
{
NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
});
NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration));
}
/// <inheritdoc />

View File

@@ -83,6 +83,7 @@ using MediaBrowser.Controller.SyncPlay;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.MediaEncoding.Subtitles;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
@@ -111,7 +112,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Class CompositionRoot.
/// </summary>
public abstract class ApplicationHost : IServerApplicationHost, IDisposable
public abstract class ApplicationHost : IServerApplicationHost, IAsyncDisposable, IDisposable
{
/// <summary>
/// The environment variable prefixes to log at server startup.
@@ -634,7 +635,8 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
serviceCollection.AddSingleton<ISubtitleParser, SubtitleEditParser>();
serviceCollection.AddSingleton<ISubtitleEncoder, SubtitleEncoder>();
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
@@ -1233,5 +1235,49 @@ namespace Emby.Server.Implementations
_disposed = true;
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Used to perform asynchronous cleanup of managed resources or for cascading calls to <see cref="DisposeAsync"/>.
/// </summary>
/// <returns>A ValueTask.</returns>
protected virtual async ValueTask DisposeAsyncCore()
{
var type = GetType();
Logger.LogInformation("Disposing {Type}", type.Name);
foreach (var (part, _) in _disposableParts)
{
var partType = part.GetType();
if (partType == type)
{
continue;
}
Logger.LogInformation("Disposing {Type}", partType.Name);
try
{
part.Dispose();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error disposing {Type}", partType.Name);
}
}
// used for closing websockets
foreach (var session in _sessionManager.Sessions)
{
await session.DisposeAsync().ConfigureAwait(false);
}
}
}
}

View File

@@ -4934,6 +4934,7 @@ SELECT key FROM UserDatas WHERE isFavorite=@IsFavorite AND userId=@UserId)
AND Type = @InternalPersonType)");
statement?.TryBind("@IsFavorite", query.IsFavorite.Value);
statement?.TryBind("@InternalPersonType", typeof(Person).FullName);
statement?.TryBind("@UserId", query.User.InternalId);
}
if (!query.ItemId.Equals(default))
@@ -4988,11 +4989,6 @@ AND Type = @InternalPersonType)");
statement?.TryBind("@NameContains", "%" + query.NameContains + "%");
}
if (query.User != null)
{
statement?.TryBind("@UserId", query.User.InternalId);
}
return whereClauses;
}

View File

@@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.People))
{
AttachPeople(dto, item);
AttachPeople(dto, item, user);
}
if (options.ContainsField(ItemFields.PrimaryImageAspectRatio))
@@ -503,7 +503,8 @@ namespace Emby.Server.Implementations.Dto
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item)
/// <param name="user">The requesting user.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item, User user = null)
{
// Ordering by person type to ensure actors and artists are at the front.
// This is taking advantage of the fact that they both begin with A
@@ -560,6 +561,9 @@ namespace Emby.Server.Implementations.Dto
return null;
}
}).Where(i => i != null)
.Where(i => user == null ?
true :
i.IsVisible(user))
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);

View File

@@ -29,10 +29,10 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.9" />
<PackageReference Include="Mono.Nat" Version="3.0.3" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.4" />
<PackageReference Include="sharpcompress" Version="0.32.1" />
<PackageReference Include="sharpcompress" Version="0.32.2" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
</ItemGroup>

View File

@@ -1,6 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;

View File

@@ -11,7 +11,6 @@ using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer
@@ -19,7 +18,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Class WebSocketConnection.
/// </summary>
public class WebSocketConnection : IWebSocketConnection, IDisposable
public class WebSocketConnection : IWebSocketConnection
{
/// <summary>
/// The logger.
@@ -36,6 +35,8 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
private readonly WebSocket _socket;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
/// </summary>
@@ -244,10 +245,39 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (_disposed)
{
return;
}
if (dispose)
{
_socket.Dispose();
}
_disposed = true;
}
/// <inheritdoc />
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Used to perform asynchronous cleanup of managed resources or for cascading calls to <see cref="DisposeAsync"/>.
/// </summary>
/// <returns>A ValueTask.</returns>
protected virtual async ValueTask DisposeAsyncCore()
{
if (_socket.State == WebSocketState.Open)
{
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "System Shutdown", CancellationToken.None).ConfigureAwait(false);
}
_socket.Dispose();
}
}
}

View File

@@ -46,7 +46,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
@@ -2453,6 +2452,12 @@ namespace Emby.Server.Implementations.Library
return RootFolder;
}
/// <inheritdoc />
public void QueueLibraryScan()
{
_taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
}
/// <inheritdoc />
public int? GetSeasonNumberFromPath(string path)
=> SeasonPathParser.Parse(path, true, true).SeasonNumber;
@@ -2523,7 +2528,7 @@ namespace Emby.Server.Implementations.Library
}
catch (Exception ex)
{
_logger.LogError(ex, "Error reading the episode informations with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path);
_logger.LogError(ex, "Error reading the episode information with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path);
}
var changed = false;
@@ -2760,7 +2765,8 @@ namespace Emby.Server.Implementations.Library
public List<Person> GetPeopleItems(InternalPeopleQuery query)
{
return _itemRepository.GetPeopleNames(query).Select(i =>
return _itemRepository.GetPeopleNames(query)
.Select(i =>
{
try
{
@@ -2771,7 +2777,12 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person");
return null;
}
}).Where(i => i != null).ToList();
})
.Where(i => i != null)
.Where(i => query.User == null ?
true :
i.IsVisible(query.User))
.ToList();
}
public List<string> GetPeopleNames(InternalPeopleQuery query)

View File

@@ -387,7 +387,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (!string.IsNullOrEmpty(item.Path))
{
// check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
// check for imdb id - we use full media path, as we can assume, that this will match in any use case (either id in parent dir or in file name)
var imdbid = item.Path.AsSpan().GetAttributeValue("imdbid");
if (!string.IsNullOrWhiteSpace(imdbid))
@@ -464,7 +464,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ??
new MultiItemResolverResult();
if (result.Items.Count == 1)
var isPhotosCollection = string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)
|| string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase);
if (!isPhotosCollection && result.Items.Count == 1)
{
var videoPath = result.Items[0].Path;
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));

View File

@@ -995,7 +995,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
throw new Exception("Tuner not found.");
throw new ResourceNotFoundException("Tuner not found.");
}
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)

View File

@@ -13,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -297,7 +298,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
else
{
_taskCompletionSource.TrySetException(
new Exception(
new FfmpegException(
string.Format(
CultureInfo.InvariantCulture,
"Recording for {0} failed. Exit code {1}",

View File

@@ -20,6 +20,7 @@ using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -591,13 +592,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
catch (HttpRequestException ex)
{
if (ex.StatusCode.HasValue)
if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest)
{
if ((int)ex.StatusCode.Value == 400)
{
_tokens.Clear();
_lastErrorResponse = DateTime.UtcNow;
}
_tokens.Clear();
_lastErrorResponse = DateTime.UtcNow;
}
throw;
@@ -662,7 +660,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return root.Token;
}
throw new Exception("Could not authenticate with Schedules Direct Error: " + root.Message);
throw new AuthenticationException("Could not authenticate with Schedules Direct Error: " + root.Message);
}
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
@@ -697,7 +695,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (string.IsNullOrEmpty(token))
{
throw new Exception("token required");
throw new ArgumentException("token required");
}
_logger.LogInformation("Headends on account ");
@@ -768,14 +766,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var listingsId = info.ListingsId;
if (string.IsNullOrEmpty(listingsId))
{
throw new Exception("ListingsId required");
throw new ArgumentException("ListingsId required");
}
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(token))
{
throw new Exception("token required");
throw new ArgumentException("token required");
}
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);

View File

@@ -196,7 +196,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
IsInfiniteStream = true,
IsRemote = isRemote,
IgnoreDts = true,
IgnoreDts = info.IgnoreDts,
SupportsDirectPlay = supportsDirectPlay,
SupportsDirectStream = supportsDirectStream,

View File

@@ -199,7 +199,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (string.IsNullOrWhiteSpace(numberString))
{
// Using this as a fallback now as this leads to Problems with channels like "5 USA"
// where 5 isn't ment to be the channel number
// where 5 isn't meant to be the channel number
// Check for channel number with the format from SatIp
// #EXTINF:0,84. VOX Schweiz
// #EXTINF:0,84.0 - VOX Schweiz

View File

@@ -92,22 +92,22 @@
"ValueHasBeenAddedToLibrary": "تمت اضافت {0} إلى مكتبة الوسائط",
"ValueSpecialEpisodeName": "حلقه خاصه - {0}",
"VersionNumber": "النسخة {0}",
"TaskCleanCacheDescription": "يحذف ملفات ذاكرة التخزين المؤقت التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "احذف مجلد ذاكرة التخزين المؤقت",
"TaskCleanCacheDescription": "يحذف الملفات المؤقتة التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "احذف ما بمجلد الملفات المؤقتة",
"TasksChannelsCategory": "قنوات الإنترنت",
"TasksLibraryCategory": "مكتبة",
"TasksMaintenanceCategory": "صيانة",
"TaskRefreshLibraryDescription": قوم بفصح مكتبة الوسائط الخاصة بك بحثًا عن ملفات جديدة وتحديث البيانات الوصفية.",
"TaskRefreshLibraryDescription": "يفصح مكتبة الوسائط الخاصة بك بحثًا عن ملفات جديدة، ومن ثم يتحدث البيانات الوصفية.",
"TaskRefreshLibrary": "افحص مكتبة الوسائط",
"TaskRefreshChapterImagesDescription": قوم بانشاء صور مصغرة لمقاطع الفيديو التي تحتوي على فصول.",
"TaskRefreshChapterImagesDescription": ُنشئ صور مصغرة لمقاطع الفيديو التي تحتوي على فصول.",
"TaskRefreshChapterImages": "استخراج صور الفصل",
"TasksApplicationCategory": "تطبيق",
"TaskDownloadMissingSubtitlesDescription": قوم بالبحث في الإنترنت على الترجمات المفقودة إستنادا على البيانات الوصفية.",
"TaskDownloadMissingSubtitles": "تحميل الترجمات المفقودة",
"TaskRefreshChannelsDescription": قوم بتحديث معلومات قنوات الإنترنت.",
"TaskDownloadMissingSubtitlesDescription": "يبحث في الإنترنت على الترجمات الناقصة استنادا على البيانات الوصفية.",
"TaskDownloadMissingSubtitles": "تحميل الترجمات الناقصة",
"TaskRefreshChannelsDescription": "يحدث معلومات قنوات الإنترنت.",
"TaskRefreshChannels": "إعادة تحديث القنوات",
"TaskCleanTranscodeDescription": قوم بحذف ملفات الترميز الأقدم من يوم واحد.",
"TaskCleanTranscode": "حذف سجلات الترميز",
"TaskCleanTranscodeDescription": "يحذف ملفات الترميز الأقدم من يوم واحد.",
"TaskCleanTranscode": "حذف ما بمجلد الترميز",
"TaskUpdatePluginsDescription": "تحميل وتثبيت الإضافات التي تم تفعيل التحديث التلقائي لها.",
"TaskUpdatePlugins": "تحديث الإضافات",
"TaskRefreshPeopleDescription": "يقوم بتحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
@@ -116,12 +116,12 @@
"TaskCleanLogs": "حذف مسار السجل",
"TaskCleanActivityLogDescription": "يحذف سجل الأنشطة الأقدم من الوقت الذي تم تحديده.",
"TaskCleanActivityLog": "حذف سجل الأنشطة",
"Default": "إفتراضي",
"Default": "افتراضي",
"Undefined": "غير معرف",
"Forced": "ملحقة",
"TaskOptimizeDatabaseDescription": "يضغط قاعدة البيانات ويقتطع المساحة الحرة. تشغيل هذه المهمة بعد فحص المكتبة أو إجراء تغييرات أخرى تتضمن تعديلات في قاعدة البيانات قد تؤدي إلى تحسين الأداء.",
"TaskOptimizeDatabase": "تحسين قاعدة البيانات",
"TaskKeyframeExtractorDescription": قوم باستخراج الإطارات الرئيسيه من ملفات الفيديو لكي ينشئ قوائم تشغيل بث HTTP المباشر. هذه المهمه قد تستمر لاوقات طويلة.",
"TaskKeyframeExtractorDescription": "يستخرج الإطارات الرئيسية من ملفات الفيديو لكي ينشئ قوائم تشغيل بث HTTP المباشر. قد تستمر هذه العملية لوقت طويل.",
"TaskKeyframeExtractor": "مستخرج الإطار الرئيسي",
"External": "خارجي"
}

View File

@@ -119,5 +119,6 @@
"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}"
"UserOnlineFromDevice": "{0} on ühendatud seadmest {1}",
"External": "Väline"
}

View File

@@ -5,7 +5,7 @@
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
"CameraImageUploadedFrom": "Une photo a été chargée depuis {0}",
"CameraImageUploadedFrom": "Une photo a été téléversée depuis {0}",
"Channels": "Chaînes",
"ChapterNameValue": "Chapitre {0}",
"Collections": "Collections",
@@ -42,13 +42,13 @@
"MusicVideos": "Clips musicaux",
"NameInstallFailed": "{0} échec de l'installation",
"NameSeasonNumber": "Saison {0}",
"NameSeasonUnknown": "Saison Inconnue",
"NameSeasonUnknown": "Saison inconnue",
"NewVersionIsAvailable": "Une nouvelle version de Jellyfin Serveur est disponible au téléchargement.",
"NotificationOptionApplicationUpdateAvailable": "Mise à jour de l'application disponible",
"NotificationOptionApplicationUpdateInstalled": "Mise à jour de l'application installée",
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été téléversée",
"NotificationOptionInstallationFailed": "Échec de l'installation",
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
"NotificationOptionPluginError": "Erreur d'extension",
@@ -93,33 +93,33 @@
"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.",
"TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquants sur Internet en se basant sur la configuration des métadonnées.",
"TaskDownloadMissingSubtitles": "Télécharger les sous-titres manquants",
"TaskRefreshChannelsDescription": "Rafraîchit les informations des chaînes en ligne.",
"TaskRefreshChannels": "Rafraîchir les chaînes",
"TaskRefreshChannelsDescription": "Actualise les informations des chaînes en ligne.",
"TaskRefreshChannels": "Actualiser les chaînes",
"TaskCleanTranscodeDescription": "Supprime les fichiers transcodés de plus d'un jour.",
"TaskCleanTranscode": "Nettoyer les dossier des transcodages",
"TaskCleanTranscode": "Nettoyer le dossier des transcodages",
"TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurées pour être mises à jour automatiquement.",
"TaskUpdatePlugins": "Mettre à jour les extensions",
"TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque.",
"TaskRefreshPeople": "Rafraîchir les acteurs",
"TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre médiathèque.",
"TaskRefreshPeople": "Actualiser les acteurs",
"TaskCleanLogsDescription": "Supprime les journaux de plus de {0} jours.",
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
"TaskRefreshLibraryDescription": "Scanne votre médiathèque pour trouver les nouveaux fichiers et rafraîchit les métadonnées.",
"TaskRefreshLibraryDescription": "Scanne votre médiathèque pour trouver les nouveaux fichiers et actualise les métadonnées.",
"TaskRefreshLibrary": "Scanner la médiathèque",
"TaskRefreshChapterImagesDescription": "Crée des vignettes pour les vidéos ayant des chapitres.",
"TaskRefreshChapterImages": "Extraire les images de chapitre",
"TaskCleanCacheDescription": "Supprime les fichiers de cache dont le système n'a plus besoin.",
"TaskCleanCache": "Vider le répertoire cache",
"TasksApplicationCategory": "Application",
"TasksLibraryCategory": "Bibliothèque",
"TasksLibraryCategory": "Médiathèque",
"TasksMaintenanceCategory": "Maintenance",
"TaskCleanActivityLogDescription": "Supprime les entrées du journal d'activité antérieures à l'âge configuré.",
"TaskCleanActivityLog": "Nettoyer le journal d'activité",
"Undefined": "Non défini",
"Forced": "Forcé",
"Default": "Par défaut",
"TaskOptimizeDatabaseDescription": "Réduit les espaces vides ou inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la bibliothèque ou toute autre modification de la base de données peut améliorer les performances du serveur.",
"TaskOptimizeDatabaseDescription": "Réduit les espaces vides ou inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la médiathèque ou toute autre modification de la base de données peut améliorer les performances du serveur.",
"TaskOptimizeDatabase": "Optimiser la base de données",
"TaskKeyframeExtractorDescription": "Extrait les images clés des fichiers vidéo pour créer des listes de lecture HLS plus précises. Cette tâche peut durer très longtemps.",
"TaskKeyframeExtractor": "Extracteur d'image clé",

View File

@@ -122,5 +122,6 @@
"TaskOptimizeDatabase": "Optimiziraj bazu podataka",
"External": "Vanjski",
"TaskKeyframeExtractorDescription": "Izvlačenje ključnih okvira iz videozapisa za stvaranje objektivnije HLS liste za reprodukciju. Pokretanje ovog zadatka može potrajati.",
"TaskKeyframeExtractor": "Izvoditelj ključnog okvira"
"TaskKeyframeExtractor": "Izvoditelj ključnog okvira",
"TaskOptimizeDatabaseDescription": "Sažima bazu podataka i uklanja prazan prostor. Pokretanje ovog zadatka, može poboljšati performanse nakon provođenja indeksiranja biblioteke ili provođenja drugih promjena koje utječu na bazu podataka."
}

View File

@@ -120,5 +120,8 @@
"Forced": "강제하기",
"Default": "기본 설정",
"TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.",
"TaskOptimizeDatabase": "데이터베이스 최적화"
"TaskOptimizeDatabase": "데이터베이스 최적화",
"TaskKeyframeExtractorDescription": "비디오 파일에서 키프레임을 추출하여 더 정확한 HLS 재생 목록을 만듭니다. 이 작업은 오랫동안 진행될 수 있습니다.",
"TaskKeyframeExtractor": "키프레임 추출",
"External": "외부"
}

View File

@@ -39,7 +39,7 @@
"MixedContent": "Mixed content",
"Movies": "Filmai",
"Music": "Muzika",
"MusicVideos": "Muzikiniai klipai",
"MusicVideos": "Muzikiniai vaizdo įrašai",
"NameInstallFailed": "{0} diegimo klaida",
"NameSeasonNumber": "Sezonas {0}",
"NameSeasonUnknown": "Sezonas neatpažintas",

View File

@@ -84,7 +84,7 @@
"CameraImageUploadedFrom": "Jauns kameras attēls ir ticis augšupielādēts no {0}",
"Books": "Grāmatas",
"Artists": "Izpildītāji",
"Albums": "Albumi",
"Albums": "Albūmi",
"ProviderValue": "Provider: {0}",
"HeaderFavoriteSongs": "Dziesmu Favorīti",
"HeaderFavoriteShows": "Raidījumu Favorīti",
@@ -117,7 +117,8 @@
"TaskCleanActivityLogDescription": "Nodzēš darbību žurnāla ierakstus, kuri ir vecāki par doto vecumu.",
"TaskCleanActivityLog": "Notīrīt Darbību Žurnālu",
"Undefined": "Nenoteikts",
"Default": "Noklusējums",
"Default": "Noklusējuma",
"TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Uzdevum palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.",
"TaskOptimizeDatabase": "Optimizēt datubāzi"
"TaskOptimizeDatabase": "Optimizēt datubāzi",
"External": "Ārējais"
}

View File

@@ -64,9 +64,9 @@
"CameraImageUploadedFrom": "Нова слика од камера беше поставена од {0}",
"Books": "Книги",
"AuthenticationSucceededWithUserName": "{0} успешно поврзан",
"Artists": "Изведувач",
"Artists": "Изведувачи",
"Application": "Апликација",
"AppDeviceValues": "Аплиакција: {0}, Уред: {1}",
"AppDeviceValues": "Апликација: {0}, Уред: {1}",
"Albums": "Албуми",
"VersionNumber": "Верзија {0}",
"ValueSpecialEpisodeName": "Специјално - {0}",
@@ -100,5 +100,27 @@
"TasksMaintenanceCategory": "Одржување",
"Undefined": "Недефинирано",
"Forced": "Принудно",
"Default": "Зададено"
"Default": "Зададено",
"TaskKeyframeExtractorDescription": "Извлекува клучни рамки од видео фајлови за да се направат попрецизни HLS плејлисти. Оваа задача може да работи многу долго време.",
"TaskKeyframeExtractor": "Извлекувач на клучни рамки",
"TaskOptimizeDatabaseDescription": "Компактира датабазата и смалува празното место. Извршувањето на оваа задача по скенирање на библиотеката или правење други промени што прават модификации на датабазата може да подобри перформансите.",
"TaskOptimizeDatabase": "Оптимизирај датабаза",
"TaskDownloadMissingSubtitlesDescription": "Пребарува интернет за преводи што недостиваат според метадата конфигурација.",
"TaskDownloadMissingSubtitles": "Симни преводи што недостигаат",
"TaskRefreshChannelsDescription": "Ажурирај информации за интернет канали.",
"TaskRefreshChannels": "Ажурирај Канали",
"TaskCleanTranscodeDescription": "Избриши транскодирани фајлови постари од еден ден.",
"TaskCleanTranscode": "Исчисти Директориум за Транскодирање",
"TaskUpdatePluginsDescription": "Симни и инсталирај ажурирања за плагини што се конфигурирани за автоматско ажурирање.",
"TaskUpdatePlugins": "Ажурирај Плагини",
"TaskRefreshPeopleDescription": "Ажурирај метадата за акери и директори во вашата медиска библиотека.",
"TaskRefreshPeople": "Ажурирајте ги Луѓето",
"TaskCleanLogsDescription": "Избриши лог фајлови постари од {0} денови.",
"TaskCleanLogs": "Избриши Директориум на Логови",
"TaskRefreshLibraryDescription": "Скенирајте ја вашата медиска библиотека за нови фајлови и ажурирај метадата.",
"TaskRefreshLibrary": "Скенирај Медиумска Библиотека",
"TaskRefreshChapterImagesDescription": "Создава тамбнеил за видеата шти имаат поглавја.",
"TaskCleanActivityLogDescription": "Избришува логови на активности постари од определеното време.",
"TaskCleanActivityLog": "Избриши Лог на Активности",
"External": "Надворешен"
}

View File

@@ -61,7 +61,7 @@
"NotificationOptionVideoPlayback": "Ulangmain video bermula",
"NotificationOptionVideoPlaybackStopped": "Ulangmain video dihentikan",
"Photos": "Gambar-gambar",
"Playlists": "Senarai main",
"Playlists": "Senarai ulangmain",
"Plugin": "Plugin",
"PluginInstalledWithName": "{0} telah dipasang",
"PluginUninstalledWithName": "{0} telah dinyahpasang",

View File

@@ -6,97 +6,97 @@
"Artists": "အနုပညာရှင်များ",
"Albums": "သီချင်းအခွေများ",
"TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.",
"TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ",
"TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ",
"TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။",
"TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ",
"TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ",
"TaskRefreshChannelsDescription": "အင်တာနက်ချန်နယ်အချက်အလက်ကို ပြန်လည်စတင်သည်။",
"TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ",
"TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ",
"TaskCleanTranscodeDescription": "သက်တမ်း တစ်ရက်ထက်ပိုသော အသွင်ပြောင်းကုဒ်ဖိုင်များကို ဖျက်ပါ။",
"TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskUpdatePluginsDescription": "အလိုအလျောက် အပ်ဒိတ်လုပ်ရန် စီစဉ်ထားသော ပလပ်အင်များအတွက် အပ်ဒိတ်များကို ဒေါင်းလုဒ်လုပ်ပြီး ထည့်သွင်းပါ။",
"TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ",
"TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ",
"TaskRefreshPeopleDescription": "သင့်မီဒီယာစာကြည့်တိုက်ရှိ သရုပ်ဆောင်များနှင့် ဒါရိုက်တာများအတွက် မက်တာဒေတာကို အပ်ဒိတ်လုပ်ပါ။",
"TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ",
"TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ",
"TaskCleanLogsDescription": "{0} ရက်ထက်ပိုသော မှတ်တမ်းဖိုင်များကို ဖျက်သည်။",
"TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskRefreshLibraryDescription": "သင့်မီဒီယာဒစ်ဂျစ်တိုက်ကို ဖိုင်အသစ်များရှိမရှိ စကင်န်ဖတ်ပြီး ဖိုင်ရဲ့အကြောင်းအရာများ ကို ပြန်ပြုပြင်မွမ်းမံပါ။",
"TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ",
"TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ",
"TaskRefreshChapterImagesDescription": "အခန်းများပါရှိသော ဗီဒီယိုများအတွက် ပုံသေးများကို ဖန်တီးပါ။",
"TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ",
"TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ",
"TaskCleanCacheDescription": "စနစ်မှ မလိုအပ်တော့သော ကက်ရှ်ဖိုင်များကို ဖျက်ပါ။.",
"TaskCleanCache": "Cache Directory ကို ရှင်းပါ",
"TaskCleanCache": "Cache Directory ကို ရှင်းပါ",
"TaskCleanActivityLogDescription": "စီစဉ်သတ်မှတ်ထားသော အသက်ထက် ပိုကြီးသော လုပ်ဆောင်ချက်မှတ်တမ်းများကို ဖျက်ပါ။",
"TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ",
"TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ",
"TasksChannelsCategory": "အင်တာနက် ချန်နယ်လိုင်းများ",
"TasksApplicationCategory": "အပလီကေးရှင်း",
"TasksLibraryCategory": "မီဒီယာတိုက်",
"TasksMaintenanceCategory": "ပြုပြင် ထိန်းသိမ်းခြင်း",
"VersionNumber": "ဗားရှင်း {0}",
"ValueSpecialEpisodeName": "အထူး- {0}",
"ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ",
"ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ",
"UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ",
"UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်",
"UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်",
"UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်",
"UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်",
"UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်",
"UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်",
"UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်",
"UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ",
"UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ",
"UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ",
"UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ",
"User": "အသုံးပြုသူ",
"Undefined": "သတ်မှတ်မထားသော",
"TvShows": "တီဗီ ဇာတ်လမ်းတွဲများ",
"System": "စနစ်",
"Sync": "ထပ်တူကျသည်။",
"SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ",
"SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ",
"StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို အသင့်ပြင်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။",
"Songs": "သီချင်းများ",
"Shows": "ဇာတ်လမ်းတွဲများ",
"ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်",
"ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်",
"ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ",
"ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်",
"ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်",
"ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ",
"ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}",
"PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်",
"PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ",
"PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်",
"PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်",
"PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ",
"PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်",
"Plugin": "ပလပ်အင်",
"Playlists": "အစီအစဉ်များ",
"Photos": "ဓာတ်ပုံများ",
"NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်",
"NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်",
"NotificationOptionTaskFailed": "စီစဉ်ထားသော အလုပ်ပျက်ကွက်",
"NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်",
"NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ",
"NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ",
"NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်",
"NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း",
"NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်",
"NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ",
"NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ",
"NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်",
"NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ",
"NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်",
"NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ",
"NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ",
"NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်",
"NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း",
"NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်",
"NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ",
"NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ",
"NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်",
"NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ",
"NewVersionIsAvailable": "Jellyfin Server ၏ ဗားရှင်းအသစ်ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါပြီ။",
"NameSeasonUnknown": "ဇာတ်လမ်းတွဲ အပိုင်းမသိ",
"NameSeasonNumber": "ဇာတ်လမ်းတွဲ အပိုင်း {0}",
"NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ",
"NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ",
"MusicVideos": "ဂီတဗီဒီယိုများ",
"Music": "တေးဂီတ",
"Movies": "ရုပ်ရှင်များ",
"MixedContent": "ရောနှောပါဝင်မှု",
"MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်",
"MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"Latest": "နောက်ဆုံး",
"LabelRunningTimeValue": "ကြာချိန် - {0}",
"LabelIpAddressValue": "IP လိပ်စာ- {0}",
"ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်",
"ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်",
"Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်",
"ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်",
"ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်",
"Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်",
"HomeVideos": "ကိုယ်တိုင်ရိုက် ဗီဒီယိုများ",
"HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ",
"HeaderNextUp": "နောက်ထပ်",
@@ -106,18 +106,18 @@
"HeaderFavoriteEpisodes": "အကြိုက်ဆုံး ဇာတ်လမ်းအပိုင်းများ",
"HeaderFavoriteArtists": "အကြိုက်ဆုံးအနုပညာရှင်များ",
"HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ",
"HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ",
"HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ",
"HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ",
"Genres": "အမျိုးအစားများ",
"Forced": "အတင်းအကြပ်",
"Folders": "ဖိုလ်ဒါများ",
"Favorites": "အကြိုက်ဆုံးများ",
"FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ",
"DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်",
"DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ",
"DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်",
"DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ",
"ChapterNameValue": "အခန်း {0}",
"CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်",
"AuthenticationSucceededWithUserName": "{0} စစ်မှန်ကြောင်း အောင်မြင်စွာ အတည်ပြုပြီးပါပြီ",
"CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်",
"AuthenticationSucceededWithUserName": "{0} အောင်မြင်စွာ စစ်မှန်ကြောင်း အတည်ပြုပြီးပါပြီ",
"Application": "အပလီကေးရှင်း",
"AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}",
"External": "ပြင်ပ"

View File

@@ -8,15 +8,15 @@
"CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
"Channels": "Canais",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Coleções",
"Collections": "Colecçõ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",
"HeaderAlbumArtists": "Artistas do álbum",
"HeaderContinueWatching": "Continuar a ver",
"HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",

View File

@@ -1,5 +1,5 @@
{
"HeaderLiveTV": "TV Ao Vivo",
"HeaderLiveTV": "TV Em Direto",
"Collections": "Coleções",
"Books": "Livros",
"Artists": "Artistas",
@@ -10,9 +10,9 @@
"HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",
"HeaderFavoriteShows": "Séries Favoritas",
"HeaderContinueWatching": "Continuar assistindo",
"HeaderContinueWatching": "Continuar a ver",
"HeaderAlbumArtists": "Artistas do Álbum",
"Genres": "Gêneros",
"Genres": "Géneros",
"Folders": "Diretórios",
"Favorites": "Favoritos",
"Channels": "Canais",
@@ -74,7 +74,7 @@
"ItemRemovedWithName": "{0} foi removido da biblioteca",
"ItemAddedWithName": "{0} foi adicionado à biblioteca",
"Inherit": "Herdar",
"HomeVideos": "Vídeos principais",
"HomeVideos": "Vídeos Caseiros",
"HeaderRecordingGroups": "Grupos de Gravação",
"ValueSpecialEpisodeName": "Episódio Especial - {0}",
"Sync": "Sincronização",
@@ -83,14 +83,14 @@
"Playlists": "Listas de Reprodução",
"Photos": "Fotografias",
"Movies": "Filmes",
"FailedLoginAttemptWithUserName": "Tentativa falha de login a partir de {0}",
"DeviceOnlineWithName": "{0} está conectado",
"DeviceOfflineWithName": "{0} desconectou-se",
"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": "Aplicativo",
"AppDeviceValues": "Aplicativo {0}, Dispositivo: {1}",
"Application": "Aplicação",
"AppDeviceValues": "Aplicação: {0}, Dispositivo: {1}",
"TaskCleanCache": "Limpar Diretório de Cache",
"TasksApplicationCategory": "Aplicativo",
"TasksLibraryCategory": "Biblioteca",

View File

@@ -90,7 +90,7 @@
"UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
"ValueSpecialEpisodeName": "Bonus - {0}",
"ValueSpecialEpisodeName": "Posebna epizoda - {0}",
"VersionNumber": "Različica {0}",
"TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise",
"TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.",
@@ -122,5 +122,6 @@
"TaskOptimizeDatabaseDescription": "Stisne bazo podatkov in uredi prazen prostor. Zagon tega opravila po iskanju predstavnosti ali drugih spremembah ki vplivajo na bazo podatkov lahko izboljša hitrost delovanja.",
"TaskOptimizeDatabase": "Optimiziraj bazo podatkov",
"TaskKeyframeExtractor": "Ekstraktor ključnih sličic",
"External": "Zunanje"
"External": "Zunanji",
"TaskKeyframeExtractorDescription": "Iz video datoteke Izvleče ključne sličice, da ustvari bolj natančne sezname predvajanja HLS. Proces lahko traja dolgo časa."
}

View File

@@ -86,7 +86,7 @@
"Channels": "Канали",
"CameraImageUploadedFrom": "Нова фотографија је учитана са {0}",
"Books": "Књиге",
"AuthenticationSucceededWithUserName": "{0} Успешна аутентикација",
"AuthenticationSucceededWithUserName": "{0} Успешна аутентификација",
"Artists": "Извођачи",
"Application": "Апликација",
"AppDeviceValues": "Апликација: {0}, Уређај: {1}",
@@ -118,7 +118,9 @@
"Undefined": "Недефинисано",
"Forced": "Принудно",
"Default": "Подразумевано",
"TaskOptimizeDatabase": "Оптимизуј датабазу",
"TaskOptimizeDatabase": "Оптимизуј банку података",
"TaskOptimizeDatabaseDescription": "Сажима базу података и скраћује слободан простор. Покретање овог задатка након скенирања библиотеке или других промена које подразумевају измене базе података које могу побољшати перформансе.",
"External": "Спољно"
"External": "Спољно",
"TaskKeyframeExtractorDescription": "Екстрактује кљулне сличице из видео датотека да би креирао више преицзну HLS плеј-листу. Овај задатак може да потраје дуже време.",
"TaskKeyframeExtractor": "Екстрактор кључних сличица"
}

View File

@@ -3,7 +3,16 @@
"Channels": "قانال",
"CameraImageUploadedFrom": "{0} ئورۇندىن يېڭى سۈرەت چىقىرىلدى",
"Books": "كىتاب",
"AuthenticationSucceededWithUserName": "تىزىملىتىش مۇۋەپپەقىيەتلىك بول",
"AuthenticationSucceededWithUserName": "{0} تەستىقلاش مۇۋاپىقىيەتلىك بولدى",
"Artists": "سەنئەتكار",
"Albums": "پىلاستىنكا"
"Albums": "پىلاستىنكا",
"DeviceOnlineWithName": "{0} ئۇلاندى",
"DeviceOfflineWithName": "{0} ئۈزۈلدى",
"Collections": "توپلام",
"Application": "ئەپ",
"AppDeviceValues": "ئەپ: {0}، ئۈسكۈنە: {1}",
"HeaderLiveTV": "تور تېلېۋىزىيەسى",
"Default": "سۈكۈتتىكى",
"Folders": "ھۆججەت خالتىسى",
"Favorites": "ساقلىغۇچ"
}

View File

@@ -120,5 +120,8 @@
"Default": "預設",
"TaskOptimizeDatabaseDescription": "壓縮數據庫並截斷可用空間。在掃描媒體庫或執行其他數據庫的修改後運行此任務可能會提高性能。",
"TaskOptimizeDatabase": "最佳化數據庫",
"TaskCleanActivityLogDescription": "刪除早於設定時間的日誌記錄。"
"TaskCleanActivityLogDescription": "刪除早於設定時間的日誌記錄。",
"TaskKeyframeExtractorDescription": "提取關鍵格以創建更準確的HLS播放列表。次指示可能用時很長。",
"TaskKeyframeExtractor": "關鍵幀提取器",
"External": "外部"
}

View File

@@ -0,0 +1,10 @@
FI-S,1
FI-T,1
FI-7,4
FI-12,5
FI-16,8
FI-18,9
FI-K7,4
FI-K12,5
FI-K16,8
FI-K18,9
1 FI-S 1
2 FI-T 1
3 FI-7 4
4 FI-12 5
5 FI-16 8
6 FI-18 9
7 FI-K7 4
8 FI-K12 5
9 FI-K16 8
10 FI-K18 9

View File

@@ -0,0 +1,6 @@
NO-A,1
NO-6,3
NO-9,4
NO-12,5
NO-15,8
NO-18,9
1 NO-A 1
2 NO-6 3
3 NO-9 4
4 NO-12 5
5 NO-15 8
6 NO-18 9

View File

@@ -0,0 +1,5 @@
SE-Btl,1
SE-Barntillåten,1
SE-7,3
SE-11,5
SE-15,8
1 SE-Btl 1
2 SE-Barntillåten 1
3 SE-7 3
4 SE-11 5
5 SE-15 8

View File

@@ -96,7 +96,7 @@ namespace Emby.Server.Implementations.Net
}
else
{
tcs.TrySetException(new Exception("SocketError: " + e.SocketError));
tcs.TrySetException(new SocketException((int)e.SocketError));
}
}
}
@@ -114,7 +114,7 @@ namespace Emby.Server.Implementations.Net
}
else
{
tcs.TrySetException(new Exception("SocketError: " + e.SocketError));
tcs.TrySetException(new SocketException((int)e.SocketError));
}
}
}

View File

@@ -1242,7 +1242,7 @@ namespace Emby.Server.Implementations.Session
if (item == null)
{
_logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id);
_logger.LogError("A non-existent item Id {0} was passed into TranslateItemForPlayback", id);
return Array.Empty<BaseItem>();
}

View File

@@ -6,7 +6,6 @@ using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Net;
@@ -37,7 +36,7 @@ namespace Emby.Server.Implementations.Session
private const float ForceKeepAliveFactor = 0.75f;
/// <summary>
/// Lock used for accesing the KeepAlive cancellation token.
/// Lock used for accessing the KeepAlive cancellation token.
/// </summary>
private readonly object _keepAliveLock = new object();

View File

@@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Session
{
public sealed class WebSocketController : ISessionController, IDisposable
public sealed class WebSocketController : ISessionController, IAsyncDisposable, IDisposable
{
private readonly ILogger<WebSocketController> _logger;
private readonly ISessionManager _sessionManager;
@@ -99,6 +99,23 @@ namespace Emby.Server.Implementations.Session
foreach (var socket in _sockets)
{
socket.Closed -= OnConnectionClosed;
socket.Dispose();
}
_disposed = true;
}
public async ValueTask DisposeAsync()
{
if (_disposed)
{
return;
}
foreach (var socket in _sockets)
{
socket.Closed -= OnConnectionClosed;
await socket.DisposeAsync().ConfigureAwait(false);
}
_disposed = true;

View File

@@ -3,7 +3,6 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Sorting;

View File

@@ -43,9 +43,9 @@ namespace Emby.Server.Implementations.TV
}
string presentationUniqueKey = null;
if (!string.IsNullOrEmpty(query.SeriesId))
if (query.SeriesId.HasValue && !query.SeriesId.Value.Equals(default))
{
if (_libraryManager.GetItemById(query.SeriesId) is Series series)
if (_libraryManager.GetItemById(query.SeriesId.Value) is Series series)
{
presentationUniqueKey = GetUniqueSeriesKey(series);
}
@@ -93,9 +93,9 @@ namespace Emby.Server.Implementations.TV
string presentationUniqueKey = null;
int? limit = null;
if (!string.IsNullOrEmpty(request.SeriesId))
if (request.SeriesId.HasValue && !request.SeriesId.Value.Equals(default))
{
if (_libraryManager.GetItemById(request.SeriesId) is Series series)
if (_libraryManager.GetItemById(request.SeriesId.Value) is Series series)
{
presentationUniqueKey = GetUniqueSeriesKey(series);
limit = 1;
@@ -135,25 +135,20 @@ namespace Emby.Server.Implementations.TV
return GetResult(episodes, request);
}
public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IReadOnlyList<string> seriesKeys, DtoOptions dtoOptions)
private IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IReadOnlyList<string> seriesKeys, DtoOptions dtoOptions)
{
// Avoid implicitly captured closure
var currentUser = user;
var allNextUp = seriesKeys
.Select(i => GetNextUp(i, currentUser, dtoOptions, false));
var allNextUp = seriesKeys.Select(i => GetNextUp(i, user, dtoOptions, false));
if (request.EnableRewatching)
{
allNextUp = allNextUp.Concat(
seriesKeys.Select(i => GetNextUp(i, currentUser, dtoOptions, true))
)
.OrderByDescending(i => i.Item1);
seriesKeys.Select(i => GetNextUp(i, user, dtoOptions, true)))
.OrderByDescending(i => i.LastWatchedDate);
}
// If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view)
var alwaysEnableFirstEpisode = !string.IsNullOrEmpty(request.SeriesId);
var alwaysEnableFirstEpisode = request.SeriesId.HasValue && !request.SeriesId.Value.Equals(default);
var anyFound = false;
return allNextUp
@@ -161,23 +156,18 @@ namespace Emby.Server.Implementations.TV
{
if (request.DisableFirstEpisode)
{
return i.Item1 != DateTime.MinValue;
return i.LastWatchedDate != DateTime.MinValue;
}
if (alwaysEnableFirstEpisode || (i.Item1 != DateTime.MinValue && i.Item1.Date >= request.NextUpDateCutoff))
if (alwaysEnableFirstEpisode || (i.LastWatchedDate != DateTime.MinValue && i.LastWatchedDate.Date >= request.NextUpDateCutoff))
{
anyFound = true;
return true;
}
if (!anyFound && i.Item1 == DateTime.MinValue)
{
return true;
}
return false;
return !anyFound && i.LastWatchedDate == DateTime.MinValue;
})
.Select(i => i.Item2())
.Select(i => i.GetEpisodeFunction())
.Where(i => i != null);
}
@@ -195,14 +185,14 @@ namespace Emby.Server.Implementations.TV
/// Gets the next up.
/// </summary>
/// <returns>Task{Episode}.</returns>
private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions, bool rewatching)
private (DateTime LastWatchedDate, Func<Episode> GetEpisodeFunction) GetNextUp(string seriesKey, User user, DtoOptions dtoOptions, bool rewatching)
{
var lastQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Descending) },
OrderBy = new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) },
IsPlayed = true,
Limit = 1,
ParentIndexNumberNotEquals = 0,
@@ -216,24 +206,23 @@ namespace Emby.Server.Implementations.TV
if (rewatching)
{
// find last watched by date played, not by newest episode watched
lastQuery.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) };
lastQuery.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) };
}
var lastWatchedEpisode = _libraryManager.GetItemList(lastQuery).Cast<Episode>().FirstOrDefault();
Func<Episode> getEpisode = () =>
Episode GetEpisode()
{
var nextQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
OrderBy = new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Ascending), (ItemSortBy.IndexNumber, SortOrder.Ascending) },
Limit = 1,
IsPlayed = rewatching,
IsVirtualItem = false,
ParentIndexNumberNotEquals = 0,
MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
};
@@ -297,7 +286,7 @@ namespace Emby.Server.Implementations.TV
}
return nextEpisode;
};
}
if (lastWatchedEpisode != null)
{
@@ -305,11 +294,11 @@ namespace Emby.Server.Implementations.TV
var lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue.AddDays(1);
return new Tuple<DateTime, Func<Episode>>(lastWatchedDate, getEpisode);
return (lastWatchedDate, GetEpisode);
}
// Return the first episode
return new Tuple<DateTime, Func<Episode>>(DateTime.MinValue, getEpisode);
return (DateTime.MinValue, GetEpisode);
}
private static QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, NextUpQuery query)