mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-02-24 13:32:26 +00:00
Merge branch 'master' into issue15137
This commit is contained in:
@@ -107,10 +107,20 @@ namespace Emby.Server.Implementations.AppBase
|
||||
|
||||
private void CheckOrCreateMarker(string path, string markerName, bool recursive = false)
|
||||
{
|
||||
var otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => Path.GetFileName(e) != markerName);
|
||||
string? otherMarkers = null;
|
||||
try
|
||||
{
|
||||
otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => !Path.GetFileName(e.AsSpan()).Equals(markerName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Error while checking for marker files, assume none exist and keep going
|
||||
// TODO: add some logging
|
||||
}
|
||||
|
||||
if (otherMarkers is not null)
|
||||
{
|
||||
throw new InvalidOperationException($"Exepected to find only {markerName} but found marker for {otherMarkers}.");
|
||||
throw new InvalidOperationException($"Expected to find only {markerName} but found marker for {otherMarkers}.");
|
||||
}
|
||||
|
||||
var markerPath = Path.Combine(path, markerName);
|
||||
|
||||
@@ -223,7 +223,7 @@ public class ChapterManager : IChapterManager
|
||||
|
||||
if (saveChapters && changesMade)
|
||||
{
|
||||
_chapterRepository.SaveChapters(video.Id, chapters);
|
||||
SaveChapters(video, chapters);
|
||||
}
|
||||
|
||||
DeleteDeadImages(currentImages, chapters);
|
||||
@@ -234,7 +234,9 @@ public class ChapterManager : IChapterManager
|
||||
/// <inheritdoc />
|
||||
public void SaveChapters(Video video, IReadOnlyList<ChapterInfo> chapters)
|
||||
{
|
||||
_chapterRepository.SaveChapters(video.Id, chapters);
|
||||
// Remove any chapters that are outside of the runtime of the video
|
||||
var validChapters = chapters.Where(c => c.StartPositionTicks < video.RunTimeTicks).ToList();
|
||||
_chapterRepository.SaveChapters(video.Id, validChapters);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -39,22 +39,24 @@ namespace Emby.Server.Implementations.Cryptography
|
||||
{
|
||||
if (string.Equals(hash.Id, "PBKDF2", StringComparison.Ordinal))
|
||||
{
|
||||
var iterations = GetIterationsParameter(hash);
|
||||
return hash.Hash.SequenceEqual(
|
||||
Rfc2898DeriveBytes.Pbkdf2(
|
||||
password,
|
||||
hash.Salt,
|
||||
int.Parse(hash.Parameters["iterations"], CultureInfo.InvariantCulture),
|
||||
iterations,
|
||||
HashAlgorithmName.SHA1,
|
||||
32));
|
||||
}
|
||||
|
||||
if (string.Equals(hash.Id, "PBKDF2-SHA512", StringComparison.Ordinal))
|
||||
{
|
||||
var iterations = GetIterationsParameter(hash);
|
||||
return hash.Hash.SequenceEqual(
|
||||
Rfc2898DeriveBytes.Pbkdf2(
|
||||
password,
|
||||
hash.Salt,
|
||||
int.Parse(hash.Parameters["iterations"], CultureInfo.InvariantCulture),
|
||||
iterations,
|
||||
HashAlgorithmName.SHA512,
|
||||
DefaultOutputLength));
|
||||
}
|
||||
@@ -62,6 +64,27 @@ namespace Emby.Server.Implementations.Cryptography
|
||||
throw new NotSupportedException($"Can't verify hash with id: {hash.Id}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts and validates the iterations parameter from a password hash.
|
||||
/// </summary>
|
||||
/// <param name="hash">The password hash containing parameters.</param>
|
||||
/// <returns>The number of iterations.</returns>
|
||||
/// <exception cref="FormatException">Thrown when iterations parameter is missing or invalid.</exception>
|
||||
private static int GetIterationsParameter(PasswordHash hash)
|
||||
{
|
||||
if (!hash.Parameters.TryGetValue("iterations", out var iterationsStr))
|
||||
{
|
||||
throw new FormatException($"Password hash with id '{hash.Id}' is missing required 'iterations' parameter.");
|
||||
}
|
||||
|
||||
if (!int.TryParse(iterationsStr, CultureInfo.InvariantCulture, out var iterations))
|
||||
{
|
||||
throw new FormatException($"Password hash with id '{hash.Id}' has invalid 'iterations' parameter: '{iterationsStr}'.");
|
||||
}
|
||||
|
||||
return iterations;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte[] GenerateSalt()
|
||||
=> GenerateSalt(DefaultSaltLength);
|
||||
|
||||
@@ -1051,16 +1051,16 @@ namespace Emby.Server.Implementations.Dto
|
||||
|
||||
// Include artists that are not in the database yet, e.g., just added via metadata editor
|
||||
// var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
|
||||
dto.ArtistItems = _libraryManager.GetArtists([.. hasArtist.Artists.Where(e => !string.IsNullOrWhiteSpace(e))])
|
||||
.Where(e => e.Value.Length > 0)
|
||||
.Select(i =>
|
||||
{
|
||||
return new NameGuidPair
|
||||
{
|
||||
Name = i.Key,
|
||||
Id = i.Value.First().Id
|
||||
};
|
||||
}).Where(i => i is not null).ToArray();
|
||||
var artistsLookup = _libraryManager.GetArtists([.. hasArtist.Artists.Where(e => !string.IsNullOrWhiteSpace(e))]);
|
||||
|
||||
dto.ArtistItems = hasArtist.Artists
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.Distinct()
|
||||
.Select(name => artistsLookup.TryGetValue(name, out var artists) && artists.Length > 0
|
||||
? new NameGuidPair { Name = name, Id = artists[0].Id }
|
||||
: null)
|
||||
.Where(item => item is not null)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (item is IHasAlbumArtist hasAlbumArtist)
|
||||
@@ -1085,31 +1085,16 @@ namespace Emby.Server.Implementations.Dto
|
||||
// })
|
||||
// .ToList();
|
||||
|
||||
var albumArtistsLookup = _libraryManager.GetArtists([.. hasAlbumArtist.AlbumArtists.Where(e => !string.IsNullOrWhiteSpace(e))]);
|
||||
|
||||
dto.AlbumArtists = hasAlbumArtist.AlbumArtists
|
||||
// .Except(foundArtists, new DistinctNameComparer())
|
||||
.Select(i =>
|
||||
{
|
||||
// This should not be necessary but we're seeing some cases of it
|
||||
if (string.IsNullOrEmpty(i))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
|
||||
{
|
||||
EnableImages = false
|
||||
});
|
||||
if (artist is not null)
|
||||
{
|
||||
return new NameGuidPair
|
||||
{
|
||||
Name = artist.Name,
|
||||
Id = artist.Id
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}).Where(i => i is not null).ToArray();
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.Distinct()
|
||||
.Select(name => albumArtistsLookup.TryGetValue(name, out var albumArtists) && albumArtists.Length > 0
|
||||
? new NameGuidPair { Name = name, Id = albumArtists[0].Id }
|
||||
: null)
|
||||
.Where(item => item is not null)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// Add video info
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
|
||||
<PackageReference Include="prometheus-net.DotNetRuntime" />
|
||||
@@ -39,7 +38,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -352,6 +352,12 @@ namespace Emby.Server.Implementations.IO
|
||||
return;
|
||||
}
|
||||
|
||||
var fileInfo = _fileSystem.GetFileSystemInfo(path);
|
||||
if (DotIgnoreIgnoreRule.IsIgnored(fileInfo, null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore certain files, If the parent of an ignored path has a change event, ignore that too
|
||||
foreach (var i in _tempIgnoredPaths.Keys)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Security;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -152,6 +153,10 @@ namespace Emby.Server.Implementations.IO
|
||||
/// <inheritdoc />
|
||||
public void MoveDirectory(string source, string destination)
|
||||
{
|
||||
// Make sure parent directory of target exists
|
||||
var parent = Directory.GetParent(destination);
|
||||
parent?.Create();
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Move(source, destination);
|
||||
@@ -248,47 +253,40 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
|
||||
|
||||
// if (!result.IsDirectory)
|
||||
// {
|
||||
// result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
|
||||
// }
|
||||
|
||||
if (info is FileInfo fileInfo)
|
||||
{
|
||||
result.Length = fileInfo.Length;
|
||||
|
||||
// Issue #2354 get the size of files behind symbolic links. Also Enum.HasFlag is bad as it boxes!
|
||||
if ((fileInfo.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
|
||||
result.CreationTimeUtc = GetCreationTimeUtc(info);
|
||||
result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
|
||||
if (fileInfo.LinkTarget is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fileHandle = File.OpenHandle(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
var targetFileInfo = FileSystemHelper.ResolveLinkTarget(fileInfo, returnFinalTarget: true);
|
||||
if (targetFileInfo is not null)
|
||||
{
|
||||
result.Length = RandomAccess.GetLength(fileHandle);
|
||||
result.Exists = targetFileInfo.Exists;
|
||||
if (result.Exists)
|
||||
{
|
||||
result.Length = targetFileInfo.Length;
|
||||
result.CreationTimeUtc = GetCreationTimeUtc(targetFileInfo);
|
||||
result.LastWriteTimeUtc = GetLastWriteTimeUtc(targetFileInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Exists = false;
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
// Dangling symlinks cannot be detected before opening the file unfortunately...
|
||||
_logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName);
|
||||
result.Exists = false;
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Reading the file at {Path} failed due to a permissions exception.", fileInfo.FullName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// IOException generally means the file is not accessible due to filesystem issues
|
||||
// Catch this exception and mark the file as not exist to ignore it
|
||||
_logger.LogError(ex, "Reading the file at {Path} failed due to an IO Exception. Marking the file as not existing", fileInfo.FullName);
|
||||
result.Exists = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Length = fileInfo.Length;
|
||||
}
|
||||
}
|
||||
|
||||
result.CreationTimeUtc = GetCreationTimeUtc(info);
|
||||
result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -499,8 +497,17 @@ namespace Emby.Server.Implementations.IO
|
||||
/// <inheritdoc />
|
||||
public virtual bool AreEqual(string path1, string path2)
|
||||
{
|
||||
return Path.TrimEndingDirectorySeparator(path1).Equals(
|
||||
Path.TrimEndingDirectorySeparator(path2),
|
||||
if (string.IsNullOrWhiteSpace(path1) || string.IsNullOrWhiteSpace(path2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var normalized1 = Path.TrimEndingDirectorySeparator(path1);
|
||||
var normalized2 = Path.TrimEndingDirectorySeparator(path2);
|
||||
|
||||
return string.Equals(
|
||||
normalized1,
|
||||
normalized2,
|
||||
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,22 +267,24 @@ namespace Emby.Server.Implementations.Images
|
||||
{
|
||||
var image = item.GetImageInfo(type, 0);
|
||||
|
||||
if (image is not null)
|
||||
if (image is null)
|
||||
{
|
||||
if (!image.IsLocalFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return GetItemsWithImages(item).Count is not 0;
|
||||
}
|
||||
|
||||
if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!image.IsLocalFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasChangedByDate(item, image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasChangedByDate(item, image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -98,5 +98,11 @@ namespace Emby.Server.Implementations.Images
|
||||
|
||||
return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex);
|
||||
}
|
||||
|
||||
protected override bool HasChangedByDate(BaseItem item, ItemImageInfo image)
|
||||
{
|
||||
var age = DateTime.UtcNow - image.DateModified;
|
||||
return age.TotalDays > 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
@@ -11,28 +13,24 @@ namespace Emby.Server.Implementations.Library;
|
||||
/// </summary>
|
||||
public class DotIgnoreIgnoreRule : IResolverIgnoreRule
|
||||
{
|
||||
private static readonly bool IsWindows = OperatingSystem.IsWindows();
|
||||
|
||||
private static FileInfo? FindIgnoreFile(DirectoryInfo directory)
|
||||
{
|
||||
var ignoreFile = new FileInfo(Path.Join(directory.FullName, ".ignore"));
|
||||
if (ignoreFile.Exists)
|
||||
for (var current = directory; current is not null; current = current.Parent)
|
||||
{
|
||||
return ignoreFile;
|
||||
var ignorePath = Path.Join(current.FullName, ".ignore");
|
||||
if (File.Exists(ignorePath))
|
||||
{
|
||||
return new FileInfo(ignorePath);
|
||||
}
|
||||
}
|
||||
|
||||
var parentDir = directory.Parent;
|
||||
if (parentDir is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return FindIgnoreFile(parentDir);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent)
|
||||
{
|
||||
return IsIgnored(fileInfo, parent);
|
||||
}
|
||||
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) => IsIgnored(fileInfo, parent);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the file is ignored.
|
||||
@@ -42,60 +40,101 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule
|
||||
/// <returns>True if the file should be ignored.</returns>
|
||||
public static bool IsIgnored(FileSystemMetadata fileInfo, BaseItem? parent)
|
||||
{
|
||||
if (fileInfo.IsDirectory)
|
||||
{
|
||||
var dirIgnoreFile = FindIgnoreFile(new DirectoryInfo(fileInfo.FullName));
|
||||
if (dirIgnoreFile is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var searchDirectory = fileInfo.IsDirectory
|
||||
? new DirectoryInfo(fileInfo.FullName)
|
||||
: new DirectoryInfo(Path.GetDirectoryName(fileInfo.FullName) ?? string.Empty);
|
||||
|
||||
// Fast path in case the ignore files isn't a symlink and is empty
|
||||
if ((dirIgnoreFile.Attributes & FileAttributes.ReparsePoint) == 0
|
||||
&& dirIgnoreFile.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ignore the directory only if the .ignore file is empty
|
||||
// evaluate individual files otherwise
|
||||
return string.IsNullOrWhiteSpace(GetFileContent(dirIgnoreFile));
|
||||
}
|
||||
|
||||
var parentDirPath = Path.GetDirectoryName(fileInfo.FullName);
|
||||
if (string.IsNullOrEmpty(parentDirPath))
|
||||
if (string.IsNullOrEmpty(searchDirectory.FullName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var folder = new DirectoryInfo(parentDirPath);
|
||||
var ignoreFile = FindIgnoreFile(folder);
|
||||
var ignoreFile = FindIgnoreFile(searchDirectory);
|
||||
if (ignoreFile is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string ignoreFileString = GetFileContent(ignoreFile);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ignoreFileString))
|
||||
// Fast path in case the ignore files isn't a symlink and is empty
|
||||
if (ignoreFile.LinkTarget is null && ignoreFile.Length == 0)
|
||||
{
|
||||
// Ignore directory if we just have the file
|
||||
return true;
|
||||
}
|
||||
|
||||
// If file has content, base ignoring off the content .gitignore-style rules
|
||||
var ignoreRules = ignoreFileString.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
var ignore = new Ignore.Ignore();
|
||||
ignore.Add(ignoreRules);
|
||||
|
||||
return ignore.IsIgnored(fileInfo.FullName);
|
||||
var content = GetFileContent(ignoreFile);
|
||||
return string.IsNullOrWhiteSpace(content)
|
||||
|| CheckIgnoreRules(fileInfo.FullName, content, fileInfo.IsDirectory);
|
||||
}
|
||||
|
||||
private static string GetFileContent(FileInfo dirIgnoreFile)
|
||||
private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
|
||||
{
|
||||
using (var reader = dirIgnoreFile.OpenText())
|
||||
// If file has content, base ignoring off the content .gitignore-style rules
|
||||
var rules = ignoreFileContent.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
return CheckIgnoreRules(path, rules, isDirectory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a path should be ignored based on an array of ignore rules.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check.</param>
|
||||
/// <param name="rules">The array of ignore rules.</param>
|
||||
/// <param name="isDirectory">Whether the path is a directory.</param>
|
||||
/// <returns>True if the path should be ignored.</returns>
|
||||
internal static bool CheckIgnoreRules(string path, string[] rules, bool isDirectory)
|
||||
=> CheckIgnoreRules(path, rules, isDirectory, IsWindows);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a path should be ignored based on an array of ignore rules.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check.</param>
|
||||
/// <param name="rules">The array of ignore rules.</param>
|
||||
/// <param name="isDirectory">Whether the path is a directory.</param>
|
||||
/// <param name="normalizePath">Whether to normalize backslashes to forward slashes (for Windows paths).</param>
|
||||
/// <returns>True if the path should be ignored.</returns>
|
||||
internal static bool CheckIgnoreRules(string path, string[] rules, bool isDirectory, bool normalizePath)
|
||||
{
|
||||
var ignore = new Ignore.Ignore();
|
||||
|
||||
// Add each rule individually to catch and skip invalid patterns
|
||||
var validRulesAdded = 0;
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
try
|
||||
{
|
||||
ignore.Add(rule);
|
||||
validRulesAdded++;
|
||||
}
|
||||
catch (RegexParseException)
|
||||
{
|
||||
// Ignore invalid patterns
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid rules were added, fall back to ignoring everything (like an empty .ignore file)
|
||||
if (validRulesAdded == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mitigate the problem of the Ignore library not handling Windows paths correctly.
|
||||
// See https://github.com/jellyfin/jellyfin/issues/15484
|
||||
var pathToCheck = normalizePath ? path.NormalizePath('/') : path;
|
||||
|
||||
// Add trailing slash for directories to match "folder/"
|
||||
if (isDirectory)
|
||||
{
|
||||
pathToCheck = string.Concat(pathToCheck.AsSpan().TrimEnd('/'), "/");
|
||||
}
|
||||
|
||||
return ignore.IsIgnored(pathToCheck);
|
||||
}
|
||||
|
||||
private static string GetFileContent(FileInfo ignoreFile)
|
||||
{
|
||||
ignoreFile = FileSystemHelper.ResolveLinkTarget(ignoreFile, returnFinalTarget: true) ?? ignoreFile;
|
||||
return ignoreFile.Exists
|
||||
? File.ReadAllText(ignoreFile.FullName)
|
||||
: string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ namespace Emby.Server.Implementations.Library
|
||||
"**/lost+found",
|
||||
"**/subs/**",
|
||||
"**/subs",
|
||||
"**/.snapshots/**",
|
||||
"**/.snapshots",
|
||||
"**/.snapshot/**",
|
||||
"**/.snapshot",
|
||||
|
||||
// Trickplay files
|
||||
"**/*.trickplay",
|
||||
|
||||
@@ -457,6 +457,12 @@ namespace Emby.Server.Implementations.Library
|
||||
_cache.TryRemove(child.Id, out _);
|
||||
}
|
||||
|
||||
if (parent is Folder folder)
|
||||
{
|
||||
folder.Children = null;
|
||||
folder.UserData = null;
|
||||
}
|
||||
|
||||
ReportItemRemoved(item, parent);
|
||||
}
|
||||
|
||||
@@ -1052,6 +1058,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
IncludeItemTypes = [BaseItemKind.MusicArtist],
|
||||
Name = name,
|
||||
UseRawName = true,
|
||||
DtoOptions = options
|
||||
}).Cast<MusicArtist>()
|
||||
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
|
||||
@@ -1993,6 +2000,12 @@ namespace Emby.Server.Implementations.Library
|
||||
RegisterItem(item);
|
||||
}
|
||||
|
||||
if (parent is Folder folder)
|
||||
{
|
||||
folder.Children = null;
|
||||
folder.UserData = null;
|
||||
}
|
||||
|
||||
if (ItemAdded is not null)
|
||||
{
|
||||
foreach (var item in items)
|
||||
@@ -2131,7 +2144,7 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
item.ValidateImages();
|
||||
|
||||
_itemRepository.SaveImages(item);
|
||||
await _itemRepository.SaveImagesAsync(item).ConfigureAwait(false);
|
||||
|
||||
RegisterItem(item);
|
||||
}
|
||||
@@ -2150,6 +2163,12 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
_itemRepository.SaveItems(items, cancellationToken);
|
||||
|
||||
if (parent is Folder folder)
|
||||
{
|
||||
folder.Children = null;
|
||||
folder.UserData = null;
|
||||
}
|
||||
|
||||
if (ItemUpdated is not null)
|
||||
{
|
||||
foreach (var item in items)
|
||||
@@ -2183,6 +2202,12 @@ namespace Emby.Server.Implementations.Library
|
||||
public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||
=> UpdateItemsAsync([item], parent, updateReason, cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ReattachUserDataAsync(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
await _itemRepository.ReattachUserDataAsync(item, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason)
|
||||
{
|
||||
if (item.IsFileProtocol)
|
||||
@@ -3176,19 +3201,7 @@ namespace Emby.Server.Implementations.Library
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
|
||||
|
||||
var shortcutFilename = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
|
||||
|
||||
while (File.Exists(lnk))
|
||||
{
|
||||
shortcutFilename += "1";
|
||||
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
|
||||
}
|
||||
|
||||
_fileSystem.CreateShortcut(lnk, _appHost.ReverseVirtualPath(path));
|
||||
|
||||
RemoveContentTypeOverrides(path);
|
||||
CreateShortcut(virtualFolderPath, pathInfo);
|
||||
|
||||
if (saveLibraryOptions)
|
||||
{
|
||||
@@ -3353,5 +3366,24 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
return item is UserRootFolder || item.IsVisibleStandalone(user);
|
||||
}
|
||||
|
||||
public void CreateShortcut(string virtualFolderPath, MediaPathInfo pathInfo)
|
||||
{
|
||||
var path = pathInfo.Path;
|
||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
|
||||
var shortcutFilename = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
|
||||
|
||||
while (File.Exists(lnk))
|
||||
{
|
||||
shortcutFilename += "1";
|
||||
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
|
||||
}
|
||||
|
||||
_fileSystem.CreateShortcut(lnk, _appHost.ReverseVirtualPath(path));
|
||||
RemoveContentTypeOverrides(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.Library
|
||||
/// <inheritdoc />>
|
||||
public MediaProtocol GetPathProtocol(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return MediaProtocol.File;
|
||||
}
|
||||
|
||||
if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return MediaProtocol.Rtsp;
|
||||
|
||||
@@ -28,7 +28,9 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
public IReadOnlyList<BaseItem> GetInstantMixFromSong(Audio item, User? user, DtoOptions dtoOptions)
|
||||
{
|
||||
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
||||
var instantMixItems = GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
||||
|
||||
return [item, .. instantMixItems.Where(i => !i.Id.Equals(item.Id))];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -37,15 +37,25 @@ namespace Emby.Server.Implementations.Library
|
||||
while (attributeIndex > -1 && attributeIndex < maxIndex)
|
||||
{
|
||||
var attributeEnd = attributeIndex + attribute.Length;
|
||||
if (attributeIndex > 0
|
||||
&& str[attributeIndex - 1] == '['
|
||||
&& (str[attributeEnd] == '=' || str[attributeEnd] == '-'))
|
||||
if (attributeIndex > 0)
|
||||
{
|
||||
var closingIndex = str[attributeEnd..].IndexOf(']');
|
||||
// Must be at least 1 character before the closing bracket.
|
||||
if (closingIndex > 1)
|
||||
var attributeOpener = str[attributeIndex - 1];
|
||||
var attributeCloser = attributeOpener switch
|
||||
{
|
||||
return str[(attributeEnd + 1)..(attributeEnd + closingIndex)].Trim().ToString();
|
||||
'[' => ']',
|
||||
'(' => ')',
|
||||
'{' => '}',
|
||||
_ => '\0'
|
||||
};
|
||||
if (attributeCloser != '\0' && (str[attributeEnd] == '=' || str[attributeEnd] == '-'))
|
||||
{
|
||||
var closingIndex = str[attributeEnd..].IndexOf(attributeCloser);
|
||||
|
||||
// Must be at least 1 character before the closing bracket.
|
||||
if (closingIndex > 1)
|
||||
{
|
||||
return str[(attributeEnd + 1)..(attributeEnd + closingIndex)].Trim().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Emby.Naming.Book;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||
{
|
||||
@@ -35,17 +35,22 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||
|
||||
var extension = Path.GetExtension(args.Path.AsSpan());
|
||||
|
||||
if (_validExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
|
||||
if (!_validExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// It's a book
|
||||
return new Book
|
||||
{
|
||||
Path = args.Path,
|
||||
IsInMixedFolder = true
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
var result = BookFileNameParser.Parse(Path.GetFileNameWithoutExtension(args.Path));
|
||||
|
||||
return new Book
|
||||
{
|
||||
Path = args.Path,
|
||||
Name = result.Name ?? string.Empty,
|
||||
IndexNumber = result.Index,
|
||||
ProductionYear = result.Year,
|
||||
SeriesName = result.SeriesName ?? Path.GetFileName(Path.GetDirectoryName(args.Path)),
|
||||
IsInMixedFolder = true,
|
||||
};
|
||||
}
|
||||
|
||||
private Book GetBook(ItemResolveArgs args)
|
||||
@@ -59,15 +64,22 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}).ToList();
|
||||
|
||||
// Don't return a Book if there is more (or less) than one document in the directory
|
||||
// directory is only considered a book when it contains exactly one supported file
|
||||
// other library structures with multiple books to a directory will get picked up as individual files
|
||||
if (bookFiles.Count != 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = BookFileNameParser.Parse(Path.GetFileName(args.Path));
|
||||
|
||||
return new Book
|
||||
{
|
||||
Path = bookFiles[0].FullName
|
||||
Path = bookFiles[0].FullName,
|
||||
Name = result.Name ?? string.Empty,
|
||||
IndexNumber = result.Index,
|
||||
ProductionYear = result.Year,
|
||||
SeriesName = result.SeriesName ?? string.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,13 +369,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||
// We need to only look at the name of this actual item (not parents)
|
||||
var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path.AsSpan()) : Path.GetFileName(item.ContainingFolderPath.AsSpan());
|
||||
|
||||
if (!justName.IsEmpty)
|
||||
var tmdbid = justName.GetAttributeValue("tmdbid");
|
||||
|
||||
// If not in a mixed folder and ID not found in folder path, check filename
|
||||
if (string.IsNullOrEmpty(tmdbid) && !item.IsInMixedFolder)
|
||||
{
|
||||
// Check for TMDb id
|
||||
var tmdbid = justName.GetAttributeValue("tmdbid");
|
||||
item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
|
||||
tmdbid = Path.GetFileName(item.Path.AsSpan()).GetAttributeValue("tmdbid");
|
||||
}
|
||||
|
||||
item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
|
||||
|
||||
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 (whether id in parent dir or in file name)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.Library
|
||||
results = results.GetRange(query.StartIndex.Value, totalRecordCount - query.StartIndex.Value);
|
||||
}
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
if (query.Limit.HasValue && query.Limit.Value > 0)
|
||||
{
|
||||
results = results.GetRange(0, Math.Min(query.Limit.Value, results.Count));
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
"Albums": "ألبومات",
|
||||
"AppDeviceValues": "تطبيق: {0}, جهاز: {1}",
|
||||
"Application": "تطبيق",
|
||||
"Artists": "الفنانون",
|
||||
"Artists": "فنانون",
|
||||
"AuthenticationSucceededWithUserName": "نجحت عملية التوثيق بـ {0}",
|
||||
"Books": "الكتب",
|
||||
"CameraImageUploadedFrom": "رُفعت صورة الكاميرا الجديدة من {0}",
|
||||
"Channels": "القنوات",
|
||||
"ChapterNameValue": "الفصل {0}",
|
||||
"Collections": "المجموعات",
|
||||
"Collections": "مجموعات",
|
||||
"DeviceOfflineWithName": "قُطِع الاتصال ب{0}",
|
||||
"DeviceOnlineWithName": "{0} متصل",
|
||||
"FailedLoginAttemptWithUserName": "محاولة تسجيل الدخول فاشلة من {0}",
|
||||
@@ -16,7 +16,7 @@
|
||||
"Folders": "المجلدات",
|
||||
"Genres": "التصنيفات",
|
||||
"HeaderAlbumArtists": "فناني الألبوم",
|
||||
"HeaderContinueWatching": "إستئناف المشاهدة",
|
||||
"HeaderContinueWatching": "متابعة المشاهدة",
|
||||
"HeaderFavoriteAlbums": "الألبومات المفضلة",
|
||||
"HeaderFavoriteArtists": "الفنانون المفضلون",
|
||||
"HeaderFavoriteEpisodes": "الحلقات المفضلة",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "العروض",
|
||||
"Songs": "الأغاني",
|
||||
"StartupEmbyServerIsLoading": "يتم تحميل خادم Jellyfin . الرجاء المحاولة بعد قليل.",
|
||||
"SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}",
|
||||
"SubtitleDownloadFailureFromForItem": "فشل تحميل الترجمات من {0} ل {1}",
|
||||
"Sync": "مزامنة",
|
||||
"System": "النظام",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Playlists": "Плэй-лісты",
|
||||
"Latest": "Апошняе",
|
||||
"LabelIpAddressValue": "IP-адрас: {0}",
|
||||
"ItemAddedWithName": "{0} даданы ў бібліятэку",
|
||||
"ItemAddedWithName": "{0} дададзены ў бібліятэку",
|
||||
"MessageApplicationUpdated": "Сервер Jellyfin абноўлены",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Абнаўленне праграмы ўсталявана",
|
||||
"PluginInstalledWithName": "{0} быў усталяваны",
|
||||
@@ -14,9 +14,9 @@
|
||||
"Channels": "Каналы",
|
||||
"ChapterNameValue": "Раздзел {0}",
|
||||
"Collections": "Калекцыі",
|
||||
"Default": "Па змаўчанні",
|
||||
"Default": "Прадвызначана",
|
||||
"FailedLoginAttemptWithUserName": "Няўдалая спроба ўваходу з {0}",
|
||||
"Folders": "Тэчкі",
|
||||
"Folders": "Папкі",
|
||||
"Favorites": "Абранае",
|
||||
"External": "Знешні",
|
||||
"Genres": "Жанры",
|
||||
@@ -50,7 +50,7 @@
|
||||
"User": "Карыстальнік",
|
||||
"UserDeletedWithName": "Карыстальнік {0} быў выдалены",
|
||||
"UserDownloadingItemWithValues": "{0} спампоўваецца {1}",
|
||||
"TaskOptimizeDatabase": "Аптымізаваць базу дадзеных",
|
||||
"TaskOptimizeDatabase": "Аптымізацыя базы даных",
|
||||
"Artists": "Выканаўцы",
|
||||
"UserOfflineFromDevice": "{0} адлучыўся ад {1}",
|
||||
"UserPolicyUpdatedWithName": "Палітыка карыстальніка абноўлена для {0}",
|
||||
@@ -59,8 +59,8 @@
|
||||
"TaskCleanLogsDescription": "Выдаляе файлы журналу, якім больш за {0} дзён.",
|
||||
"TaskUpdatePluginsDescription": "Спампоўвае і ўсталёўвае абнаўленні для плагінаў, якія сканфігураваныя на аўтаматычнае абнаўленне.",
|
||||
"TaskRefreshChannelsDescription": "Абнаўляе інфармацыю аб інтэрнэт-канале.",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Шукае ў інтэрнэце адсутныя субцітры на аснове канфігурацыі метададзеных.",
|
||||
"TaskOptimizeDatabaseDescription": "Ушчыльняе базу дадзеных і скарачае вольную прастору. Выкананне гэтай задачы пасля сканавання бібліятэкі або ўнясення іншых зменаў, якія прадугледжваюць мадыфікацыю базы дадзеных, можа палепшыць выдайнасць.",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Шукае ў інтэрнэце адсутныя субцітры на аснове канфігурацыі метаданых.",
|
||||
"TaskOptimizeDatabaseDescription": "Сціскае базу даных і вызваляе вольную прастору. Выкананне гэтай задачы пасля сканіравання бібліятэкі або іншых змяненняў, якія мадыфікуюць базу даных, можа палепшыць прадукцыйнасць.",
|
||||
"TaskKeyframeExtractor": "Экстрактар ключавых кадраў",
|
||||
"TasksApplicationCategory": "Праграма",
|
||||
"AppDeviceValues": "Праграма: {0}, Прылада: {1}",
|
||||
@@ -81,8 +81,8 @@
|
||||
"NotificationOptionInstallationFailed": "Збой усталёўкі",
|
||||
"NewVersionIsAvailable": "Новая версія сервера Jellyfin даступная для cпампоўкі.",
|
||||
"NotificationOptionCameraImageUploaded": "Выява камеры запампавана",
|
||||
"NotificationOptionAudioPlaybackStopped": "Прайграванне аўдыё спынена",
|
||||
"NotificationOptionAudioPlayback": "Прайграванне аўдыё пачалося",
|
||||
"NotificationOptionAudioPlaybackStopped": "Прайграванне аўдыя спынена",
|
||||
"NotificationOptionAudioPlayback": "Прайграванне аўдыя пачалося",
|
||||
"NotificationOptionNewLibraryContent": "Дададзены новы кантэнт",
|
||||
"NotificationOptionPluginError": "Збой плагіна",
|
||||
"NotificationOptionPluginUninstalled": "Плагін выдалены",
|
||||
@@ -95,7 +95,7 @@
|
||||
"ServerNameNeedsToBeRestarted": "{0} патрабуе перазапуску",
|
||||
"Shows": "Шоу",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server загружаецца. Калі ласка, паўтарыце спробу крыху пазней.",
|
||||
"SubtitleDownloadFailureFromForItem": "Не атрымалася спампаваць субтытры з {0} для {1}",
|
||||
"SubtitleDownloadFailureFromForItem": "Субцітры для {1} не ўдалося спампаваць з {0}",
|
||||
"TvShows": "Тэлепраграма",
|
||||
"Undefined": "Нявызначана",
|
||||
"UserLockedOutWithName": "Карыстальнік {0} быў заблакіраваны",
|
||||
@@ -104,7 +104,7 @@
|
||||
"UserStartedPlayingItemWithValues": "{0} прайграваецца {1} на {2}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} скончыў прайграванне {1} на {2}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} быў дададзены ў вашу медыятэку",
|
||||
"ValueSpecialEpisodeName": "Спецэпізод - {0}",
|
||||
"ValueSpecialEpisodeName": "Спецвыпуск - {0}",
|
||||
"VersionNumber": "Версія {0}",
|
||||
"TasksMaintenanceCategory": "Абслугоўванне",
|
||||
"TasksLibraryCategory": "Бібліятэка",
|
||||
@@ -114,7 +114,7 @@
|
||||
"TaskCleanCacheDescription": "Выдаляе файлы кэша, якія больш не патрэбныя сістэме.",
|
||||
"TaskRefreshChapterImages": "Вынуць выявы раздзелаў",
|
||||
"TaskRefreshLibrary": "Сканаваць бібліятэку",
|
||||
"TaskRefreshLibraryDescription": "Скануе вашу медыятэку на наяўнасць новых файлаў і абнаўляе метададзеныя.",
|
||||
"TaskRefreshLibraryDescription": "Сканіруе вашу медыятэку на наяўнасць новых файлаў і абнаўляе метаданыя.",
|
||||
"TaskCleanLogs": "Ачысціць журнал",
|
||||
"TaskRefreshPeople": "Абнавіць выканаўцаў",
|
||||
"TaskRefreshPeopleDescription": "Абнаўленне метаданых для акцёраў і рэжысёраў у вашай медыятэцы.",
|
||||
@@ -136,6 +136,6 @@
|
||||
"TaskDownloadMissingLyricsDescription": "Спампоўвае тэксты для песняў",
|
||||
"TaskExtractMediaSegments": "Сканіраванне медыя-сегмента",
|
||||
"TaskMoveTrickplayImages": "Перанесці месцазнаходжанне выявы Trickplay",
|
||||
"CleanupUserDataTask": "Задача па ачыстцы дадзеных карыстальніка",
|
||||
"CleanupUserDataTaskDescription": "Ачысьціць усе дадзеныя карыстальніка (стан прагляду, абранае і г.д.) для медыяфайлаў, што адсутнічаюць больш за 90 дзён."
|
||||
"CleanupUserDataTask": "Задача па ачыстцы даных карыстальніка",
|
||||
"CleanupUserDataTaskDescription": "Ачышчае ўсе даныя карыстальніка (стан прагляду, абранае і г.д.) для медыяфайлаў, што адсутнічаюць больш за 90 дзён."
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Сериали",
|
||||
"Songs": "Песни",
|
||||
"StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
|
||||
"SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Субтитрите за {1} от {0} не можаха да бъдат изтеглени",
|
||||
"Sync": "Синхронизиране",
|
||||
"System": "Система",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Sèries",
|
||||
"Songs": "Cançons",
|
||||
"StartupEmbyServerIsLoading": "El servidor de Jellyfin s'està carregant. Proveu-ho 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": "Sincronitza",
|
||||
"System": "Sistema",
|
||||
@@ -105,7 +104,7 @@
|
||||
"TaskCleanLogsDescription": "Esborra els registres que tinguin més de {0} dies.",
|
||||
"TaskCleanLogs": "Neteja dels registres",
|
||||
"TaskRefreshLibraryDescription": "Escaneja les mediateques, a la cerca de fitxers nous i refresca les metadades.",
|
||||
"TaskRefreshLibrary": "Escaneig de les mediateques",
|
||||
"TaskRefreshLibrary": "Escaneja la mediateca",
|
||||
"TaskRefreshChapterImagesDescription": "Creació de les miniatures dels vídeos que tinguin capítols.",
|
||||
"TaskRefreshChapterImages": "Extracció de les imatges dels capítols",
|
||||
"TaskCleanCacheDescription": "Eliminació de la memòria cau no necessària per al servidor.",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Seriály",
|
||||
"Songs": "Skladby",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server je spouštěn. Zkuste to prosím v brzké době znovu.",
|
||||
"SubtitleDownloadFailureForItem": "Stahování titulků selhalo pro {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
|
||||
"Sync": "Synchronizace",
|
||||
"System": "Systém",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"CameraImageUploadedFrom": "Mae delwedd camera newydd wedi'i lanlwytho o {0}",
|
||||
"Books": "Llyfrau",
|
||||
"AuthenticationSucceededWithUserName": "{0} wedi’i ddilysu’n llwyddiannus",
|
||||
"Artists": "Artistiaid",
|
||||
"Artists": "Crewyr",
|
||||
"AppDeviceValues": "Ap: {0}, Dyfais: {1}",
|
||||
"Albums": "Albwmau",
|
||||
"Genres": "Genres",
|
||||
@@ -67,7 +67,7 @@
|
||||
"NotificationOptionAudioPlayback": "Dechreuwyd chwarae sain",
|
||||
"MessageServerConfigurationUpdated": "Mae gosodiadau gweinydd wedi'i ddiweddaru",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Mae adran gosodiadau gweinydd {0} wedi'i diweddaru",
|
||||
"FailedLoginAttemptWithUserName": "Cais mewngofnodi wedi methu gan {0}",
|
||||
"FailedLoginAttemptWithUserName": "Cais mewngofnodi wedi methu o {0}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} wedi'i hychwanegu at eich llyfrgell gyfryngau",
|
||||
"UserStoppedPlayingItemWithValues": "{0} wedi gorffen chwarae {1} ar {2}",
|
||||
"UserStartedPlayingItemWithValues": "{0} yn chwarae {1} ar {2}",
|
||||
@@ -123,5 +123,14 @@
|
||||
"TaskRefreshChapterImages": "Echdynnu Lluniau Pennod",
|
||||
"TaskCleanCacheDescription": "Dileu ffeiliau cache nad oes eu hangen ar y system mwyach.",
|
||||
"TaskCleanCache": "Gwaghau Ffolder Cache",
|
||||
"HearingImpaired": "Nam ar y clyw"
|
||||
"HearingImpaired": "Nam ar y clyw",
|
||||
"TaskAudioNormalization": "Gwastatau Sain",
|
||||
"TaskAudioNormalizationDescription": "Yn sganio ffeiliau am ddata gwastatau sain.",
|
||||
"TaskRefreshTrickplayImages": "Creuwch lluniau Trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Creu rhagolygon Trickplay ar gyfer fideos mewn llyfrgelloedd gweithredol.",
|
||||
"TaskDownloadMissingLyrics": "Lawrlwytho geiriau coll",
|
||||
"TaskDownloadMissingLyricsDescription": "Lawrlwytho geiriau caneuon",
|
||||
"TaskCleanCollectionsAndPlaylists": "Glanhau casgliadau a rhestrau chwarae",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Dileu eitemau o gasgliadau a rhestrau chwarae sydd ddim yn bodoli bellach.",
|
||||
"TaskExtractMediaSegments": "Sganio Darnau Cyfryngau"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serier",
|
||||
"Songs": "Sange",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin er i gang med at starte. Prøv igen om et øjeblik.",
|
||||
"SubtitleDownloadFailureForItem": "Fejlet i download af undertekster for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Undertekster kunne ikke hentes fra {0} til {1}",
|
||||
"Sync": "Synkroniser",
|
||||
"System": "System",
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"Channels": "Kanäle",
|
||||
"ChapterNameValue": "Kapitel {0}",
|
||||
"Collections": "Sammlungen",
|
||||
"DeviceOfflineWithName": "{0} hat die Verbindung getrennt",
|
||||
"DeviceOnlineWithName": "{0} ist verbunden",
|
||||
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
|
||||
"DeviceOfflineWithName": "{0} ist offline",
|
||||
"DeviceOnlineWithName": "{0} ist online",
|
||||
"FailedLoginAttemptWithUserName": "Anmeldung von {0} fehlgeschlagen",
|
||||
"Favorites": "Favoriten",
|
||||
"Folders": "Verzeichnisse",
|
||||
"Genres": "Genres",
|
||||
@@ -21,7 +21,7 @@
|
||||
"HeaderFavoriteArtists": "Lieblingsinterpreten",
|
||||
"HeaderFavoriteEpisodes": "Lieblingsepisoden",
|
||||
"HeaderFavoriteShows": "Lieblingsserien",
|
||||
"HeaderFavoriteSongs": "Lieblingslieder",
|
||||
"HeaderFavoriteSongs": "Lieblingssongs",
|
||||
"HeaderLiveTV": "Live TV",
|
||||
"HeaderNextUp": "Als Nächstes",
|
||||
"HeaderRecordingGroups": "Aufnahme-Gruppen",
|
||||
@@ -46,7 +46,7 @@
|
||||
"NewVersionIsAvailable": "Eine neue Jellyfin-Serverversion steht zum Download bereit.",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Anwendungsaktualisierung verfügbar",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Anwendungsaktualisierung installiert",
|
||||
"NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
|
||||
"NotificationOptionAudioPlayback": "Audio wird abgespielt",
|
||||
"NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
|
||||
"NotificationOptionCameraImageUploaded": "Foto hochgeladen",
|
||||
"NotificationOptionInstallationFailed": "Installation fehlgeschlagen",
|
||||
@@ -57,8 +57,8 @@
|
||||
"NotificationOptionPluginUpdateInstalled": "Pluginaktualisierung installiert",
|
||||
"NotificationOptionServerRestartRequired": "Serverneustart notwendig",
|
||||
"NotificationOptionTaskFailed": "Geplante Aufgabe fehlgeschlagen",
|
||||
"NotificationOptionUserLockedOut": "Benutzer ausgeschlossen",
|
||||
"NotificationOptionVideoPlayback": "Videowiedergabe gestartet",
|
||||
"NotificationOptionUserLockedOut": "Benutzer gesperrt",
|
||||
"NotificationOptionVideoPlayback": "Video wird abgespielt",
|
||||
"NotificationOptionVideoPlaybackStopped": "Videowiedergabe gestoppt",
|
||||
"Photos": "Fotos",
|
||||
"Playlists": "Wiedergabelisten",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serien",
|
||||
"Songs": "Lieder",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin-Server lädt. Bitte versuche es gleich noch einmal.",
|
||||
"SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
|
||||
"Sync": "Synchronisation",
|
||||
"System": "System",
|
||||
@@ -82,7 +81,7 @@
|
||||
"UserCreatedWithName": "Benutzer {0} wurde erstellt",
|
||||
"UserDeletedWithName": "Benutzer {0} wurde gelöscht",
|
||||
"UserDownloadingItemWithValues": "{0} lädt {1} herunter",
|
||||
"UserLockedOutWithName": "Benutzer {0} wurde ausgeschlossen",
|
||||
"UserLockedOutWithName": "Benutzer {0} wurde gesperrt",
|
||||
"UserOfflineFromDevice": "{0} wurde getrennt von {1}",
|
||||
"UserOnlineFromDevice": "{0} ist online von {1}",
|
||||
"UserPasswordChangedWithName": "Das Passwort für Benutzer {0} wurde geändert",
|
||||
@@ -97,25 +96,25 @@
|
||||
"TaskRefreshChannelsDescription": "Aktualisiert Internet-Kanal-Informationen.",
|
||||
"TaskRefreshChannels": "Kanäle aktualisieren",
|
||||
"TaskCleanTranscodeDescription": "Löscht Transkodierungsdateien, die älter als einen Tag sind.",
|
||||
"TaskCleanTranscode": "Transkodierungs-Verzeichnis aufräumen",
|
||||
"TaskCleanTranscode": "Transkodierungsverzeichnis leeren",
|
||||
"TaskUpdatePluginsDescription": "Lädt Updates für Plugins herunter, welche für automatische Updates konfiguriert sind und installiert diese.",
|
||||
"TaskUpdatePlugins": "Plugins aktualisieren",
|
||||
"TaskRefreshPeopleDescription": "Aktualisiert Metadaten für Schauspieler und Regisseure in deinen Bibliotheken.",
|
||||
"TaskRefreshPeople": "Personen aktualisieren",
|
||||
"TaskCleanLogsDescription": "Lösche Log-Dateien, die älter als {0} Tage sind.",
|
||||
"TaskCleanLogs": "Log-Verzeichnis aufräumen",
|
||||
"TaskRefreshLibraryDescription": "Durchsucht alle Bibliotheken nach neu hinzugefügten Dateien und aktualisiert Metadaten.",
|
||||
"TaskCleanLogs": "Protokollverzeichnis leeren",
|
||||
"TaskRefreshLibraryDescription": "Durchsucht deine Medienbibliothek nach neuen Dateien und aktualisiert Metadaten.",
|
||||
"TaskRefreshLibrary": "Medien-Bibliothek scannen",
|
||||
"TaskRefreshChapterImagesDescription": "Erstellt Vorschaubilder für Videos, die Kapitel besitzen.",
|
||||
"TaskRefreshChapterImages": "Kapitel-Bilder extrahieren",
|
||||
"TaskCleanCacheDescription": "Löscht vom System nicht mehr benötigte Zwischenspeicherdateien.",
|
||||
"TaskCleanCache": "Zwischenspeicher-Verzeichnis aufräumen",
|
||||
"TaskRefreshChapterImagesDescription": "Erstellt Vorschaubilder für Videokapitel.",
|
||||
"TaskRefreshChapterImages": "Kapitelvorschauen erstellen",
|
||||
"TaskCleanCacheDescription": "Löscht Cache-Dateien, die vom System nicht mehr benötigt werden.",
|
||||
"TaskCleanCache": "Cache-Verzeichnis leeren",
|
||||
"TasksChannelsCategory": "Internet-Kanäle",
|
||||
"TasksApplicationCategory": "Anwendung",
|
||||
"TasksLibraryCategory": "Bibliothek",
|
||||
"TasksMaintenanceCategory": "Wartung",
|
||||
"TaskCleanActivityLogDescription": "Löscht Aktivitätsprotokolleinträge, die älter als das konfigurierte Alter sind.",
|
||||
"TaskCleanActivityLog": "Aktivitätsprotokolle aufräumen",
|
||||
"TaskCleanActivityLog": "Aktivitätsverlauf bereinigen",
|
||||
"Undefined": "Undefiniert",
|
||||
"Forced": "Erzwungen",
|
||||
"Default": "Standard",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Σειρές",
|
||||
"Songs": "Τραγούδια",
|
||||
"StartupEmbyServerIsLoading": "Ο διακομιστής Jellyfin φορτώνει. Περιμένετε λίγο και δοκιμάστε ξανά.",
|
||||
"SubtitleDownloadFailureForItem": "Οι υπότιτλοι απέτυχαν να κατέβουν για {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Αποτυχίες μεταφόρτωσης υποτίτλων από {0} για {1}",
|
||||
"Sync": "Συγχρονισμός",
|
||||
"System": "Σύστημα",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Shows",
|
||||
"Songs": "Songs",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
|
||||
"Sync": "Sync",
|
||||
"System": "System",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"HeaderFavoriteAlbums": "Álbumes favoritos",
|
||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||
"HeaderFavoriteEpisodes": "Capítulos favoritos",
|
||||
"HeaderFavoriteShows": "Programas favoritos",
|
||||
"HeaderFavoriteShows": "Series favoritas",
|
||||
"HeaderFavoriteSongs": "Canciones favoritas",
|
||||
"HeaderLiveTV": "TV en vivo",
|
||||
"HeaderNextUp": "Siguiente",
|
||||
@@ -70,10 +70,9 @@
|
||||
"ScheduledTaskFailedWithName": "{0} falló",
|
||||
"ScheduledTaskStartedWithName": "{0} iniciado",
|
||||
"ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
|
||||
"Shows": "Programas",
|
||||
"Shows": "Series",
|
||||
"Songs": "Canciones",
|
||||
"StartupEmbyServerIsLoading": "El servidor Jellyfin se está cargando. Vuelve a intentarlo en breve.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtitulos desde {0} para {1}",
|
||||
"Sync": "Sincronizar",
|
||||
"System": "Sistema",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Programas",
|
||||
"Songs": "Canciones",
|
||||
"StartupEmbyServerIsLoading": "El servidor Jellyfin está cargando. Por favor, intente de nuevo pronto.",
|
||||
"SubtitleDownloadFailureForItem": "Falló la descarga de subtítulos para {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Falló la descarga de subtítulos desde {0} para {1}",
|
||||
"Sync": "Sincronizar",
|
||||
"System": "Sistema",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Series",
|
||||
"Songs": "Canciones",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
|
||||
"SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Fallo en la descarga de subtítulos desde {0} para {1}",
|
||||
"Sync": "Sincronizar",
|
||||
"System": "Sistema",
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"NotificationOptionApplicationUpdateAvailable": "Rakenduse uuendus on saadaval",
|
||||
"NewVersionIsAvailable": "Jellyfin serveri uus versioon on allalaadimiseks saadaval.",
|
||||
"NameSeasonUnknown": "Tundmatu hooaeg",
|
||||
"NameSeasonNumber": "Hooaeg {0}",
|
||||
"NameSeasonNumber": "{0}. hooaeg",
|
||||
"NameInstallFailed": "{0} paigaldamine nurjus",
|
||||
"MusicVideos": "Muusikavideod",
|
||||
"Music": "Muusika",
|
||||
@@ -137,5 +137,5 @@
|
||||
"TaskExtractMediaSegmentsDescription": "Eraldab või võtab meediasegmendid MediaSegment'i lubavatest pluginatest.",
|
||||
"TaskMoveTrickplayImages": "Muuda trickplay piltide asukoht",
|
||||
"CleanupUserDataTask": "Puhasta kasutajaandmed",
|
||||
"CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mis pole enam vähemalt 90 päeva saadaval olnud."
|
||||
"CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mida pole enam vähemalt 90 päeva saadaval olnud."
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "سریالها",
|
||||
"Songs": "موسیقیها",
|
||||
"StartupEmbyServerIsLoading": "سرور Jellyfin در حال بارگیری است. لطفا کمی بعد دوباره تلاش کنید.",
|
||||
"SubtitleDownloadFailureForItem": "دانلود زیرنویس برای {0} ناموفق بود",
|
||||
"SubtitleDownloadFailureFromForItem": "بارگیری زیرنویس برای {1} از {0} شکست خورد",
|
||||
"Sync": "همگامسازی",
|
||||
"System": "سیستم",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Séries",
|
||||
"Songs": "Chansons",
|
||||
"StartupEmbyServerIsLoading": "Serveur Jellyfin en cours de chargement. Réessayez dans quelques instants.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
|
||||
"Sync": "Synchroniser",
|
||||
"System": "Système",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Séries",
|
||||
"Songs": "Chansons",
|
||||
"StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
|
||||
"SubtitleDownloadFailureForItem": "Le téléchargement des sous-titres pour {0} a échoué.",
|
||||
"SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
|
||||
"Sync": "Synchroniser",
|
||||
"System": "Système",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"Collections": "Sammlungen",
|
||||
"DeviceOfflineWithName": "{0} wurde getrennt",
|
||||
"DeviceOnlineWithName": "{0} ist verbunden",
|
||||
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
|
||||
"FailedLoginAttemptWithUserName": "Fählgschlagene Ameldeversuech vo {0}",
|
||||
"Favorites": "Favorite",
|
||||
"Folders": "Ordner",
|
||||
"Genres": "Genre",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serie",
|
||||
"Songs": "Lieder",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server ladt. Bitte grad noeinisch probiere.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Ondertetle vo {0} för {1} hend ned chönne abeglade wärde",
|
||||
"Sync": "Synchronisation",
|
||||
"System": "System",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "סדרות",
|
||||
"Songs": "שירים",
|
||||
"StartupEmbyServerIsLoading": "שרת Jellyfin בתהליך טעינה. נא לנסות שוב בקרוב.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "הורדת כתוביות מ־{0} עבור {1} נכשלה",
|
||||
"Sync": "סנכרון",
|
||||
"System": "מערכת",
|
||||
|
||||
@@ -129,5 +129,12 @@
|
||||
"TaskAudioNormalization": "श्रव्य सामान्यीकरण",
|
||||
"TaskAudioNormalizationDescription": "श्रव्य सामान्यीकरण के लिए फाइलें अन्वेषण करें",
|
||||
"TaskDownloadMissingLyrics": "लापता गानों के बोल डाउनलोड करेँ",
|
||||
"TaskDownloadMissingLyricsDescription": "गानों के बोल डाउनलोड करता है"
|
||||
"TaskDownloadMissingLyricsDescription": "गानों के बोल डाउनलोड करता है",
|
||||
"TaskExtractMediaSegments": "मीडिया सेगमेंट स्कैन",
|
||||
"TaskExtractMediaSegmentsDescription": "मीडियासेगमेंट सक्षम प्लगइन्स से मीडिया सेगमेंट निकालता है या प्राप्त करता है।",
|
||||
"TaskMoveTrickplayImages": "ट्रिकप्ले छवि स्थान माइग्रेट करें",
|
||||
"TaskMoveTrickplayImagesDescription": "लाइब्रेरी सेटिंग्स के अनुसार मौजूदा ट्रिकप्ले फ़ाइलों को स्थानांतरित करता है।",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "संग्रहों और प्लेलिस्टों से उन आइटमों को हटाता है जो अब मौजूद नहीं हैं।",
|
||||
"TaskCleanCollectionsAndPlaylists": "संग्रह और प्लेलिस्ट साफ़ करें",
|
||||
"CleanupUserDataTask": "यूज़र डेटा की सफाई करता है।"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"CameraImageUploadedFrom": "Nova fotografija sa kamere je učitana iz {0}",
|
||||
"Channels": "Kanali",
|
||||
"ChapterNameValue": "Poglavlje {0}",
|
||||
"Collections": "Kolekcije",
|
||||
"Collections": "Zbirke",
|
||||
"DeviceOfflineWithName": "{0} je prekinuo vezu",
|
||||
"DeviceOnlineWithName": "{0} je povezan",
|
||||
"FailedLoginAttemptWithUserName": "Neuspješan pokušaj prijave od {0}",
|
||||
@@ -70,10 +70,9 @@
|
||||
"ScheduledTaskFailedWithName": "{0} neuspjelo",
|
||||
"ScheduledTaskStartedWithName": "{0} pokrenuto",
|
||||
"ServerNameNeedsToBeRestarted": "{0} treba ponovno pokrenuti",
|
||||
"Shows": "Serije",
|
||||
"Shows": "Emisije",
|
||||
"Songs": "Pjesme",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin server se učitava. Pokušajte ponovo uskoro.",
|
||||
"SubtitleDownloadFailureForItem": "Titlovi prijevoda nisu preuzeti za {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Prijevod nije uspješno preuzet od {0} za {1}",
|
||||
"Sync": "Sinkronizacija",
|
||||
"System": "Sustav",
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"NotificationOptionPluginInstalled": "Bővítmény telepítve",
|
||||
"NotificationOptionPluginUninstalled": "Bővítmény eltávolítva",
|
||||
"NotificationOptionPluginUpdateInstalled": "Bővítményfrissítés telepítve",
|
||||
"NotificationOptionServerRestartRequired": "A kiszolgáló újraindítása szükséges",
|
||||
"NotificationOptionServerRestartRequired": "A szerver újraindítása szükséges",
|
||||
"NotificationOptionTaskFailed": "Hiba az ütemezett feladatban",
|
||||
"NotificationOptionUserLockedOut": "Felhasználó tiltva",
|
||||
"NotificationOptionVideoPlayback": "Videólejátszás elkezdve",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Sorozatok",
|
||||
"Songs": "Számok",
|
||||
"StartupEmbyServerIsLoading": "A Jellyfin kiszolgáló betöltődik. Próbálja újra hamarosan.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0}, ehhez: {1}",
|
||||
"Sync": "Szinkronizálás",
|
||||
"System": "Rendszer",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"AppDeviceValues": "App: {0}, Dispositivo: {1}",
|
||||
"Application": "Applicazione",
|
||||
"Artists": "Artisti",
|
||||
"AuthenticationSucceededWithUserName": "{0} autenticato con successo",
|
||||
"AuthenticationSucceededWithUserName": "{0} autenticato correttamente",
|
||||
"Books": "Libri",
|
||||
"CameraImageUploadedFrom": "È stata caricata una nuova fotografia da {0}",
|
||||
"Channels": "Canali",
|
||||
@@ -11,36 +11,36 @@
|
||||
"Collections": "Collezioni",
|
||||
"DeviceOfflineWithName": "{0} si è disconnesso",
|
||||
"DeviceOnlineWithName": "{0} è connesso",
|
||||
"FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da {0}",
|
||||
"FailedLoginAttemptWithUserName": "Tentativo di accesso non riuscito da {0}",
|
||||
"Favorites": "Preferiti",
|
||||
"Folders": "Cartelle",
|
||||
"Genres": "Generi",
|
||||
"HeaderAlbumArtists": "Artisti dell'album",
|
||||
"HeaderContinueWatching": "Continua a guardare",
|
||||
"HeaderFavoriteAlbums": "Album Preferiti",
|
||||
"HeaderFavoriteArtists": "Artisti Preferiti",
|
||||
"HeaderFavoriteEpisodes": "Episodi Preferiti",
|
||||
"HeaderFavoriteShows": "Serie TV Preferite",
|
||||
"HeaderFavoriteSongs": "Brani Preferiti",
|
||||
"HeaderFavoriteAlbums": "Album preferiti",
|
||||
"HeaderFavoriteArtists": "Artisti preferiti",
|
||||
"HeaderFavoriteEpisodes": "Episodi preferiti",
|
||||
"HeaderFavoriteShows": "Serie TV preferite",
|
||||
"HeaderFavoriteSongs": "Brani preferiti",
|
||||
"HeaderLiveTV": "Diretta TV",
|
||||
"HeaderNextUp": "Prossimo",
|
||||
"HeaderRecordingGroups": "Gruppi di Registrazione",
|
||||
"HomeVideos": "Video Personali",
|
||||
"HeaderRecordingGroups": "Gruppi di registrazione",
|
||||
"HomeVideos": "Video personali",
|
||||
"Inherit": "Eredita",
|
||||
"ItemAddedWithName": "{0} è stato aggiunto alla libreria",
|
||||
"ItemRemovedWithName": "{0} è stato rimosso dalla libreria",
|
||||
"LabelIpAddressValue": "Indirizzo IP: {0}",
|
||||
"LabelRunningTimeValue": "Durata: {0}",
|
||||
"Latest": "Novità",
|
||||
"MessageApplicationUpdated": "Il Server Jellyfin è stato aggiornato",
|
||||
"MessageApplicationUpdated": "Jellyfin Server è stato aggiornato",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin Server è stato aggiornato a {0}",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "La sezione {0} della configurazione server è stata aggiornata",
|
||||
"MessageServerConfigurationUpdated": "La configurazione del server è stata aggiornata",
|
||||
"MixedContent": "Contenuto misto",
|
||||
"Movies": "Film",
|
||||
"Music": "Musica",
|
||||
"MusicVideos": "Video Musicali",
|
||||
"NameInstallFailed": "{0} installazione fallita",
|
||||
"MusicVideos": "Video musicali",
|
||||
"NameInstallFailed": "{0} installazione non riuscita",
|
||||
"NameSeasonNumber": "Stagione {0}",
|
||||
"NameSeasonUnknown": "Stagione sconosciuta",
|
||||
"NewVersionIsAvailable": "Una nuova versione di Jellyfin Server è disponibile per il download.",
|
||||
@@ -49,38 +49,37 @@
|
||||
"NotificationOptionAudioPlayback": "La riproduzione audio è iniziata",
|
||||
"NotificationOptionAudioPlaybackStopped": "La riproduzione audio è stata interrotta",
|
||||
"NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata",
|
||||
"NotificationOptionInstallationFailed": "Installazione fallita",
|
||||
"NotificationOptionInstallationFailed": "Installazione non riuscita",
|
||||
"NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto",
|
||||
"NotificationOptionPluginError": "Errore del plugin",
|
||||
"NotificationOptionPluginInstalled": "Plugin installato",
|
||||
"NotificationOptionPluginUninstalled": "Plugin disinstallato",
|
||||
"NotificationOptionPluginUpdateInstalled": "Aggiornamento plugin installato",
|
||||
"NotificationOptionServerRestartRequired": "Riavvio del server necessario",
|
||||
"NotificationOptionTaskFailed": "Operazione pianificata fallita",
|
||||
"NotificationOptionTaskFailed": "Operazione pianificata non riuscita",
|
||||
"NotificationOptionUserLockedOut": "Utente bloccato",
|
||||
"NotificationOptionVideoPlayback": "Riproduzione video iniziata",
|
||||
"NotificationOptionVideoPlaybackStopped": "Riproduzione video interrotta",
|
||||
"Photos": "Foto",
|
||||
"Playlists": "Playlist",
|
||||
"Playlists": "Scalette",
|
||||
"Plugin": "Plugin",
|
||||
"PluginInstalledWithName": "{0} è stato Installato",
|
||||
"PluginInstalledWithName": "{0} è stato installato",
|
||||
"PluginUninstalledWithName": "{0} è stato disinstallato",
|
||||
"PluginUpdatedWithName": "{0} è stato aggiornato",
|
||||
"ProviderValue": "Provider: {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} fallito",
|
||||
"ScheduledTaskFailedWithName": "{0} non riuscito",
|
||||
"ScheduledTaskStartedWithName": "{0} avviato",
|
||||
"ServerNameNeedsToBeRestarted": "{0} deve essere riavviato",
|
||||
"Shows": "Serie TV",
|
||||
"Songs": "Brani",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.",
|
||||
"SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server si sta avviando. Riprova più tardi.",
|
||||
"SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}",
|
||||
"Sync": "Sincronizza",
|
||||
"System": "Sistema",
|
||||
"TvShows": "Serie TV",
|
||||
"User": "Utente",
|
||||
"UserCreatedWithName": "L'utente {0} è stato creato",
|
||||
"UserDeletedWithName": "L'utente {0} è stato rimosso",
|
||||
"UserDeletedWithName": "L'utente {0} è stato eliminato",
|
||||
"UserDownloadingItemWithValues": "{0} sta scaricando {1}",
|
||||
"UserLockedOutWithName": "L'utente {0} è stato bloccato",
|
||||
"UserOfflineFromDevice": "{0} si è disconnesso da {1}",
|
||||
@@ -115,20 +114,20 @@
|
||||
"TasksLibraryCategory": "Libreria",
|
||||
"TasksMaintenanceCategory": "Manutenzione",
|
||||
"TaskCleanActivityLog": "Attività di Registro Completate",
|
||||
"TaskCleanActivityLogDescription": "Elimina le voci del registro delle attività più vecchie dell’età configurata.",
|
||||
"Undefined": "Non Definito",
|
||||
"TaskCleanActivityLogDescription": "Elimina le voci del registro delle attività più vecchie dell'età configurata.",
|
||||
"Undefined": "Non specificato",
|
||||
"Forced": "Forzato",
|
||||
"Default": "Predefinito",
|
||||
"TaskOptimizeDatabaseDescription": "Compatta database e tronca spazi liberi. Eseguire questa azione dopo la scansione o dopo aver fatto altre modifiche inerenti il database potrebbe aumentarne le prestazioni.",
|
||||
"TaskOptimizeDatabase": "Ottimizza database",
|
||||
"TaskKeyframeExtractor": "Estrattore di Keyframe",
|
||||
"TaskKeyframeExtractorDescription": "Estrae i keyframe dai video per creare migliori playlist HLS. Questa procedura potrebbe richiedere molto tempo.",
|
||||
"TaskKeyframeExtractorDescription": "Estrae i keyframe dai video per creare migliori scalette HLS. Questa procedura potrebbe richiedere molto tempo.",
|
||||
"External": "Esterno",
|
||||
"HearingImpaired": "Non Udenti",
|
||||
"HearingImpaired": "Non udenti",
|
||||
"TaskRefreshTrickplayImages": "Genera immagini Trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Crea anteprime trickplay per i video nelle librerie abilitate.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Ripulire le collezioni e le playlist",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Rimuove gli elementi dalle collezioni e dalle playlist che non esistono più.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Ripulisci le collezioni e le scalette",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Rimuove gli elementi dalle collezioni e dalle scalette che non esistono più.",
|
||||
"TaskAudioNormalization": "Normalizzazione dell'audio",
|
||||
"TaskAudioNormalizationDescription": "Scansiona i file alla ricerca dei dati per la normalizzazione dell'audio.",
|
||||
"TaskDownloadMissingLyricsDescription": "Scarica testi per le canzoni",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Körsetımder",
|
||||
"Songs": "Äuender",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server jüktelude. Ärekettı köp ūzamai qaitalañyz.",
|
||||
"SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
|
||||
"SubtitleDownloadFailureFromForItem": "{1} üşın subtitrlerdı {0} közınen jüktep alu sätsız",
|
||||
"Sync": "Ündestıru",
|
||||
"System": "Jüie",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "시리즈",
|
||||
"Songs": "노래",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin 서버를 불러오고 있습니다. 잠시 후에 다시 시도하십시오.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "{0}에서 {1} 자막 다운로드에 실패했습니다",
|
||||
"Sync": "동기화",
|
||||
"System": "시스템",
|
||||
@@ -136,5 +135,7 @@
|
||||
"TaskMoveTrickplayImages": "트릭플레이 이미지 위치 마이그레이션",
|
||||
"TaskMoveTrickplayImagesDescription": "추출된 트릭플레이 이미지를 라이브러리 설정에 따라 이동합니다.",
|
||||
"TaskDownloadMissingLyrics": "누락된 가사 다운로드",
|
||||
"TaskDownloadMissingLyricsDescription": "가사 다운로드"
|
||||
"TaskDownloadMissingLyricsDescription": "가사 다운로드",
|
||||
"CleanupUserDataTask": "사용자 데이터 정리 작업",
|
||||
"CleanupUserDataTaskDescription": "최소 90일 이상 존재하지 않는 미디어에 대한 사용자 데이터(시청 상태, 즐겨찾기 등)를 정리합니다."
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Laidos",
|
||||
"Songs": "Kūriniai",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}",
|
||||
"Sync": "Sinchronizuoti",
|
||||
"System": "Sistema",
|
||||
|
||||
9
Emby.Server.Implementations/Localization/Core/mi.json
Normal file
9
Emby.Server.Implementations/Localization/Core/mi.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Albums": "Pukaemi",
|
||||
"AppDeviceValues": "Taupānga: {0}, Pūrere: {1}",
|
||||
"Application": "Taupānga",
|
||||
"Artists": "Kaiwaiata",
|
||||
"AuthenticationSucceededWithUserName": "{0} has been successfully authenticated",
|
||||
"Books": "Ngā pukapuka",
|
||||
"CameraImageUploadedFrom": "Kua tuku ake he whakaahua kāmera hou mai i {0}"
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
"AppDeviceValues": "അപ്ലിക്കേഷൻ: {0}, ഉപകരണം: {1}",
|
||||
"Application": "അപ്ലിക്കേഷൻ",
|
||||
"AuthenticationSucceededWithUserName": "{0} വിജയകരമായി പ്രാമാണീകരിച്ചു",
|
||||
"CameraImageUploadedFrom": "Camera 0 from എന്നതിൽ നിന്ന് ഒരു പുതിയ ക്യാമറ ചിത്രം അപ്ലോഡുചെയ്തു",
|
||||
"CameraImageUploadedFrom": "{0} എന്നതിൽ നിന്ന് ഒരു പുതിയ ക്യാമറ ചിത്രം അപ്ലോഡുചെയ്തു",
|
||||
"ChapterNameValue": "അധ്യായം {0}",
|
||||
"DeviceOfflineWithName": "{0} വിച്ഛേദിച്ചു",
|
||||
"DeviceOnlineWithName": "{0} ബന്ധിപ്പിച്ചു",
|
||||
"FailedLoginAttemptWithUserName": "{0}ൽ നിന്നുള്ള പ്രവേശന ശ്രമം പരാജയപ്പെട്ടു",
|
||||
"Forced": "നിർബന്ധിച്ചു",
|
||||
"Forced": "നിർബന്ധിതമായി",
|
||||
"HeaderFavoriteAlbums": "പ്രിയപ്പെട്ട ആൽബങ്ങൾ",
|
||||
"HeaderFavoriteArtists": "പ്രിയപ്പെട്ട കലാകാരന്മാർ",
|
||||
"HeaderFavoriteEpisodes": "പ്രിയപ്പെട്ട എപ്പിസോഡുകൾ",
|
||||
@@ -114,7 +114,7 @@
|
||||
"Artists": "കലാകാരന്മാർ",
|
||||
"Shows": "ഷോകൾ",
|
||||
"Default": "സ്ഥിരസ്ഥിതി",
|
||||
"Favorites": "പ്രിയങ്കരങ്ങൾ",
|
||||
"Favorites": "പ്രിയപ്പെട്ടവ",
|
||||
"Books": "പുസ്തകങ്ങൾ",
|
||||
"Genres": "വിഭാഗങ്ങൾ",
|
||||
"Channels": "ചാനലുകൾ",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"HeaderNextUp": "Дараа нь",
|
||||
"HeaderContinueWatching": "Үргэлжлүүлэн үзэх",
|
||||
"Songs": "Дуунууд",
|
||||
"Playlists": "Playlist-ууд",
|
||||
"Playlists": "Тоглуулах жагсаалтууд",
|
||||
"Movies": "Кинонууд",
|
||||
"Latest": "Сүүлийн үеийн",
|
||||
"Genres": "Төрлүүд",
|
||||
@@ -71,7 +71,7 @@
|
||||
"Forced": "Хүчээр",
|
||||
"HeaderAlbumArtists": "Цомгийн уран бүтээлчид",
|
||||
"HeaderFavoriteAlbums": "Дуртай цомгууд",
|
||||
"HeaderLiveTV": "Шууд",
|
||||
"HeaderLiveTV": "Шууд ТВ",
|
||||
"HeaderRecordingGroups": "Бичлэгийн бүлгүүд",
|
||||
"HearingImpaired": "Сонсголын бэрхшээлтэй",
|
||||
"HomeVideos": "Үндсэн дүрсүүд",
|
||||
@@ -109,7 +109,7 @@
|
||||
"ScheduledTaskStartedWithName": "{0}-г эхлүүлэв",
|
||||
"ServerNameNeedsToBeRestarted": "{0}-г дахин асаана уу",
|
||||
"Shows": "Шоу",
|
||||
"Sync": "Дахин",
|
||||
"Sync": "Синхрончлох",
|
||||
"System": "Систем",
|
||||
"TvShows": "ТВ нэвтрүүлгүүд",
|
||||
"Undefined": "Танисангүй",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Tayangan",
|
||||
"Songs": "Lagu-lagu",
|
||||
"StartupEmbyServerIsLoading": "Pelayan Jellyfin sedang dimuatkan. Sila cuba sebentar lagi.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Muat turun sarikata gagal dari {0} untuk {1}",
|
||||
"Sync": "Segerak",
|
||||
"System": "Sistem",
|
||||
|
||||
@@ -126,5 +126,7 @@
|
||||
"TaskRefreshTrickplayImages": "ထရစ်ခ်ပလေး ပုံများကို ထုတ်မည်",
|
||||
"TaskKeyframeExtractor": "ကီးဖရိန်များကို ထုတ်နုတ်ခြင်း",
|
||||
"TaskCleanCollectionsAndPlaylists": "စုစည်းမှုများနှင့် အစဉ်လိုက်ပြသမှုများကို ရှင်းလင်းမည်",
|
||||
"HearingImpaired": "အကြားအာရုံ ချို့တဲ့သူ"
|
||||
"HearingImpaired": "အကြားအာရုံ ချို့တဲ့သူ",
|
||||
"TaskDownloadMissingLyrics": "ကျန်နေသောသီချင်းစာသားများအား ဒေါင်းလုတ်ဆွဲပါ",
|
||||
"TaskDownloadMissingLyricsDescription": "သီချင်းများအတွက် သီချင်းစာသား ဒေါင်းလုတ်ဆွဲပါ"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serier",
|
||||
"Songs": "Sanger",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
|
||||
"SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
|
||||
"Sync": "Synkroniser",
|
||||
"System": "System",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Series",
|
||||
"Songs": "Nummers",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden. Probeer het later opnieuw.",
|
||||
"SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
|
||||
"SubtitleDownloadFailureFromForItem": "Ondertiteling kon niet gedownload worden van {0} voor {1}",
|
||||
"Sync": "Synchronisatie",
|
||||
"System": "Systeem",
|
||||
|
||||
1
Emby.Server.Implementations/Localization/Core/oc.json
Normal file
1
Emby.Server.Implementations/Localization/Core/oc.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -134,6 +134,8 @@
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "ਕਲੈਕਸ਼ਨਾਂ ਅਤੇ ਪਲੇਲਿਸਟਾਂ ਵਿੱਚੋਂ ਉਹ ਆਈਟਮ ਹਟਾਉਂਦਾ ਹੈ ਜੋ ਹੁਣ ਮੌਜੂਦ ਨਹੀਂ ਹਨ।",
|
||||
"TaskCleanCollectionsAndPlaylists": "ਕਲੈਕਸ਼ਨਾਂ ਅਤੇ ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਸਾਫ ਕਰੋ",
|
||||
"TaskAudioNormalization": "ਆਵਾਜ਼ ਸਧਾਰਣੀਕਰਨ",
|
||||
"TaskRefreshTrickplayImagesDescription": "ਚਲ ਰਹੀ ਲਾਇਬ੍ਰੇਰੀਆਂ ਵਿੱਚ ਵੀਡੀਓਜ਼ ਲਈ ਟ੍ਰਿਕਪਲੇ ਪ੍ਰੀਵਿਊ ਬਣਾਉਂਦਾ ਹੈ।",
|
||||
"TaskKeyframeExtractorDescription": "ਕੀ-ਫ੍ਰੇਮਜ਼ ਨੂੰ ਵੀਡੀਓ ਫਾਈਲਾਂ ਵਿੱਚੋਂ ਨਿਕਾਲਦਾ ਹੈ ਤਾਂ ਜੋ ਹੋਰ ਜ਼ਿਆਦਾ ਸਟਿਕ ਹੋਣ ਵਾਲੀਆਂ HLS ਪਲੇਲਿਸਟਾਂ ਬਣਾਈਆਂ ਜਾ ਸਕਣ। ਇਹ ਕੰਮ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਚੱਲ ਸਕਦਾ ਹੈ।"
|
||||
"TaskRefreshTrickplayImagesDescription": "ਵੀਡੀਓ ਲਈ ਟ੍ਰਿਕਪਲੇ ਪ੍ਰੀਵਿਊ ਬਣਾਉਂਦਾ ਹੈ (ਜੇ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਚੁਣਿਆ ਗਿਆ ਹੈ)।",
|
||||
"TaskKeyframeExtractorDescription": "ਕੀ-ਫ੍ਰੇਮਜ਼ ਨੂੰ ਵੀਡੀਓ ਫਾਈਲਾਂ ਵਿੱਚੋਂ ਨਿਕਾਲਦਾ ਹੈ ਤਾਂ ਜੋ ਹੋਰ ਜ਼ਿਆਦਾ ਸਟਿਕ ਹੋਣ ਵਾਲੀਆਂ HLS ਪਲੇਲਿਸਟਾਂ ਬਣਾਈਆਂ ਜਾ ਸਕਣ। ਇਹ ਕੰਮ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਚੱਲ ਸਕਦਾ ਹੈ।",
|
||||
"CleanupUserDataTaskDescription": "ਘੱਟੋ-ਘੱਟ 90 ਦਿਨਾਂ ਤੋਂ ਮੌਜੂਦ ਨਾ ਹੋਣ ਵਾਲੇ ਮੀਡੀਆ ਤੋਂ ਸਾਰੇ ਉਪਭੋਗਤਾ ਡੇਟਾ (ਵਾਚ ਸਟੇਟ, ਮਨਪਸੰਦ ਸਟੇਟਸ ਆਦਿ) ਨੂੰ ਸਾਫ਼ ਕਰਦਾ ਹੈ।",
|
||||
"CleanupUserDataTask": "ਯੂਜ਼ਰ ਡਾਟਾ ਸਾਫ਼ ਕਰਨ ਦਾ ਕੰਮ"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Seriale",
|
||||
"Songs": "Utwory",
|
||||
"StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
|
||||
"SubtitleDownloadFailureForItem": "Pobieranie napisów dla {0} zakończone niepowodzeniem",
|
||||
"SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
|
||||
"Sync": "Synchronizacja",
|
||||
"System": "System",
|
||||
@@ -125,8 +124,8 @@
|
||||
"TaskKeyframeExtractorDescription": "Wyodrębnia klatki kluczowe z plików wideo w celu utworzenia bardziej precyzyjnych list odtwarzania HLS. To zadanie może trwać przez długi czas.",
|
||||
"TaskKeyframeExtractor": "Ekstraktor klatek kluczowych",
|
||||
"HearingImpaired": "Niedosłyszący",
|
||||
"TaskRefreshTrickplayImages": "Generuj obrazy trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Tworzy podglądy trickplay dla filmów we włączonych bibliotekach.",
|
||||
"TaskRefreshTrickplayImages": "Generuj obrazy Trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Tworzy podglądy Trickplay dla filmów we włączonych bibliotekach.",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Usuwa elementy z kolekcji i list odtwarzania, które już nie istnieją.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Oczyść kolekcje i listy odtwarzania",
|
||||
"TaskAudioNormalization": "Normalizacja dźwięku",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"Collections": "Barrels",
|
||||
"ItemAddedWithName": "{0} is now with yer treasure",
|
||||
"Default": "Normal-like",
|
||||
"FailedLoginAttemptWithUserName": "Ye failed to get in, try from {0}",
|
||||
"FailedLoginAttemptWithUserName": "Ye failed to enter from {0}",
|
||||
"Favorites": "Finest Loot",
|
||||
"ItemRemovedWithName": "{0} was taken from yer treasure",
|
||||
"LabelIpAddressValue": "Ship's coordinates: {0}",
|
||||
@@ -113,5 +113,10 @@
|
||||
"TaskCleanCache": "Sweep the Cache Chest",
|
||||
"TaskRefreshChapterImages": "Claim chapter portraits",
|
||||
"TaskRefreshChapterImagesDescription": "Paints wee portraits fer videos that own chapters.",
|
||||
"TaskRefreshLibrary": "Scan the Treasure Trove"
|
||||
"TaskRefreshLibrary": "Scan the Treasure Trove",
|
||||
"TasksChannelsCategory": "Channels o' thy Internet",
|
||||
"TaskRefreshTrickplayImages": "Summon the picture tricks",
|
||||
"TaskRefreshTrickplayImagesDescription": "Summons picture trick previews for videos in ye enabled book roost",
|
||||
"TaskUpdatePlugins": "Resummon yer Plugins",
|
||||
"TaskCleanTranscode": "Swab Ye Transcode Directory"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Séries",
|
||||
"Songs": "Músicas",
|
||||
"StartupEmbyServerIsLoading": "O Servidor Jellyfin está carregando. Por favor, tente novamente mais tarde.",
|
||||
"SubtitleDownloadFailureForItem": "Download de legendas falhou para {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Houve um problema ao baixar as legendas de {0} para {1}",
|
||||
"Sync": "Sincronizar",
|
||||
"System": "Sistema",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"Artists": "Artistas",
|
||||
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
|
||||
"Books": "Livros",
|
||||
"CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
|
||||
"CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
|
||||
"Channels": "Canais",
|
||||
"ChapterNameValue": "Capítulo {0}",
|
||||
"Collections": "Coleções",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Séries",
|
||||
"Songs": "Músicas",
|
||||
"StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente mais tarde.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas a partir de {0} para {1}",
|
||||
"Sync": "Sincronização",
|
||||
"System": "Sistema",
|
||||
@@ -125,8 +124,8 @@
|
||||
"TaskKeyframeExtractor": "Extrator de Quadros-chave",
|
||||
"External": "Externo",
|
||||
"HearingImpaired": "Surdo",
|
||||
"TaskRefreshTrickplayImages": "Gerar imagens de truques",
|
||||
"TaskRefreshTrickplayImagesDescription": "Cria vizualizações de truques para videos nas librarias ativas.",
|
||||
"TaskRefreshTrickplayImages": "Gerar imagens de trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Cria pré-visualizações de trickplay para vídeos nas bibliotecas ativadas.",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Remove itens de coleções e listas de reprodução que já não existem.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Limpar coleções e listas de reprodução",
|
||||
"TaskAudioNormalizationDescription": "Analisa os ficheiros para obter dados de normalização de áudio.",
|
||||
|
||||
@@ -124,8 +124,8 @@
|
||||
"HearingImpaired": "Problemas auditivos",
|
||||
"TaskKeyframeExtractor": "Extrator de quadro-chave",
|
||||
"TaskKeyframeExtractorDescription": "Retira frames chave do video para criar listas HLS precisas. Esta tarefa pode correr durante algum tempo.",
|
||||
"TaskRefreshTrickplayImages": "Gerar miniaturas de vídeo",
|
||||
"TaskRefreshTrickplayImagesDescription": "Cria miniaturas de vídeo para vídeos nas bibliotecas definidas.",
|
||||
"TaskRefreshTrickplayImages": "Gerar imagens de trickplay",
|
||||
"TaskRefreshTrickplayImagesDescription": "Cria pré-visualizações de trickplay para vídeos nas bibliotecas ativadas.",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Remove itens de coleções e listas de reprodução que já não existem.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Limpar coleções e listas de reprodução",
|
||||
"TaskAudioNormalizationDescription": "Analisa os ficheiros para obter dados de normalização de áudio.",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Сериалы",
|
||||
"Songs": "Композиции",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
|
||||
"SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
|
||||
"SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
|
||||
"Sync": "Синхронизация",
|
||||
"System": "Система",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Seriály",
|
||||
"Songs": "Skladby",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server sa spúšťa. Prosím, skúste to o chvíľu znova.",
|
||||
"SubtitleDownloadFailureForItem": "Sťahovanie titulkov pre {0} zlyhalo",
|
||||
"SubtitleDownloadFailureFromForItem": "Sťahovanie titulkov z {0} pre {1} zlyhalo",
|
||||
"Sync": "Synchronizácia",
|
||||
"System": "Systém",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serije",
|
||||
"Songs": "Pesmi",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin strežnik se zaganja. Poskusite ponovno kasneje.",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Neuspešen prenos podnapisov iz {0} za {1}",
|
||||
"Sync": "Sinhroniziraj",
|
||||
"System": "Sistem",
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "Serier",
|
||||
"Songs": "Låtar",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Server arbetar. Pröva igen snart.",
|
||||
"SubtitleDownloadFailureForItem": "Nerladdning av undertexter för {0} misslyckades",
|
||||
"SubtitleDownloadFailureFromForItem": "Undertexter kunde inte laddas ner från {0} till {1}",
|
||||
"Sync": "Synk",
|
||||
"System": "System",
|
||||
|
||||
1
Emby.Server.Implementations/Localization/Core/sw.json
Normal file
1
Emby.Server.Implementations/Localization/Core/sw.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -135,5 +135,7 @@
|
||||
"TaskExtractMediaSegments": "การสแกนส่วนของสื่อมีเดีย",
|
||||
"TaskMoveTrickplayImagesDescription": "ย้ายไฟล์ Trickplay ตามการตั้งค่าของไลบรารี",
|
||||
"TaskExtractMediaSegmentsDescription": "แยกหรือดึงส่วนของสื่อจากปลั๊กอินที่เปิดใช้งาน MediaSegment",
|
||||
"TaskMoveTrickplayImages": "ย้ายตำแหน่งเก็บภาพตัวอย่าง Trickplay"
|
||||
"TaskMoveTrickplayImages": "ย้ายตำแหน่งเก็บภาพตัวอย่าง Trickplay",
|
||||
"CleanupUserDataTask": "ส่วนงานล้างข้อมูลผู้ใช้",
|
||||
"CleanupUserDataTaskDescription": "ล้างข้อมูลผู้ใช้ทั้งหมด (สถานะการรับชม สถานะรายการโปรด ฯลฯ) จากสื่อที่ไม่ได้ใช้งานแล้วอย่างน้อย 90 วัน"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"ItemAddedWithName": "{0} kütüphaneye eklendi",
|
||||
"ItemRemovedWithName": "{0} kütüphaneden silindi",
|
||||
"LabelIpAddressValue": "IP adresi: {0}",
|
||||
"LabelRunningTimeValue": "Çalışma süresi: {0}",
|
||||
"LabelRunningTimeValue": "Oynatma süresi: {0}",
|
||||
"Latest": "En son",
|
||||
"MessageApplicationUpdated": "Jellyfin Sunucusu güncellendi",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin Sunucusu {0} sürümüne güncellendi",
|
||||
@@ -42,7 +42,7 @@
|
||||
"MusicVideos": "Müzik Videoları",
|
||||
"NameInstallFailed": "{0} kurulumu başarısız",
|
||||
"NameSeasonNumber": "{0}. Sezon",
|
||||
"NameSeasonUnknown": "Bilinmeyen Sezon",
|
||||
"NameSeasonUnknown": "Sezon Bilinmiyor",
|
||||
"NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir sürümü indirmek için hazır.",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Uygulama güncellemesi mevcut",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Uygulama güncellemesi yüklendi",
|
||||
@@ -57,7 +57,7 @@
|
||||
"NotificationOptionPluginUpdateInstalled": "Eklenti güncellemesi yüklendi",
|
||||
"NotificationOptionServerRestartRequired": "Sunucunun yeniden başlatılması gerekiyor",
|
||||
"NotificationOptionTaskFailed": "Zamanlanmış görev hatası",
|
||||
"NotificationOptionUserLockedOut": "Kullanıcı kilitlendi",
|
||||
"NotificationOptionUserLockedOut": "Kullanıcı hesabı kilitlendi",
|
||||
"NotificationOptionVideoPlayback": "Video oynatma başladı",
|
||||
"NotificationOptionVideoPlaybackStopped": "Video oynatma durduruldu",
|
||||
"Photos": "Fotoğraflar",
|
||||
@@ -73,8 +73,7 @@
|
||||
"Shows": "Diziler",
|
||||
"Songs": "Şarkılar",
|
||||
"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} sağlayıcısından indirilemedi",
|
||||
"SubtitleDownloadFailureFromForItem": "{1} için altyazılar {0} sağlayıcısından indirilemedi",
|
||||
"Sync": "Eşzamanlama",
|
||||
"System": "Sistem",
|
||||
"TvShows": "Diziler",
|
||||
@@ -82,7 +81,7 @@
|
||||
"UserCreatedWithName": "{0} kullanıcısı oluşturuldu",
|
||||
"UserDeletedWithName": "{0} kullanıcısı silindi",
|
||||
"UserDownloadingItemWithValues": "{0} kullanıcısı {1} medyasını indiriyor",
|
||||
"UserLockedOutWithName": "{0} adlı kullanıcı kilitlendi",
|
||||
"UserLockedOutWithName": "{0} adlı kullanıcı hesabı kilitlendi",
|
||||
"UserOfflineFromDevice": "{0} kullanıcısının {1} ile bağlantısı kesildi",
|
||||
"UserOnlineFromDevice": "{0} kullanıcısı {1} ile çevrimiçi",
|
||||
"UserPasswordChangedWithName": "{0} kullanıcısının parolası değiştirildi",
|
||||
@@ -98,8 +97,8 @@
|
||||
"TasksLibraryCategory": "Kütüphane",
|
||||
"TasksMaintenanceCategory": "Bakım",
|
||||
"TaskRefreshPeopleDescription": "Medya kütüphanenizdeki videoların oyuncu ve yönetmen bilgilerini günceller.",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Meta veri yapılandırmasına dayalı olarak eksik alt yazılar için internette arama yapar.",
|
||||
"TaskDownloadMissingSubtitles": "Eksik alt yazıları indir",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Meta veri yapılandırmasına dayalı olarak eksik altyazılar için internette arama yapar.",
|
||||
"TaskDownloadMissingSubtitles": "Eksik altyazıları indir",
|
||||
"TaskRefreshChannelsDescription": "Internet kanal bilgilerini yenile.",
|
||||
"TaskRefreshChannels": "Kanalları Yenile",
|
||||
"TaskCleanTranscodeDescription": "Bir günden daha eski kod dönüştürme dosyalarını siler.",
|
||||
@@ -125,15 +124,15 @@
|
||||
"TaskKeyframeExtractor": "Ana Kare Çıkarıcı",
|
||||
"External": "Harici",
|
||||
"HearingImpaired": "Duyma Engelli",
|
||||
"TaskRefreshTrickplayImages": "Trickplay Görselleri Oluştur",
|
||||
"TaskRefreshTrickplayImagesDescription": "Etkin kütüphanelerdeki videolar için trickplay önizlemeleri oluşturur.",
|
||||
"TaskRefreshTrickplayImages": "Hızlı Önizleme Görsellerini Oluştur",
|
||||
"TaskRefreshTrickplayImagesDescription": "Etkin kütüphanelerdeki videolar için hızlı önizleme görselleri oluşturur.",
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "Artık var olmayan koleksiyon ve çalma listelerindeki ögeleri kaldırır.",
|
||||
"TaskCleanCollectionsAndPlaylists": "Koleksiyonları ve çalma listelerini temizleyin",
|
||||
"TaskAudioNormalizationDescription": "Ses normalleştirme verileri için dosyaları tarar.",
|
||||
"TaskAudioNormalization": "Ses Normalleştirme",
|
||||
"TaskExtractMediaSegments": "Medya Segmenti Tarama",
|
||||
"TaskMoveTrickplayImages": "Trickplay Görsel Konumunu Taşıma",
|
||||
"TaskMoveTrickplayImagesDescription": "Mevcut trickplay dosyalarını kütüphane ayarlarına göre taşır.",
|
||||
"TaskMoveTrickplayImages": "Hızlı Önizleme Görsel Konumunu Taşıma",
|
||||
"TaskMoveTrickplayImagesDescription": "Mevcut hızlı önizleme dosyalarını kütüphane ayarlarına göre taşır.",
|
||||
"TaskDownloadMissingLyrics": "Eksik şarkı sözlerini indir",
|
||||
"TaskDownloadMissingLyricsDescription": "Şarkı sözlerini indirir",
|
||||
"TaskExtractMediaSegmentsDescription": "MediaSegment özelliği etkin olan eklentilerden medya segmentlerini çıkarır veya alır.",
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"TasksMaintenanceCategory": "Bảo Trì",
|
||||
"VersionNumber": "Phiên Bản {0}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} đã được thêm vào thư viện của bạn",
|
||||
"UserStoppedPlayingItemWithValues": "{0} đã phát xong {1} trên {2}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} đã kết thúc phát {1} trên {2}",
|
||||
"UserStartedPlayingItemWithValues": "{0} đang phát {1} trên {2}",
|
||||
"UserPolicyUpdatedWithName": "Chính sách người dùng đã được cập nhật cho {0}",
|
||||
"UserPasswordChangedWithName": "Mật khẩu đã được thay đổi cho người dùng {0}",
|
||||
|
||||
@@ -5,60 +5,60 @@
|
||||
"Artists": "艺术家",
|
||||
"AuthenticationSucceededWithUserName": "{0} 认证成功",
|
||||
"Books": "书籍",
|
||||
"CameraImageUploadedFrom": "新的相机图像已从 {0} 上传",
|
||||
"CameraImageUploadedFrom": "已从 {0} 上传新的相机照片",
|
||||
"Channels": "频道",
|
||||
"ChapterNameValue": "章节 {0}",
|
||||
"Collections": "合集",
|
||||
"DeviceOfflineWithName": "{0} 已断开",
|
||||
"DeviceOfflineWithName": "{0} 已断开连接",
|
||||
"DeviceOnlineWithName": "{0} 已连接",
|
||||
"FailedLoginAttemptWithUserName": "来自 {0} 的登录尝试失败",
|
||||
"Favorites": "我的最爱",
|
||||
"FailedLoginAttemptWithUserName": "来自 {0} 的登录失败",
|
||||
"Favorites": "收藏夹",
|
||||
"Folders": "文件夹",
|
||||
"Genres": "类型",
|
||||
"HeaderAlbumArtists": "专辑艺术家",
|
||||
"HeaderContinueWatching": "继续观看",
|
||||
"HeaderFavoriteAlbums": "收藏的专辑",
|
||||
"HeaderFavoriteArtists": "最爱的艺术家",
|
||||
"HeaderFavoriteEpisodes": "最爱的剧集",
|
||||
"HeaderFavoriteShows": "最爱的节目",
|
||||
"HeaderFavoriteSongs": "最爱的歌曲",
|
||||
"HeaderFavoriteArtists": "收藏的艺术家",
|
||||
"HeaderFavoriteEpisodes": "收藏的剧集",
|
||||
"HeaderFavoriteShows": "收藏的节目",
|
||||
"HeaderFavoriteSongs": "收藏的歌曲",
|
||||
"HeaderLiveTV": "电视直播",
|
||||
"HeaderNextUp": "接下来",
|
||||
"HeaderNextUp": "接下来播放",
|
||||
"HeaderRecordingGroups": "录制组",
|
||||
"HomeVideos": "家庭视频",
|
||||
"Inherit": "继承",
|
||||
"ItemAddedWithName": "{0} 已添加到媒体库",
|
||||
"ItemRemovedWithName": "{0} 已从媒体库中移除",
|
||||
"ItemRemovedWithName": "{0} 已从媒体库移除",
|
||||
"LabelIpAddressValue": "IP 地址:{0}",
|
||||
"LabelRunningTimeValue": "运行时间:{0}",
|
||||
"Latest": "最新",
|
||||
"MessageApplicationUpdated": "Jellyfin 服务器已更新",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin Server 版本已更新为 {0}",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin 服务器版本已更新到 {0}",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "服务器配置 {0} 部分已更新",
|
||||
"MessageServerConfigurationUpdated": "服务器配置已更新",
|
||||
"MixedContent": "混合内容",
|
||||
"Movies": "电影",
|
||||
"Music": "音乐",
|
||||
"MusicVideos": "音乐视频",
|
||||
"MusicVideos": "MV",
|
||||
"NameInstallFailed": "{0} 安装失败",
|
||||
"NameSeasonNumber": "第 {0} 季",
|
||||
"NameSeasonUnknown": "未知季",
|
||||
"NewVersionIsAvailable": "Jellyfin Server 有新版本可以下载。",
|
||||
"NewVersionIsAvailable": "Jellyfin 服务器有新版本可供下载。",
|
||||
"NotificationOptionApplicationUpdateAvailable": "有可用的应用程序更新",
|
||||
"NotificationOptionApplicationUpdateInstalled": "应用程序更新已安装",
|
||||
"NotificationOptionAudioPlayback": "音频开始播放",
|
||||
"NotificationOptionAudioPlayback": "音频已开始播放",
|
||||
"NotificationOptionAudioPlaybackStopped": "音频播放已停止",
|
||||
"NotificationOptionCameraImageUploaded": "相机图片已上传",
|
||||
"NotificationOptionCameraImageUploaded": "相机照片已上传",
|
||||
"NotificationOptionInstallationFailed": "安装失败",
|
||||
"NotificationOptionNewLibraryContent": "已添加新内容",
|
||||
"NotificationOptionPluginError": "插件失败",
|
||||
"NotificationOptionPluginError": "插件出错",
|
||||
"NotificationOptionPluginInstalled": "插件已安装",
|
||||
"NotificationOptionPluginUninstalled": "插件已卸载",
|
||||
"NotificationOptionPluginUpdateInstalled": "插件更新已安装",
|
||||
"NotificationOptionPluginUpdateInstalled": "插件已更新",
|
||||
"NotificationOptionServerRestartRequired": "服务器需要重启",
|
||||
"NotificationOptionTaskFailed": "计划任务失败",
|
||||
"NotificationOptionUserLockedOut": "用户已锁定",
|
||||
"NotificationOptionVideoPlayback": "视频开始播放",
|
||||
"NotificationOptionUserLockedOut": "用户已被锁定",
|
||||
"NotificationOptionVideoPlayback": "视频已开始播放",
|
||||
"NotificationOptionVideoPlaybackStopped": "视频播放已停止",
|
||||
"Photos": "照片",
|
||||
"Playlists": "播放列表",
|
||||
@@ -72,23 +72,22 @@
|
||||
"ServerNameNeedsToBeRestarted": "{0} 需要重新启动",
|
||||
"Shows": "节目",
|
||||
"Songs": "歌曲",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin 服务器加载中。请稍后再试。",
|
||||
"SubtitleDownloadFailureForItem": "为 {0} 下载字幕失败",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin 服务器正在启动,请稍后再试。",
|
||||
"SubtitleDownloadFailureFromForItem": "无法从 {0} 下载 {1} 的字幕",
|
||||
"Sync": "同步",
|
||||
"System": "系统",
|
||||
"TvShows": "电视剧",
|
||||
"User": "用户",
|
||||
"UserCreatedWithName": "用户 {0} 已创建",
|
||||
"UserDeletedWithName": "用户 {0} 已删除",
|
||||
"UserCreatedWithName": "已创建用户 {0}",
|
||||
"UserDeletedWithName": "已删除用户 {0}",
|
||||
"UserDownloadingItemWithValues": "{0} 正在下载 {1}",
|
||||
"UserLockedOutWithName": "用户 {0} 已被锁定",
|
||||
"UserOfflineFromDevice": "{0} 已从 {1} 断开",
|
||||
"UserOnlineFromDevice": "{0} 在线,来自 {1}",
|
||||
"UserPasswordChangedWithName": "已为用户 {0} 更改密码",
|
||||
"UserPolicyUpdatedWithName": "用户协议已经被更新为 {0}",
|
||||
"UserStartedPlayingItemWithValues": "{0} 已在 {2} 上开始播放 {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
|
||||
"UserOnlineFromDevice": "{0} 已在 {1} 上线",
|
||||
"UserPasswordChangedWithName": "用户 {0} 的密码已更改",
|
||||
"UserPolicyUpdatedWithName": "用户协议已更新为 {0}",
|
||||
"UserStartedPlayingItemWithValues": "{0} 在 {2} 上开始播放 {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} 在 {2} 上停止播放 {1}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} 已添加至您的媒体库中",
|
||||
"ValueSpecialEpisodeName": "特典 - {0}",
|
||||
"VersionNumber": "版本 {0}",
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"HeaderFavoriteShows": "最愛的節目",
|
||||
"HeaderFavoriteSongs": "最愛的歌曲",
|
||||
"HeaderLiveTV": "電視直播",
|
||||
"HeaderNextUp": "接著播放",
|
||||
"HeaderNextUp": "繼續觀看",
|
||||
"HeaderRecordingGroups": "錄製組",
|
||||
"HomeVideos": "家庭影片",
|
||||
"Inherit": "繼承",
|
||||
@@ -73,7 +73,6 @@
|
||||
"Shows": "節目",
|
||||
"Songs": "歌曲",
|
||||
"StartupEmbyServerIsLoading": "正在載入 Jellyfin,請稍後再試。",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "無法從 {0} 下載 {1} 的字幕",
|
||||
"Sync": "同步",
|
||||
"System": "系統",
|
||||
@@ -127,8 +126,8 @@
|
||||
"HearingImpaired": "聽力障礙",
|
||||
"TaskRefreshTrickplayImages": "建立 Trickplay 圖像",
|
||||
"TaskRefreshTrickplayImagesDescription": "為已啟用 Trickplay 的媒體庫內的影片建立 Trickplay 預覽圖。",
|
||||
"TaskExtractMediaSegments": "掃描媒體段落",
|
||||
"TaskExtractMediaSegmentsDescription": "從MediaSegment中被允許的插件獲取媒體段落。",
|
||||
"TaskExtractMediaSegments": "掃描媒體分段資訊",
|
||||
"TaskExtractMediaSegmentsDescription": "從允許MediaSegment 功能的插件中獲取媒體片段。",
|
||||
"TaskDownloadMissingLyrics": "下載欠缺歌詞",
|
||||
"TaskDownloadMissingLyricsDescription": "下載歌詞",
|
||||
"TaskCleanCollectionsAndPlaylists": "整理媒體與播放清單",
|
||||
@@ -137,5 +136,6 @@
|
||||
"TaskCleanCollectionsAndPlaylistsDescription": "從資料庫及播放清單中移除已不存在的項目。",
|
||||
"TaskMoveTrickplayImagesDescription": "根據媒體庫設定移動現有的 Trickplay 檔案。",
|
||||
"TaskMoveTrickplayImages": "轉移 Trickplay 影像位置",
|
||||
"CleanupUserDataTask": "用戶資料清理工作"
|
||||
"CleanupUserDataTask": "用戶資料清理工作",
|
||||
"CleanupUserDataTaskDescription": "從用戶數據中清除已經被刪除超過 90 日的媒體相關資料。"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
|
||||
private readonly ConcurrentDictionary<string, CultureDto?> _cultureCache = new(StringComparer.OrdinalIgnoreCase);
|
||||
private List<CultureDto> _cultures = [];
|
||||
|
||||
private FrozenDictionary<string, string> _iso6392BtoT = null!;
|
||||
@@ -161,6 +162,7 @@ namespace Emby.Server.Implementations.Localization
|
||||
list.Add(new CultureDto(name, displayname, twoCharName, threeLetterNames));
|
||||
}
|
||||
|
||||
_cultureCache.Clear();
|
||||
_cultures = list;
|
||||
_iso6392BtoT = iso6392BtoTdict.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -169,20 +171,31 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// <inheritdoc />
|
||||
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++)
|
||||
if (string.IsNullOrEmpty(language))
|
||||
{
|
||||
var culture = _cultures[i];
|
||||
if (language.Equals(culture.DisplayName, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(culture.Name, StringComparison.OrdinalIgnoreCase)
|
||||
|| culture.ThreeLetterISOLanguageNames.Contains(language, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return culture;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return default;
|
||||
return _cultureCache.GetOrAdd(
|
||||
language,
|
||||
static (lang, cultures) =>
|
||||
{
|
||||
// TODO language should ideally be a ReadOnlySpan but moq cannot mock ref structs
|
||||
for (var i = 0; i < cultures.Count; i++)
|
||||
{
|
||||
var culture = cultures[i];
|
||||
if (lang.Equals(culture.DisplayName, StringComparison.OrdinalIgnoreCase)
|
||||
|| lang.Equals(culture.Name, StringComparison.OrdinalIgnoreCase)
|
||||
|| culture.ThreeLetterISOLanguageNames.Contains(lang, StringComparison.OrdinalIgnoreCase)
|
||||
|| lang.Equals(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return culture;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
_cultures);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -311,15 +324,19 @@ namespace Emby.Server.Implementations.Localization
|
||||
else
|
||||
{
|
||||
// Fall back to server default language for ratings check
|
||||
// If it has no ratings, use the US ratings
|
||||
var ratingsDictionary = GetParentalRatingsDictionary() ?? GetParentalRatingsDictionary("us");
|
||||
var ratingsDictionary = GetParentalRatingsDictionary();
|
||||
if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRatingScore? value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't find anything, check all ratings systems
|
||||
// If we don't find anything, check all ratings systems, starting with US
|
||||
if (_allParentalRatings.TryGetValue("us", out var usRatings) && usRatings.TryGetValue(rating, out var usValue))
|
||||
{
|
||||
return usValue;
|
||||
}
|
||||
|
||||
foreach (var dictionary in _allParentalRatings.Values)
|
||||
{
|
||||
if (dictionary.TryGetValue(rating, out var value))
|
||||
|
||||
@@ -272,6 +272,8 @@ namespace Emby.Server.Implementations.Playlists
|
||||
playlist.LinkedChildren = [.. playlist.LinkedChildren, .. childrenToAdd];
|
||||
}
|
||||
|
||||
playlist.DateLastMediaAdded = DateTime.UtcNow;
|
||||
|
||||
await UpdatePlaylistInternal(playlist).ConfigureAwait(false);
|
||||
|
||||
// Refresh playlist metadata
|
||||
|
||||
@@ -793,6 +793,16 @@ namespace Emby.Server.Implementations.Session
|
||||
PlaySessionId = info.PlaySessionId
|
||||
};
|
||||
|
||||
if (info.Item is not null)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"User {0} started playback of '{1}' ({2} {3})",
|
||||
session.UserName,
|
||||
info.Item.Name,
|
||||
session.Client,
|
||||
session.ApplicationVersion);
|
||||
}
|
||||
|
||||
await _eventManager.PublishAsync(eventArgs).ConfigureAwait(false);
|
||||
|
||||
// Nothing to save here
|
||||
@@ -1060,11 +1070,12 @@ namespace Emby.Server.Implementations.Session
|
||||
var msString = info.PositionTicks.HasValue ? (info.PositionTicks.Value / 10000).ToString(CultureInfo.InvariantCulture) : "unknown";
|
||||
|
||||
_logger.LogInformation(
|
||||
"Playback stopped reported by app {0} {1} playing {2}. Stopped at {3} ms",
|
||||
session.Client,
|
||||
session.ApplicationVersion,
|
||||
"User {0} stopped playback of '{1}' at {2}ms ({3} {4})",
|
||||
session.UserName,
|
||||
info.Item.Name,
|
||||
msString);
|
||||
msString,
|
||||
session.Client,
|
||||
session.ApplicationVersion);
|
||||
}
|
||||
|
||||
if (info.NowPlayingQueue is not null)
|
||||
@@ -1175,7 +1186,8 @@ namespace Emby.Server.Implementations.Session
|
||||
return session;
|
||||
}
|
||||
|
||||
private SessionInfoDto ToSessionInfoDto(SessionInfo sessionInfo)
|
||||
/// <inheritdoc />
|
||||
public SessionInfoDto ToSessionInfoDto(SessionInfo sessionInfo)
|
||||
{
|
||||
return new SessionInfoDto
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace Emby.Server.Implementations.Sorting
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Sorting
|
||||
ArgumentNullException.ThrowIfNull(x);
|
||||
ArgumentNullException.ThrowIfNull(y);
|
||||
|
||||
return AlphanumericComparator.CompareValues(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault());
|
||||
return CultureInfo.InvariantCulture.CompareInfo.Compare(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault(), CompareOptions.NumericOrdering);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Emby.Server.Implementations.TV
|
||||
items = items.Skip(query.StartIndex.Value);
|
||||
}
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
if (query.Limit.HasValue && query.Limit.Value > 0)
|
||||
{
|
||||
items = items.Take(query.Limit.Value);
|
||||
}
|
||||
|
||||
@@ -156,6 +156,11 @@ namespace Emby.Server.Implementations.Updates
|
||||
_logger.LogError(ex, "The URL configured for the plugin repository manifest URL is not valid: {Manifest}", manifest);
|
||||
return Array.Empty<PackageInfo>();
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
_logger.LogError(ex, "The URL scheme configured for the plugin repository is not supported: {Manifest}", manifest);
|
||||
return Array.Empty<PackageInfo>();
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest);
|
||||
@@ -223,15 +228,14 @@ namespace Emby.Server.Implementations.Updates
|
||||
Guid id = default,
|
||||
Version? specificVersion = null)
|
||||
{
|
||||
if (name is not null)
|
||||
{
|
||||
availablePackages = availablePackages.Where(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (!id.IsEmpty())
|
||||
{
|
||||
availablePackages = availablePackages.Where(x => x.Id.Equals(id));
|
||||
}
|
||||
else if (name is not null)
|
||||
{
|
||||
availablePackages = availablePackages.Where(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (specificVersion is not null)
|
||||
{
|
||||
@@ -558,7 +562,7 @@ namespace Emby.Server.Implementations.Updates
|
||||
}
|
||||
|
||||
stream.Position = 0;
|
||||
ZipFile.ExtractToDirectory(stream, targetDir, true);
|
||||
await ZipFile.ExtractToDirectoryAsync(stream, targetDir, true, cancellationToken);
|
||||
|
||||
// Ensure we create one or populate existing ones with missing data.
|
||||
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status).ConfigureAwait(false);
|
||||
|
||||
Reference in New Issue
Block a user