2
0
Эх сурвалжийг харах

Merge branch 'master' into usings

Bond-009 5 жил өмнө
parent
commit
ddd5d3aaec
86 өөрчлөгдсөн 549 нэмэгдсэн , 355 устгасан
  1. 1 1
      Emby.Naming/AudioBook/AudioBookFileInfo.cs
  2. 2 10
      Emby.Naming/AudioBook/AudioBookListResolver.cs
  3. 2 1
      Emby.Naming/Subtitles/SubtitleParser.cs
  4. 8 2
      Emby.Naming/TV/EpisodePathParser.cs
  5. 1 1
      Emby.Naming/TV/SeasonPathParserResult.cs
  6. 9 16
      Emby.Naming/Video/StackResolver.cs
  7. 3 1
      Emby.Naming/Video/VideoFileInfo.cs
  8. 7 17
      Emby.Naming/Video/VideoListResolver.cs
  9. 1 1
      Emby.Server.Implementations/ApplicationHost.cs
  10. 8 4
      Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs
  11. 2 2
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  12. 3 3
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  13. 0 1
      Emby.Server.Implementations/Localization/Core/af.json
  14. 4 5
      Emby.Server.Implementations/Localization/Core/ar.json
  15. 0 1
      Emby.Server.Implementations/Localization/Core/bg-BG.json
  16. 0 1
      Emby.Server.Implementations/Localization/Core/bn.json
  17. 0 1
      Emby.Server.Implementations/Localization/Core/ca.json
  18. 0 1
      Emby.Server.Implementations/Localization/Core/cs.json
  19. 0 1
      Emby.Server.Implementations/Localization/Core/da.json
  20. 25 4
      Emby.Server.Implementations/Localization/Core/de.json
  21. 0 1
      Emby.Server.Implementations/Localization/Core/el.json
  22. 0 1
      Emby.Server.Implementations/Localization/Core/en-GB.json
  23. 23 2
      Emby.Server.Implementations/Localization/Core/en-US.json
  24. 0 1
      Emby.Server.Implementations/Localization/Core/es-AR.json
  25. 0 1
      Emby.Server.Implementations/Localization/Core/es-MX.json
  26. 23 2
      Emby.Server.Implementations/Localization/Core/es.json
  27. 41 42
      Emby.Server.Implementations/Localization/Core/fa.json
  28. 0 1
      Emby.Server.Implementations/Localization/Core/fi.json
  29. 0 1
      Emby.Server.Implementations/Localization/Core/fil.json
  30. 0 1
      Emby.Server.Implementations/Localization/Core/fr-CA.json
  31. 0 1
      Emby.Server.Implementations/Localization/Core/fr.json
  32. 0 1
      Emby.Server.Implementations/Localization/Core/gsw.json
  33. 0 1
      Emby.Server.Implementations/Localization/Core/he.json
  34. 0 1
      Emby.Server.Implementations/Localization/Core/hr.json
  35. 0 1
      Emby.Server.Implementations/Localization/Core/hu.json
  36. 0 1
      Emby.Server.Implementations/Localization/Core/id.json
  37. 0 1
      Emby.Server.Implementations/Localization/Core/is.json
  38. 0 1
      Emby.Server.Implementations/Localization/Core/it.json
  39. 0 1
      Emby.Server.Implementations/Localization/Core/ja.json
  40. 0 1
      Emby.Server.Implementations/Localization/Core/kk.json
  41. 0 1
      Emby.Server.Implementations/Localization/Core/ko.json
  42. 0 1
      Emby.Server.Implementations/Localization/Core/lt-LT.json
  43. 0 1
      Emby.Server.Implementations/Localization/Core/lv.json
  44. 0 1
      Emby.Server.Implementations/Localization/Core/mk.json
  45. 0 1
      Emby.Server.Implementations/Localization/Core/ms.json
  46. 0 1
      Emby.Server.Implementations/Localization/Core/nb.json
  47. 0 1
      Emby.Server.Implementations/Localization/Core/nl.json
  48. 0 1
      Emby.Server.Implementations/Localization/Core/pl.json
  49. 0 1
      Emby.Server.Implementations/Localization/Core/pt-BR.json
  50. 0 1
      Emby.Server.Implementations/Localization/Core/pt-PT.json
  51. 0 1
      Emby.Server.Implementations/Localization/Core/pt.json
  52. 0 1
      Emby.Server.Implementations/Localization/Core/ro.json
  53. 0 1
      Emby.Server.Implementations/Localization/Core/ru.json
  54. 23 2
      Emby.Server.Implementations/Localization/Core/sk.json
  55. 0 1
      Emby.Server.Implementations/Localization/Core/sl-SI.json
  56. 0 1
      Emby.Server.Implementations/Localization/Core/sr.json
  57. 0 1
      Emby.Server.Implementations/Localization/Core/sv.json
  58. 0 1
      Emby.Server.Implementations/Localization/Core/tr.json
  59. 25 4
      Emby.Server.Implementations/Localization/Core/zh-CN.json
  60. 0 1
      Emby.Server.Implementations/Localization/Core/zh-HK.json
  61. 0 1
      Emby.Server.Implementations/Localization/Core/zh-TW.json
  62. 14 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
  63. 8 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  64. 7 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  65. 8 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
  66. 7 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
  67. 7 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
  68. 7 4
      Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
  69. 10 10
      Emby.Server.Implementations/Session/SessionManager.cs
  70. 1 1
      Jellyfin.Api/Jellyfin.Api.csproj
  71. 1 1
      Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
  72. 2 2
      Jellyfin.Server/Jellyfin.Server.csproj
  73. 30 22
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  74. 2 2
      MediaBrowser.Common/MediaBrowser.Common.csproj
  75. 2 2
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  76. 188 109
      MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
  77. 12 4
      MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
  78. 1 0
      MediaBrowser.Model/Configuration/EncodingOptions.cs
  79. 1 0
      MediaBrowser.Model/Entities/ChapterInfo.cs
  80. 6 0
      MediaBrowser.Model/Extensions/StringHelper.cs
  81. 3 3
      MediaBrowser.Model/MediaBrowser.Model.csproj
  82. 2 2
      MediaBrowser.Providers/MediaBrowser.Providers.csproj
  83. 8 4
      MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
  84. 5 1
      MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs
  85. 5 1
      MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs
  86. 1 1
      tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

+ 1 - 1
Emby.Naming/AudioBook/AudioBookFileInfo.cs

@@ -37,7 +37,7 @@ namespace Emby.Naming.AudioBook
         /// <value>The type.</value>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }
         public bool IsDirectory { get; set; }
 
 
-        /// <inheritdoc/>
+        /// <inheritdoc />
         public int CompareTo(AudioBookFileInfo other)
         public int CompareTo(AudioBookFileInfo other)
         {
         {
             if (ReferenceEquals(this, other))
             if (ReferenceEquals(this, other))

+ 2 - 10
Emby.Naming/AudioBook/AudioBookListResolver.cs

@@ -29,11 +29,7 @@ namespace Emby.Naming.AudioBook
             // Filter out all extras, otherwise they could cause stacks to not be resolved
             // Filter out all extras, otherwise they could cause stacks to not be resolved
             // See the unit test TestStackedWithTrailer
             // See the unit test TestStackedWithTrailer
             var metadata = audiobookFileInfos
             var metadata = audiobookFileInfos
-                .Select(i => new FileSystemMetadata
-                {
-                    FullName = i.Path,
-                    IsDirectory = i.IsDirectory
-                });
+                .Select(i => new FileSystemMetadata { FullName = i.Path, IsDirectory = i.IsDirectory });
 
 
             var stackResult = new StackResolver(_options)
             var stackResult = new StackResolver(_options)
                 .ResolveAudioBooks(metadata);
                 .ResolveAudioBooks(metadata);
@@ -42,11 +38,7 @@ namespace Emby.Naming.AudioBook
             {
             {
                 var stackFiles = stack.Files.Select(i => audioBookResolver.Resolve(i, stack.IsDirectoryStack)).ToList();
                 var stackFiles = stack.Files.Select(i => audioBookResolver.Resolve(i, stack.IsDirectoryStack)).ToList();
                 stackFiles.Sort();
                 stackFiles.Sort();
-                var info = new AudioBookInfo
-                {
-                    Files = stackFiles,
-                    Name = stack.Name
-                };
+                var info = new AudioBookInfo { Files = stackFiles, Name = stack.Name };
 
 
                 yield return info;
                 yield return info;
             }
             }

+ 2 - 1
Emby.Naming/Subtitles/SubtitleParser.cs

@@ -37,7 +37,8 @@ namespace Emby.Naming.Subtitles
                 IsForced = _options.SubtitleForcedFlags.Any(i => flags.Contains(i, StringComparer.OrdinalIgnoreCase))
                 IsForced = _options.SubtitleForcedFlags.Any(i => flags.Contains(i, StringComparer.OrdinalIgnoreCase))
             };
             };
 
 
-            var parts = flags.Where(i => !_options.SubtitleDefaultFlags.Contains(i, StringComparer.OrdinalIgnoreCase) && !_options.SubtitleForcedFlags.Contains(i, StringComparer.OrdinalIgnoreCase))
+            var parts = flags.Where(i => !_options.SubtitleDefaultFlags.Contains(i, StringComparer.OrdinalIgnoreCase)
+                && !_options.SubtitleForcedFlags.Contains(i, StringComparer.OrdinalIgnoreCase))
                 .ToList();
                 .ToList();
 
 
             // Should have a name, language and file extension
             // Should have a name, language and file extension

+ 8 - 2
Emby.Naming/TV/EpisodePathParser.cs

@@ -18,7 +18,13 @@ namespace Emby.Naming.TV
             _options = options;
             _options = options;
         }
         }
 
 
-        public EpisodePathParserResult Parse(string path, bool isDirectory, bool? isNamed = null, bool? isOptimistic = null, bool? supportsAbsoluteNumbers = null, bool fillExtendedInfo = true)
+        public EpisodePathParserResult Parse(
+            string path,
+            bool isDirectory,
+            bool? isNamed = null,
+            bool? isOptimistic = null,
+            bool? supportsAbsoluteNumbers = null,
+            bool fillExtendedInfo = true)
         {
         {
             // Added to be able to use regex patterns which require a file extension.
             // Added to be able to use regex patterns which require a file extension.
             // There were no failed tests without this block, but to be safe, we can keep it until
             // There were no failed tests without this block, but to be safe, we can keep it until
@@ -64,7 +70,7 @@ namespace Emby.Naming.TV
                 {
                 {
                     result.SeriesName = result.SeriesName
                     result.SeriesName = result.SeriesName
                         .Trim()
                         .Trim()
-                        .Trim(new[] { '_', '.', '-' })
+                        .Trim('_', '.', '-')
                         .Trim();
                         .Trim();
                 }
                 }
             }
             }

+ 1 - 1
Emby.Naming/TV/SeasonPathParserResult.cs

@@ -11,7 +11,7 @@ namespace Emby.Naming.TV
         public int? SeasonNumber { get; set; }
         public int? SeasonNumber { get; set; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets a value indicating whether this <see cref="SeasonPathParserResult"/> is success.
+        /// Gets or sets a value indicating whether this <see cref="SeasonPathParserResult" /> is success.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
         public bool Success { get; set; }
         public bool Success { get; set; }

+ 9 - 16
Emby.Naming/Video/StackResolver.cs

@@ -21,31 +21,24 @@ namespace Emby.Naming.Video
 
 
         public IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files)
         public IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files)
         {
         {
-            return Resolve(files.Select(i => new FileSystemMetadata
-            {
-                FullName = i,
-                IsDirectory = true
-            }));
+            return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true }));
         }
         }
 
 
         public IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files)
         public IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files)
         {
         {
-            return Resolve(files.Select(i => new FileSystemMetadata
-            {
-                FullName = i,
-                IsDirectory = false
-            }));
+            return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false }));
         }
         }
 
 
         public IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<FileSystemMetadata> files)
         public IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<FileSystemMetadata> files)
         {
         {
-            foreach (var directory in files.GroupBy(file => file.IsDirectory ? file.FullName : Path.GetDirectoryName(file.FullName)))
+            var groupedDirectoryFiles = files.GroupBy(file =>
+                file.IsDirectory
+                    ? file.FullName
+                    : Path.GetDirectoryName(file.FullName));
+
+            foreach (var directory in groupedDirectoryFiles)
             {
             {
-                var stack = new FileStack()
-                {
-                    Name = Path.GetFileName(directory.Key),
-                    IsDirectoryStack = false
-                };
+                var stack = new FileStack { Name = Path.GetFileName(directory.Key), IsDirectoryStack = false };
                 foreach (var file in directory)
                 foreach (var file in directory)
                 {
                 {
                     if (file.IsDirectory)
                     if (file.IsDirectory)

+ 3 - 1
Emby.Naming/Video/VideoFileInfo.cs

@@ -77,7 +77,9 @@ namespace Emby.Naming.Video
         /// Gets the file name without extension.
         /// Gets the file name without extension.
         /// </summary>
         /// </summary>
         /// <value>The file name without extension.</value>
         /// <value>The file name without extension.</value>
-        public string FileNameWithoutExtension => !IsDirectory ? System.IO.Path.GetFileNameWithoutExtension(Path) : System.IO.Path.GetFileName(Path);
+        public string FileNameWithoutExtension => !IsDirectory
+            ? System.IO.Path.GetFileNameWithoutExtension(Path)
+            : System.IO.Path.GetFileName(Path);
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public override string ToString()
         public override string ToString()

+ 7 - 17
Emby.Naming/Video/VideoListResolver.cs

@@ -33,11 +33,7 @@ namespace Emby.Naming.Video
             // See the unit test TestStackedWithTrailer
             // See the unit test TestStackedWithTrailer
             var nonExtras = videoInfos
             var nonExtras = videoInfos
                 .Where(i => i.ExtraType == null)
                 .Where(i => i.ExtraType == null)
-                .Select(i => new FileSystemMetadata
-                {
-                    FullName = i.Path,
-                    IsDirectory = i.IsDirectory
-                });
+                .Select(i => new FileSystemMetadata { FullName = i.Path, IsDirectory = i.IsDirectory });
 
 
             var stackResult = new StackResolver(_options)
             var stackResult = new StackResolver(_options)
                 .Resolve(nonExtras).ToList();
                 .Resolve(nonExtras).ToList();
@@ -57,11 +53,7 @@ namespace Emby.Naming.Video
 
 
                 info.Year = info.Files[0].Year;
                 info.Year = info.Files[0].Year;
 
 
-                var extraBaseNames = new List<string>
-                {
-                    stack.Name,
-                    Path.GetFileNameWithoutExtension(stack.Files[0])
-                };
+                var extraBaseNames = new List<string> { stack.Name, Path.GetFileNameWithoutExtension(stack.Files[0]) };
 
 
                 var extras = GetExtras(remainingFiles, extraBaseNames);
                 var extras = GetExtras(remainingFiles, extraBaseNames);
 
 
@@ -83,10 +75,7 @@ namespace Emby.Naming.Video
 
 
             foreach (var media in standaloneMedia)
             foreach (var media in standaloneMedia)
             {
             {
-                var info = new VideoInfo(media.Name)
-                {
-                    Files = new List<VideoFileInfo> { media }
-                };
+                var info = new VideoInfo(media.Name) { Files = new List<VideoFileInfo> { media } };
 
 
                 info.Year = info.Files[0].Year;
                 info.Year = info.Files[0].Year;
 
 
@@ -222,8 +211,8 @@ namespace Emby.Naming.Video
             {
             {
                 testFilename = testFilename.Substring(folderName.Length).Trim();
                 testFilename = testFilename.Substring(folderName.Length).Trim();
                 return string.IsNullOrEmpty(testFilename)
                 return string.IsNullOrEmpty(testFilename)
-                    || testFilename[0] == '-'
-                    || string.IsNullOrWhiteSpace(Regex.Replace(testFilename, @"\[([^]]*)\]", string.Empty));
+                   || testFilename[0] == '-'
+                   || string.IsNullOrWhiteSpace(Regex.Replace(testFilename, @"\[([^]]*)\]", string.Empty));
             }
             }
 
 
             return false;
             return false;
@@ -239,7 +228,8 @@ namespace Emby.Naming.Video
 
 
             return remainingFiles
             return remainingFiles
                 .Where(i => i.ExtraType == null)
                 .Where(i => i.ExtraType == null)
-                .Where(i => baseNames.Any(b => i.FileNameWithoutExtension.StartsWith(b, StringComparison.OrdinalIgnoreCase)))
+                .Where(i => baseNames.Any(b =>
+                    i.FileNameWithoutExtension.StartsWith(b, StringComparison.OrdinalIgnoreCase)))
                 .ToList();
                 .ToList();
         }
         }
     }
     }

+ 1 - 1
Emby.Server.Implementations/ApplicationHost.cs

@@ -1803,7 +1803,7 @@ namespace Emby.Server.Implementations
                 }
                 }
 
 
                 _userRepository?.Dispose();
                 _userRepository?.Dispose();
-                _displayPreferencesRepository.Dispose();
+                _displayPreferencesRepository?.Dispose();
             }
             }
 
 
             _userRepository = null;
             _userRepository = null;

+ 8 - 4
Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs

@@ -9,6 +9,7 @@ using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.Channels
 namespace Emby.Server.Implementations.Channels
 {
 {
@@ -18,27 +19,30 @@ namespace Emby.Server.Implementations.Channels
         private readonly IUserManager _userManager;
         private readonly IUserManager _userManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
+        private readonly ILocalizationManager _localization;
 
 
         public RefreshChannelsScheduledTask(
         public RefreshChannelsScheduledTask(
             IChannelManager channelManager,
             IChannelManager channelManager,
             IUserManager userManager,
             IUserManager userManager,
             ILogger<RefreshChannelsScheduledTask> logger,
             ILogger<RefreshChannelsScheduledTask> logger,
-            ILibraryManager libraryManager)
+            ILibraryManager libraryManager,
+            ILocalizationManager localization)
         {
         {
             _channelManager = channelManager;
             _channelManager = channelManager;
             _userManager = userManager;
             _userManager = userManager;
             _logger = logger;
             _logger = logger;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
+            _localization = localization;
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Name => "Refresh Channels";
+        public string Name => _localization.GetLocalizedString("TasksRefreshChannels");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Description => "Refreshes internet channel information.";
+        public string Description => _localization.GetLocalizedString("TasksRefreshChannelsDescription");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Category => "Internet Channels";
+        public string Category => _localization.GetLocalizedString("TasksChannelsCategory");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public bool IsHidden => ((ChannelManager)_channelManager).Channels.Length == 0;
         public bool IsHidden => ((ChannelManager)_channelManager).Channels.Length == 0;

+ 2 - 2
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -6289,8 +6289,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                         statement.TryBind("@Codec" + index, attachment.Codec);
                         statement.TryBind("@Codec" + index, attachment.Codec);
                         statement.TryBind("@CodecTag" + index, attachment.CodecTag);
                         statement.TryBind("@CodecTag" + index, attachment.CodecTag);
                         statement.TryBind("@Comment" + index, attachment.Comment);
                         statement.TryBind("@Comment" + index, attachment.Comment);
-                        statement.TryBind("@FileName" + index, attachment.FileName);
-                        statement.TryBind("@MimeType" + index, attachment.MimeType);
+                        statement.TryBind("@Filename" + index, attachment.FileName);
+                        statement.TryBind("@MIMEType" + index, attachment.MimeType);
                     }
                     }
 
 
                     statement.Reset();
                     statement.Reset();

+ 3 - 3
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -29,9 +29,9 @@
     <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
     <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
-    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
     <PackageReference Include="Mono.Nat" Version="2.0.0" />
     <PackageReference Include="Mono.Nat" Version="2.0.0" />
     <PackageReference Include="ServiceStack.Text.Core" Version="5.8.0" />
     <PackageReference Include="ServiceStack.Text.Core" Version="5.8.0" />
     <PackageReference Include="sharpcompress" Version="0.24.0" />
     <PackageReference Include="sharpcompress" Version="0.24.0" />

+ 0 - 1
Emby.Server.Implementations/Localization/Core/af.json

@@ -41,7 +41,6 @@
     "User": "Gebruiker",
     "User": "Gebruiker",
     "TvShows": "TV Programme",
     "TvShows": "TV Programme",
     "System": "Stelsel",
     "System": "Stelsel",
-    "SubtitlesDownloadedForItem": "Ondertitels afgelaai vir {0}",
     "SubtitleDownloadFailureFromForItem": "Ondertitels het misluk om af te laai van {0} vir {1}",
     "SubtitleDownloadFailureFromForItem": "Ondertitels het misluk om af te laai van {0} vir {1}",
     "StartupEmbyServerIsLoading": "Jellyfin Bediener is besig om te laai. Probeer weer in 'n kort tyd.",
     "StartupEmbyServerIsLoading": "Jellyfin Bediener is besig om te laai. Probeer weer in 'n kort tyd.",
     "ServerNameNeedsToBeRestarted": "{0} moet herbegin word",
     "ServerNameNeedsToBeRestarted": "{0} moet herbegin word",

+ 4 - 5
Emby.Server.Implementations/Localization/Core/ar.json

@@ -4,10 +4,10 @@
     "Application": "تطبيق",
     "Application": "تطبيق",
     "Artists": "الفنانين",
     "Artists": "الفنانين",
     "AuthenticationSucceededWithUserName": "{0} سجل الدخول بنجاح",
     "AuthenticationSucceededWithUserName": "{0} سجل الدخول بنجاح",
-    "Books": "كتب",
+    "Books": "الكتب",
     "CameraImageUploadedFrom": "صورة كاميرا جديدة تم رفعها من {0}",
     "CameraImageUploadedFrom": "صورة كاميرا جديدة تم رفعها من {0}",
     "Channels": "القنوات",
     "Channels": "القنوات",
-    "ChapterNameValue": "فصل {0}",
+    "ChapterNameValue": "الفصل {0}",
     "Collections": "مجموعات",
     "Collections": "مجموعات",
     "DeviceOfflineWithName": "قُطِع الاتصال بـ{0}",
     "DeviceOfflineWithName": "قُطِع الاتصال بـ{0}",
     "DeviceOnlineWithName": "{0} متصل",
     "DeviceOnlineWithName": "{0} متصل",
@@ -51,8 +51,8 @@
     "NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
     "NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
     "NotificationOptionCameraImageUploaded": "تم رفع صورة الكاميرا",
     "NotificationOptionCameraImageUploaded": "تم رفع صورة الكاميرا",
     "NotificationOptionInstallationFailed": "فشل في التثبيت",
     "NotificationOptionInstallationFailed": "فشل في التثبيت",
-    "NotificationOptionNewLibraryContent": "أُضِيفَ محتوى جديد",
-    "NotificationOptionPluginError": "فشل في الـPlugin",
+    "NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
+    "NotificationOptionPluginError": "فشل في البرنامج المضاف",
     "NotificationOptionPluginInstalled": "تم تثبيت الملحق",
     "NotificationOptionPluginInstalled": "تم تثبيت الملحق",
     "NotificationOptionPluginUninstalled": "تمت إزالة الملحق",
     "NotificationOptionPluginUninstalled": "تمت إزالة الملحق",
     "NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق",
     "NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق",
@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "سيرفر Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.",
     "StartupEmbyServerIsLoading": "سيرفر Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.",
     "SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}",
     "SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}",
     "SubtitleDownloadFailureFromForItem": "الترجمات فشلت في التحميل من {0} الى {1}",
     "SubtitleDownloadFailureFromForItem": "الترجمات فشلت في التحميل من {0} الى {1}",
-    "SubtitlesDownloadedForItem": "تم تحميل الترجمات الى {0}",
     "Sync": "مزامنة",
     "Sync": "مزامنة",
     "System": "النظام",
     "System": "النظام",
     "TvShows": "البرامج التلفزيونية",
     "TvShows": "البرامج التلفزيونية",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/bg-BG.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
     "StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
     "SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}",
     "SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}",
     "SubtitleDownloadFailureFromForItem": "Поднадписите за {1} от {0} не можаха да се изтеглят",
     "SubtitleDownloadFailureFromForItem": "Поднадписите за {1} от {0} не можаха да се изтеглят",
-    "SubtitlesDownloadedForItem": "Изтеглени са субтитри за {0}",
     "Sync": "Синхронизиране",
     "Sync": "Синхронизиране",
     "System": "Система",
     "System": "Система",
     "TvShows": "Телевизионни сериали",
     "TvShows": "Телевизионни сериали",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/bn.json

@@ -38,7 +38,6 @@
     "TvShows": "টিভি শোগুলো",
     "TvShows": "টিভি শোগুলো",
     "System": "সিস্টেম",
     "System": "সিস্টেম",
     "Sync": "সিংক",
     "Sync": "সিংক",
-    "SubtitlesDownloadedForItem": "{0} এর জন্য সাবটাইটেল ডাউনলোড করা হয়েছে",
     "SubtitleDownloadFailureFromForItem": "{2} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ",
     "SubtitleDownloadFailureFromForItem": "{2} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ",
     "StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
     "StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
     "Songs": "গানগুলো",
     "Songs": "গানগুলো",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ca.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "El Servidor d'Jellyfin est&agrave; carregant. Si et plau, prova de nou en breus.",
     "StartupEmbyServerIsLoading": "El Servidor d'Jellyfin est&agrave; carregant. Si et plau, prova de nou en breus.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Els subtítols no s'han pogut baixar de {0} per {1}",
     "SubtitleDownloadFailureFromForItem": "Els subtítols no s'han pogut baixar de {0} per {1}",
-    "SubtitlesDownloadedForItem": "Subtítols descarregats per a {0}",
     "Sync": "Sincronitzar",
     "Sync": "Sincronitzar",
     "System": "System",
     "System": "System",
     "TvShows": "Espectacles de TV",
     "TvShows": "Espectacles de TV",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/cs.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server je spouštěn. Zkuste to prosím v brzké době znovu.",
     "StartupEmbyServerIsLoading": "Jellyfin Server je spouštěn. Zkuste to prosím v brzké době znovu.",
     "SubtitleDownloadFailureForItem": "Stahování titulků selhalo pro {0}",
     "SubtitleDownloadFailureForItem": "Stahování titulků selhalo pro {0}",
     "SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
     "SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
-    "SubtitlesDownloadedForItem": "Staženy titulky pro {0}",
     "Sync": "Synchronizace",
     "Sync": "Synchronizace",
     "System": "Systém",
     "System": "Systém",
     "TvShows": "TV seriály",
     "TvShows": "TV seriály",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/da.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server er i gang med at starte op. Prøv venligst igen om lidt.",
     "StartupEmbyServerIsLoading": "Jellyfin Server er i gang med at starte op. Prøv venligst igen om lidt.",
     "SubtitleDownloadFailureForItem": "Fejlet i download af undertekster for {0}",
     "SubtitleDownloadFailureForItem": "Fejlet i download af undertekster for {0}",
     "SubtitleDownloadFailureFromForItem": "Undertekster kunne ikke downloades fra {0} til {1}",
     "SubtitleDownloadFailureFromForItem": "Undertekster kunne ikke downloades fra {0} til {1}",
-    "SubtitlesDownloadedForItem": "Undertekster downloadet for {0}",
     "Sync": "Synk",
     "Sync": "Synk",
     "System": "System",
     "System": "System",
     "TvShows": "TV serier",
     "TvShows": "TV serier",

+ 25 - 4
Emby.Server.Implementations/Localization/Core/de.json

@@ -1,6 +1,6 @@
 {
 {
     "Albums": "Alben",
     "Albums": "Alben",
-    "AppDeviceValues": "Anw: {0}, Gerät: {1}",
+    "AppDeviceValues": "App: {0}, Gerät: {1}",
     "Application": "Anwendung",
     "Application": "Anwendung",
     "Artists": "Interpreten",
     "Artists": "Interpreten",
     "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich authentifziert",
     "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich authentifziert",
@@ -50,7 +50,7 @@
     "NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
     "NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
     "NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
     "NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
     "NotificationOptionCameraImageUploaded": "Foto hochgeladen",
     "NotificationOptionCameraImageUploaded": "Foto hochgeladen",
-    "NotificationOptionInstallationFailed": "Fehler bei der Installation",
+    "NotificationOptionInstallationFailed": "Installation fehlgeschlagen",
     "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
     "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
     "NotificationOptionPluginError": "Plugin-Fehler",
     "NotificationOptionPluginError": "Plugin-Fehler",
     "NotificationOptionPluginInstalled": "Plugin installiert",
     "NotificationOptionPluginInstalled": "Plugin installiert",
@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin-Server startet, bitte versuche es gleich noch einmal.",
     "StartupEmbyServerIsLoading": "Jellyfin-Server startet, bitte versuche es gleich noch einmal.",
     "SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
     "SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
     "SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
     "SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
-    "SubtitlesDownloadedForItem": "Untertitel heruntergeladen für {0}",
     "Sync": "Synchronisation",
     "Sync": "Synchronisation",
     "System": "System",
     "System": "System",
     "TvShows": "TV-Sendungen",
     "TvShows": "TV-Sendungen",
@@ -93,5 +92,27 @@
     "UserStoppedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} beendet",
     "UserStoppedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} beendet",
     "ValueHasBeenAddedToLibrary": "{0} wurde deiner Bibliothek hinzugefügt",
     "ValueHasBeenAddedToLibrary": "{0} wurde deiner Bibliothek hinzugefügt",
     "ValueSpecialEpisodeName": "Extra - {0}",
     "ValueSpecialEpisodeName": "Extra - {0}",
-    "VersionNumber": "Version {0}"
+    "VersionNumber": "Version {0}",
+    "TaskDownloadMissingSubtitlesDescription": "Durchsucht das Internet nach fehlenden Untertiteln, basierend auf den Meta Einstellungen.",
+    "TaskDownloadMissingSubtitles": "Lade fehlende Untertitel herunter",
+    "TaskRefreshChannelsDescription": "Erneuere Internet Kanal Informationen.",
+    "TaskRefreshChannels": "Erneuere Kanäle",
+    "TaskCleanTranscodeDescription": "Löscht Transkodierdateien welche älter als ein Tag sind.",
+    "TaskCleanTranscode": "Lösche Transkodier Pfad",
+    "TaskUpdatePluginsDescription": "Läd Updates für Plugins herunter, welche dazu eingestellt sind automatisch zu updaten und installiert sie.",
+    "TaskUpdatePlugins": "Update Plugins",
+    "TaskRefreshPeopleDescription": "Erneuert Metadaten für Schausteller und Regisseure in deinen Bibliotheken.",
+    "TaskRefreshPeople": "Erneuere Schausteller",
+    "TaskCleanLogsDescription": "Lösche Log Datein die älter als {0} Tage sind.",
+    "TaskCleanLogs": "Lösche Log Pfad",
+    "TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.",
+    "TaskRefreshLibrary": "Scanne alle Bibliotheken",
+    "TaskRefreshChapterImagesDescription": "Kreiert Vorschaubilder für Videos welche Kapitel haben.",
+    "TaskRefreshChapterImages": "Extrahiert Kapitel-Bilder",
+    "TaskCleanCacheDescription": "Löscht Zwischenspeicherdatein die nicht länger von System gebraucht werden.",
+    "TaskCleanCache": "Leere Cache Pfad",
+    "TasksChannelsCategory": "Internet Kanäle",
+    "TasksApplicationCategory": "Anwendung",
+    "TasksLibraryCategory": "Bibliothek",
+    "TasksMaintenanceCategory": "Wartung"
 }
 }

+ 0 - 1
Emby.Server.Implementations/Localization/Core/el.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Ο Jellyfin Server φορτώνει. Παρακαλώ δοκιμάστε σε λίγο.",
     "StartupEmbyServerIsLoading": "Ο Jellyfin Server φορτώνει. Παρακαλώ δοκιμάστε σε λίγο.",
     "SubtitleDownloadFailureForItem": "Οι υπότιτλοι απέτυχαν να κατέβουν για {0}",
     "SubtitleDownloadFailureForItem": "Οι υπότιτλοι απέτυχαν να κατέβουν για {0}",
     "SubtitleDownloadFailureFromForItem": "Αποτυχίες μεταφόρτωσης υποτίτλων από {0} για {1}",
     "SubtitleDownloadFailureFromForItem": "Αποτυχίες μεταφόρτωσης υποτίτλων από {0} για {1}",
-    "SubtitlesDownloadedForItem": "Οι υπότιτλοι κατέβηκαν για {0}",
     "Sync": "Συγχρονισμός",
     "Sync": "Συγχρονισμός",
     "System": "Σύστημα",
     "System": "Σύστημα",
     "TvShows": "Τηλεοπτικές Σειρές",
     "TvShows": "Τηλεοπτικές Σειρές",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/en-GB.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
     "Sync": "Sync",
     "Sync": "Sync",
     "System": "System",
     "System": "System",
     "TvShows": "TV Shows",
     "TvShows": "TV Shows",

+ 23 - 2
Emby.Server.Implementations/Localization/Core/en-US.json

@@ -75,7 +75,6 @@
     "Songs": "Songs",
     "Songs": "Songs",
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
     "Sync": "Sync",
     "Sync": "Sync",
     "System": "System",
     "System": "System",
     "TvShows": "TV Shows",
     "TvShows": "TV Shows",
@@ -92,5 +91,27 @@
     "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
     "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
     "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
     "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
     "ValueSpecialEpisodeName": "Special - {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
-    "VersionNumber": "Version {0}"
+    "VersionNumber": "Version {0}",
+    "TasksMaintenanceCategory": "Maintenance",
+    "TasksLibraryCategory": "Library",
+    "TasksApplicationCategory": "Application",
+    "TasksChannelsCategory": "Internet Channels",
+    "TaskCleanCache": "Clean Cache Directory",
+    "TaskCleanCacheDescription": "Deletes cache files no longer needed by the system.",
+    "TaskRefreshChapterImages": "Extract Chapter Images",
+    "TaskRefreshChapterImagesDescription": "Creates thumbnails for videos that have chapters.",
+    "TaskRefreshLibrary": "Scan Media Library",
+    "TaskRefreshLibraryDescription": "Scans your media library for new files and refreshes metadata.",
+    "TaskCleanLogs": "Clean Log Directory",
+    "TaskCleanLogsDescription": "Deletes log files that are more than {0} days old.",
+    "TaskRefreshPeople": "Refresh People",
+    "TaskRefreshPeopleDescription": "Updates metadata for actors and directors in your media library.",
+    "TaskUpdatePlugins": "Update Plugins",
+    "TaskUpdatePluginsDescription": "Downloads and installs updates for plugins that are configured to update automatically.",
+    "TaskCleanTranscode": "Clean Transcode Directory",
+    "TaskCleanTranscodeDescription": "Deletes transcode files more than one day old.",
+    "TaskRefreshChannels": "Refresh Channels",
+    "TaskRefreshChannelsDescription": "Refreshes internet channel information.",
+    "TaskDownloadMissingSubtitles": "Download missing subtitles",
+    "TaskDownloadMissingSubtitlesDescription": "Searches the internet for missing subtitles based on metadata configuration."
 }
 }

+ 0 - 1
Emby.Server.Implementations/Localization/Core/es-AR.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
-    "SubtitlesDownloadedForItem": "Descargar subtítulos para {0}",
     "Sync": "Sincronizar",
     "Sync": "Sincronizar",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Series de TV",
     "TvShows": "Series de TV",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/es-MX.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "El servidor Jellyfin esta cargando. Por favor intente de nuevo dentro de poco.",
     "StartupEmbyServerIsLoading": "El servidor Jellyfin esta cargando. Por favor intente de nuevo dentro de poco.",
     "SubtitleDownloadFailureForItem": "Falló la descarga de subtítulos para {0}",
     "SubtitleDownloadFailureForItem": "Falló la descarga de subtítulos para {0}",
     "SubtitleDownloadFailureFromForItem": "Falló la descarga de subtitulos desde {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Falló la descarga de subtitulos desde {0} para {1}",
-    "SubtitlesDownloadedForItem": "Subtítulos descargados para {0}",
     "Sync": "Sincronizar",
     "Sync": "Sincronizar",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Programas de TV",
     "TvShows": "Programas de TV",

+ 23 - 2
Emby.Server.Implementations/Localization/Core/es.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
     "SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
     "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
-    "SubtitlesDownloadedForItem": "Descargar subtítulos para {0}",
     "Sync": "Sincronizar",
     "Sync": "Sincronizar",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Programas de televisión",
     "TvShows": "Programas de televisión",
@@ -93,5 +92,27 @@
     "UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
     "UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
     "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia",
     "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia",
     "ValueSpecialEpisodeName": "Especial - {0}",
     "ValueSpecialEpisodeName": "Especial - {0}",
-    "VersionNumber": "Versión {0}"
+    "VersionNumber": "Versión {0}",
+    "TasksMaintenanceCategory": "Mantenimiento",
+    "TasksLibraryCategory": "Librería",
+    "TasksApplicationCategory": "Aplicación",
+    "TasksChannelsCategory": "Canales de internet",
+    "TaskCleanCache": "Eliminar archivos temporales",
+    "TaskCleanCacheDescription": "Elimina los archivos temporales que ya no son necesarios para el servidor.",
+    "TaskRefreshChapterImages": "Extraer imágenes de los capítulos",
+    "TaskRefreshChapterImagesDescription": "Crea las miniaturas de los vídeos que tengan capítulos.",
+    "TaskRefreshLibrary": "Escanear la biblioteca",
+    "TaskRefreshLibraryDescription": "Añade los archivos que se hayan añadido a la biblioteca y actualiza las etiquetas de los ya presentes.",
+    "TaskCleanLogs": "Limpiar registros",
+    "TaskCleanLogsDescription": "Elimina los archivos de registro que tengan más de {0} días.",
+    "TaskRefreshPeople": "Actualizar personas",
+    "TaskRefreshPeopleDescription": "Actualiza las etiquetas de los intérpretes y directores presentes en tus bibliotecas.",
+    "TaskUpdatePlugins": "Actualizar extensiones",
+    "TaskUpdatePluginsDescription": "Actualiza las extensiones que están configuradas para actualizarse automáticamente.",
+    "TaskCleanTranscode": "Limpiar las transcodificaciones",
+    "TaskCleanTranscodeDescription": "Elimina los archivos temporales de transcodificación anteriores a un día de antigüedad.",
+    "TaskRefreshChannels": "Actualizar canales",
+    "TaskRefreshChannelsDescription": "Actualiza la información de los canales de internet.",
+    "TaskDownloadMissingSubtitles": "Descargar los subtítulos que faltan",
+    "TaskDownloadMissingSubtitlesDescription": "Busca en internet los subtítulos que falten en el contenido de tus bibliotecas, basándose en la configuración de los metadatos."
 }
 }

+ 41 - 42
Emby.Server.Implementations/Localization/Core/fa.json

@@ -1,56 +1,56 @@
 {
 {
-    "Albums": "آلبوم ها",
+    "Albums": "آلبومها",
     "AppDeviceValues": "برنامه: {0} ، دستگاه: {1}",
     "AppDeviceValues": "برنامه: {0} ، دستگاه: {1}",
     "Application": "برنامه",
     "Application": "برنامه",
     "Artists": "هنرمندان",
     "Artists": "هنرمندان",
     "AuthenticationSucceededWithUserName": "{0} با موفقیت تایید اعتبار شد",
     "AuthenticationSucceededWithUserName": "{0} با موفقیت تایید اعتبار شد",
-    "Books": "کتاب ها",
-    "CameraImageUploadedFrom": "یک عکس جدید از دوربین ارسال شده {0}",
-    "Channels": "کانال ها",
-    "ChapterNameValue": "فصل {0}",
-    "Collections": "کلکسیون ها",
+    "Books": "کتابها",
+    "CameraImageUploadedFrom": "یک عکس جدید از دوربین ارسال شده است {0}",
+    "Channels": "کانالها",
+    "ChapterNameValue": "قسمت {0}",
+    "Collections": "مجموعه‌ها",
     "DeviceOfflineWithName": "ارتباط {0} قطع شد",
     "DeviceOfflineWithName": "ارتباط {0} قطع شد",
-    "DeviceOnlineWithName": "{0} متصل شده",
+    "DeviceOnlineWithName": "{0} متصل شد",
     "FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود",
     "FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود",
-    "Favorites": "مورد علاقه ها",
-    "Folders": "پوشه ها",
+    "Favorites": "مورد علاقهها",
+    "Folders": "پوشهها",
     "Genres": "ژانرها",
     "Genres": "ژانرها",
     "HeaderAlbumArtists": "هنرمندان آلبوم",
     "HeaderAlbumArtists": "هنرمندان آلبوم",
     "HeaderCameraUploads": "آپلودهای دوربین",
     "HeaderCameraUploads": "آپلودهای دوربین",
     "HeaderContinueWatching": "ادامه تماشا",
     "HeaderContinueWatching": "ادامه تماشا",
-    "HeaderFavoriteAlbums": "آلبوم های مورد علاقه",
+    "HeaderFavoriteAlbums": "آلبومهای مورد علاقه",
     "HeaderFavoriteArtists": "هنرمندان مورد علاقه",
     "HeaderFavoriteArtists": "هنرمندان مورد علاقه",
-    "HeaderFavoriteEpisodes": "قسمت های مورد علاقه",
-    "HeaderFavoriteShows": "سریال های مورد علاقه",
-    "HeaderFavoriteSongs": "آهنگ های مورد علاقه",
+    "HeaderFavoriteEpisodes": "قسمتهای مورد علاقه",
+    "HeaderFavoriteShows": "سریالهای مورد علاقه",
+    "HeaderFavoriteSongs": "آهنگهای مورد علاقه",
     "HeaderLiveTV": "پخش زنده تلویزیون",
     "HeaderLiveTV": "پخش زنده تلویزیون",
-    "HeaderNextUp": "بعدی چیه",
-    "HeaderRecordingGroups": "گروه های ضبط",
+    "HeaderNextUp": "قسمت بعدی",
+    "HeaderRecordingGroups": "گروههای ضبط",
     "HomeVideos": "ویدیوهای خانگی",
     "HomeVideos": "ویدیوهای خانگی",
     "Inherit": "به ارث برده",
     "Inherit": "به ارث برده",
     "ItemAddedWithName": "{0} به کتابخانه افزوده شد",
     "ItemAddedWithName": "{0} به کتابخانه افزوده شد",
     "ItemRemovedWithName": "{0} از کتابخانه حذف شد",
     "ItemRemovedWithName": "{0} از کتابخانه حذف شد",
     "LabelIpAddressValue": "آدرس آی پی: {0}",
     "LabelIpAddressValue": "آدرس آی پی: {0}",
     "LabelRunningTimeValue": "زمان اجرا: {0}",
     "LabelRunningTimeValue": "زمان اجرا: {0}",
-    "Latest": "آخرین",
+    "Latest": "جدیدترین‌ها",
     "MessageApplicationUpdated": "سرور Jellyfin بروزرسانی شد",
     "MessageApplicationUpdated": "سرور Jellyfin بروزرسانی شد",
-    "MessageApplicationUpdatedTo": "سرور جلیفین آپدیت شده به نسخه {0}",
+    "MessageApplicationUpdatedTo": "سرور Jellyfin به نسخه {0} بروزرسانی شد",
     "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور  بروزرسانی شد",
     "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور  بروزرسانی شد",
     "MessageServerConfigurationUpdated": "پیکربندی سرور بروزرسانی شد",
     "MessageServerConfigurationUpdated": "پیکربندی سرور بروزرسانی شد",
-    "MixedContent": "محتوای درهم",
-    "Movies": "فیلم های سینمایی",
+    "MixedContent": "محتوای مخلوط",
+    "Movies": "فیلم‌ها",
     "Music": "موسیقی",
     "Music": "موسیقی",
     "MusicVideos": "موزیک ویدیوها",
     "MusicVideos": "موزیک ویدیوها",
-    "NameInstallFailed": "{0} نصب با مشکل مواجه شده",
+    "NameInstallFailed": "{0} نصب با مشکل مواجه شد",
     "NameSeasonNumber": "فصل {0}",
     "NameSeasonNumber": "فصل {0}",
-    "NameSeasonUnknown": "فصل های ناشناخته",
-    "NewVersionIsAvailable": "یک نسخه جدید جلیفین برای بروزرسانی آماده میباشد.",
+    "NameSeasonUnknown": "فصل ناشناخته",
+    "NewVersionIsAvailable": "یک نسخه جدید Jellyfin برای بروزرسانی آماده می‌باشد.",
     "NotificationOptionApplicationUpdateAvailable": "بروزرسانی برنامه موجود است",
     "NotificationOptionApplicationUpdateAvailable": "بروزرسانی برنامه موجود است",
     "NotificationOptionApplicationUpdateInstalled": "بروزرسانی برنامه نصب شد",
     "NotificationOptionApplicationUpdateInstalled": "بروزرسانی برنامه نصب شد",
     "NotificationOptionAudioPlayback": "پخش صدا آغاز شد",
     "NotificationOptionAudioPlayback": "پخش صدا آغاز شد",
     "NotificationOptionAudioPlaybackStopped": "پخش صدا متوقف شد",
     "NotificationOptionAudioPlaybackStopped": "پخش صدا متوقف شد",
     "NotificationOptionCameraImageUploaded": "تصاویر دوربین آپلود شد",
     "NotificationOptionCameraImageUploaded": "تصاویر دوربین آپلود شد",
-    "NotificationOptionInstallationFailed": "شکست نصب",
+    "NotificationOptionInstallationFailed": "نصب شکست خورد",
     "NotificationOptionNewLibraryContent": "محتوای جدید افزوده شد",
     "NotificationOptionNewLibraryContent": "محتوای جدید افزوده شد",
     "NotificationOptionPluginError": "خرابی افزونه",
     "NotificationOptionPluginError": "خرابی افزونه",
     "NotificationOptionPluginInstalled": "افزونه نصب شد",
     "NotificationOptionPluginInstalled": "افزونه نصب شد",
@@ -58,40 +58,39 @@
     "NotificationOptionPluginUpdateInstalled": "بروزرسانی افزونه نصب شد",
     "NotificationOptionPluginUpdateInstalled": "بروزرسانی افزونه نصب شد",
     "NotificationOptionServerRestartRequired": "شروع مجدد سرور نیاز است",
     "NotificationOptionServerRestartRequired": "شروع مجدد سرور نیاز است",
     "NotificationOptionTaskFailed": "شکست وظیفه برنامه ریزی شده",
     "NotificationOptionTaskFailed": "شکست وظیفه برنامه ریزی شده",
-    "NotificationOptionUserLockedOut": "کاربر از سیستم خارج شد",
+    "NotificationOptionUserLockedOut": "کاربر قفل شد",
     "NotificationOptionVideoPlayback": "پخش ویدیو آغاز شد",
     "NotificationOptionVideoPlayback": "پخش ویدیو آغاز شد",
     "NotificationOptionVideoPlaybackStopped": "پخش ویدیو متوقف شد",
     "NotificationOptionVideoPlaybackStopped": "پخش ویدیو متوقف شد",
-    "Photos": "عکس ها",
-    "Playlists": "لیست های پخش",
+    "Photos": "عکسها",
+    "Playlists": "لیستهای پخش",
     "Plugin": "افزونه",
     "Plugin": "افزونه",
     "PluginInstalledWithName": "{0} نصب شد",
     "PluginInstalledWithName": "{0} نصب شد",
     "PluginUninstalledWithName": "{0} حذف شد",
     "PluginUninstalledWithName": "{0} حذف شد",
     "PluginUpdatedWithName": "{0} آپدیت شد",
     "PluginUpdatedWithName": "{0} آپدیت شد",
     "ProviderValue": "ارائه دهنده: {0}",
     "ProviderValue": "ارائه دهنده: {0}",
-    "ScheduledTaskFailedWithName": "{0} ناموفق بود",
+    "ScheduledTaskFailedWithName": "{0} شکست خورد",
     "ScheduledTaskStartedWithName": "{0} شروع شد",
     "ScheduledTaskStartedWithName": "{0} شروع شد",
-    "ServerNameNeedsToBeRestarted": "{0} احتیاج به راه اندازی مجدد",
-    "Shows": "سریال ها",
-    "Songs": "آهنگ ها",
+    "ServerNameNeedsToBeRestarted": "{0} نیاز به راه اندازی مجدد دارد",
+    "Shows": "سریالها",
+    "Songs": "موسیقی‌ها",
     "StartupEmbyServerIsLoading": "سرور Jellyfin در حال بارگیری است. لطفا کمی بعد دوباره تلاش کنید.",
     "StartupEmbyServerIsLoading": "سرور Jellyfin در حال بارگیری است. لطفا کمی بعد دوباره تلاش کنید.",
     "SubtitleDownloadFailureForItem": "دانلود زیرنویس برای {0} ناموفق بود",
     "SubtitleDownloadFailureForItem": "دانلود زیرنویس برای {0} ناموفق بود",
-    "SubtitleDownloadFailureFromForItem": "زیرنویس برای دانلود با مشکل مواجه شده از {0} برای {1}",
-    "SubtitlesDownloadedForItem": "زیرنویس {0} دانلود شد",
-    "Sync": "همگامسازی",
+    "SubtitleDownloadFailureFromForItem": "بارگیری زیرنویس برای {1} از {0} شکست خورد",
+    "Sync": "همگام‌سازی",
     "System": "سیستم",
     "System": "سیستم",
-    "TvShows": "سریال های تلویزیونی",
+    "TvShows": "سریالهای تلویزیونی",
     "User": "کاربر",
     "User": "کاربر",
     "UserCreatedWithName": "کاربر {0} ایجاد شد",
     "UserCreatedWithName": "کاربر {0} ایجاد شد",
     "UserDeletedWithName": "کاربر {0} حذف شد",
     "UserDeletedWithName": "کاربر {0} حذف شد",
-    "UserDownloadingItemWithValues": "{0} در حال دانلود است {1}",
-    "UserLockedOutWithName": "کاربر {0} از سیستم خارج شد",
+    "UserDownloadingItemWithValues": "{0} در حال بارگیری {1} می‌باشد",
+    "UserLockedOutWithName": "کاربر {0} قفل شده است",
     "UserOfflineFromDevice": "ارتباط {0} از {1} قطع شد",
     "UserOfflineFromDevice": "ارتباط {0} از {1} قطع شد",
-    "UserOnlineFromDevice": "{0}از {1} آنلاین میباشد",
-    "UserPasswordChangedWithName": "رمز برای کاربر {0} تغییر یافت",
+    "UserOnlineFromDevice": "{0} از {1} آنلاین میباشد",
+    "UserPasswordChangedWithName": "گذرواژه برای کاربر {0} تغییر کرد",
     "UserPolicyUpdatedWithName": "سیاست کاربری برای {0} بروزرسانی شد",
     "UserPolicyUpdatedWithName": "سیاست کاربری برای {0} بروزرسانی شد",
-    "UserStartedPlayingItemWithValues": "{0} شروع به پخش {1} کرد",
-    "UserStoppedPlayingItemWithValues": "{0} پخش {1} را متوقف کرد",
-    "ValueHasBeenAddedToLibrary": "{0} اضافه شده به کتابخانه رسانه شما",
-    "ValueSpecialEpisodeName": "ویژه- {0}",
+    "UserStartedPlayingItemWithValues": "{0} در حال پخش {1} بر روی {2} است",
+    "UserStoppedPlayingItemWithValues": "{0} پخش {1} را بر روی {2} به پایان رساند",
+    "ValueHasBeenAddedToLibrary": "{0} به کتابخانه‌ی رسانه‌ی شما افزوده شد",
+    "ValueSpecialEpisodeName": "ویژه - {0}",
     "VersionNumber": "نسخه {0}"
     "VersionNumber": "نسخه {0}"
 }
 }

+ 0 - 1
Emby.Server.Implementations/Localization/Core/fi.json

@@ -69,7 +69,6 @@
     "UserCreatedWithName": "Luotiin käyttäjä {0}",
     "UserCreatedWithName": "Luotiin käyttäjä {0}",
     "TvShows": "TV-Ohjelmat",
     "TvShows": "TV-Ohjelmat",
     "Sync": "Synkronoi",
     "Sync": "Synkronoi",
-    "SubtitlesDownloadedForItem": "Tekstitys ladattu {0}",
     "SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
     "SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
     "StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
     "StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
     "Songs": "Kappaleet",
     "Songs": "Kappaleet",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/fil.json

@@ -16,7 +16,6 @@
     "TvShows": "Pelikula",
     "TvShows": "Pelikula",
     "System": "Sistema",
     "System": "Sistema",
     "Sync": "Pag-sync",
     "Sync": "Pag-sync",
-    "SubtitlesDownloadedForItem": "Naidownload na ang subtitles {0}",
     "SubtitleDownloadFailureFromForItem": "Hindi naidownload ang subtitles {0} para sa {1}",
     "SubtitleDownloadFailureFromForItem": "Hindi naidownload ang subtitles {0} para sa {1}",
     "StartupEmbyServerIsLoading": "Nagloload ang Jellyfin Server. Sandaling maghintay.",
     "StartupEmbyServerIsLoading": "Nagloload ang Jellyfin Server. Sandaling maghintay.",
     "Songs": "Kanta",
     "Songs": "Kanta",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/fr-CA.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
     "StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
     "SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
-    "SubtitlesDownloadedForItem": "Les sous-titres de {0} ont été téléchargés",
     "Sync": "Synchroniser",
     "Sync": "Synchroniser",
     "System": "Système",
     "System": "Système",
     "TvShows": "Séries Télé",
     "TvShows": "Séries Télé",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/fr.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.",
     "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é.",
     "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}",
     "SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}",
-    "SubtitlesDownloadedForItem": "Les sous-titres de {0} ont été téléchargés",
     "Sync": "Synchroniser",
     "Sync": "Synchroniser",
     "System": "Système",
     "System": "Système",
     "TvShows": "Séries Télé",
     "TvShows": "Séries Télé",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/gsw.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server ladt. Bitte grad noeinisch probiere.",
     "StartupEmbyServerIsLoading": "Jellyfin Server ladt. Bitte grad noeinisch probiere.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Ondertetle vo {0} för {1} hend ned chönne abeglade wärde",
     "SubtitleDownloadFailureFromForItem": "Ondertetle vo {0} för {1} hend ned chönne abeglade wärde",
-    "SubtitlesDownloadedForItem": "Ondertetle abeglade för {0}",
     "Sync": "Synchronisation",
     "Sync": "Synchronisation",
     "System": "System",
     "System": "System",
     "TvShows": "Färnsehserie",
     "TvShows": "Färnsehserie",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/he.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "שרת Jellyfin בהליכי טעינה. אנא נסה שנית בעוד זמן קצר.",
     "StartupEmbyServerIsLoading": "שרת Jellyfin בהליכי טעינה. אנא נסה שנית בעוד זמן קצר.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
     "Sync": "סנכרן",
     "Sync": "סנכרן",
     "System": "System",
     "System": "System",
     "TvShows": "סדרות טלוויזיה",
     "TvShows": "סדרות טלוויזיה",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/hr.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server se učitava. Pokušajte ponovo kasnije.",
     "StartupEmbyServerIsLoading": "Jellyfin Server se učitava. Pokušajte ponovo kasnije.",
     "SubtitleDownloadFailureForItem": "Titlovi prijevoda nisu preuzeti za {0}",
     "SubtitleDownloadFailureForItem": "Titlovi prijevoda nisu preuzeti za {0}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Titlovi prijevoda preuzeti za {0}",
     "Sync": "Sink.",
     "Sync": "Sink.",
     "System": "Sistem",
     "System": "Sistem",
     "TvShows": "TV Shows",
     "TvShows": "TV Shows",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/hu.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek, próbáld újra hamarosan.",
     "StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek, próbáld újra hamarosan.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen:  {0} ehhez: {1}",
     "SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen:  {0} ehhez: {1}",
-    "SubtitlesDownloadedForItem": "Letöltött feliratok a következőhöz: {0}",
     "Sync": "Szinkronizál",
     "Sync": "Szinkronizál",
     "System": "Rendszer",
     "System": "Rendszer",
     "TvShows": "TV műsorok",
     "TvShows": "TV műsorok",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/id.json

@@ -54,7 +54,6 @@
     "User": "Pengguna",
     "User": "Pengguna",
     "System": "Sistem",
     "System": "Sistem",
     "Sync": "Sinkron",
     "Sync": "Sinkron",
-    "SubtitlesDownloadedForItem": "Talop telah diunduh untuk {0}",
     "Shows": "Tayangan",
     "Shows": "Tayangan",
     "ServerNameNeedsToBeRestarted": "{0} perlu dimuat ulang",
     "ServerNameNeedsToBeRestarted": "{0} perlu dimuat ulang",
     "ScheduledTaskStartedWithName": "{0} dimulai",
     "ScheduledTaskStartedWithName": "{0} dimulai",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/is.json

@@ -86,7 +86,6 @@
     "UserOfflineFromDevice": "{0} hefur aftengst frá {1}",
     "UserOfflineFromDevice": "{0} hefur aftengst frá {1}",
     "UserLockedOutWithName": "Notanda {0} hefur verið hindraður aðgangur",
     "UserLockedOutWithName": "Notanda {0} hefur verið hindraður aðgangur",
     "UserDownloadingItemWithValues": "{0} Hleður niður {1}",
     "UserDownloadingItemWithValues": "{0} Hleður niður {1}",
-    "SubtitlesDownloadedForItem": "Skjátextum halað niður fyrir {0}",
     "SubtitleDownloadFailureFromForItem": "Tókst ekki að hala niður skjátextum frá {0} til {1}",
     "SubtitleDownloadFailureFromForItem": "Tókst ekki að hala niður skjátextum frá {0} til {1}",
     "ProviderValue": "Veitandi: {0}",
     "ProviderValue": "Veitandi: {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "Stilling {0} hefur verið uppfærð á netþjón",
     "MessageNamedServerConfigurationUpdatedWithValue": "Stilling {0} hefur verið uppfærð á netþjón",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/it.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.",
     "StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.",
     "SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}",
     "SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}",
     "SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}",
     "SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}",
-    "SubtitlesDownloadedForItem": "Sottotitoli scaricati per {0}",
     "Sync": "Sincronizza",
     "Sync": "Sincronizza",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Serie TV",
     "TvShows": "Serie TV",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ja.json

@@ -75,7 +75,6 @@
     "Songs": "曲",
     "Songs": "曲",
     "StartupEmbyServerIsLoading": "Jellyfin Server は現在読み込み中です。しばらくしてからもう一度お試しください。",
     "StartupEmbyServerIsLoading": "Jellyfin Server は現在読み込み中です。しばらくしてからもう一度お試しください。",
     "SubtitleDownloadFailureFromForItem": "{0} から {1}の字幕のダウンロードに失敗しました",
     "SubtitleDownloadFailureFromForItem": "{0} から {1}の字幕のダウンロードに失敗しました",
-    "SubtitlesDownloadedForItem": "{0} の字幕がダウンロードされました",
     "Sync": "同期",
     "Sync": "同期",
     "System": "システム",
     "System": "システム",
     "TvShows": "テレビ番組",
     "TvShows": "テレビ番組",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/kk.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server júktelýde. Áreketti kóp uzamaı qaıtalańyz.",
     "StartupEmbyServerIsLoading": "Jellyfin Server júktelýde. Áreketti kóp uzamaı qaıtalańyz.",
     "SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
     "SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
     "SubtitleDownloadFailureFromForItem": "{1} úshin sýbtıtrlerdi {0} kózinen júktep alý sátsiz",
     "SubtitleDownloadFailureFromForItem": "{1} úshin sýbtıtrlerdi {0} kózinen júktep alý sátsiz",
-    "SubtitlesDownloadedForItem": "{0} úshin sýbtıtrler júktelip alyndy",
     "Sync": "Úndestirý",
     "Sync": "Úndestirý",
     "System": "Júıe",
     "System": "Júıe",
     "TvShows": "TD-kórsetimder",
     "TvShows": "TD-kórsetimder",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ko.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin 서버를 불러오고 있습니다. 잠시 후에 다시 시도하십시오.",
     "StartupEmbyServerIsLoading": "Jellyfin 서버를 불러오고 있습니다. 잠시 후에 다시 시도하십시오.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "{0}에서 {1} 자막 다운로드에 실패했습니다",
     "SubtitleDownloadFailureFromForItem": "{0}에서 {1} 자막 다운로드에 실패했습니다",
-    "SubtitlesDownloadedForItem": "{0} 자막 다운로드 완료",
     "Sync": "동기화",
     "Sync": "동기화",
     "System": "시스템",
     "System": "시스템",
     "TvShows": "TV 쇼",
     "TvShows": "TV 쇼",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/lt-LT.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.",
     "StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}",
     "SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}",
-    "SubtitlesDownloadedForItem": "{0} subtitrai parsiųsti",
     "Sync": "Sinchronizuoti",
     "Sync": "Sinchronizuoti",
     "System": "System",
     "System": "System",
     "TvShows": "TV Serialai",
     "TvShows": "TV Serialai",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/lv.json

@@ -31,7 +31,6 @@
     "TvShows": "TV Raidījumi",
     "TvShows": "TV Raidījumi",
     "Sync": "Sinhronizācija",
     "Sync": "Sinhronizācija",
     "System": "Sistēma",
     "System": "Sistēma",
-    "SubtitlesDownloadedForItem": "Subtitri lejupielādēti priekš {0}",
     "StartupEmbyServerIsLoading": "Jellyfin Serveris lādējas. Lūdzu mēģiniet vēlreiz pēc brīža.",
     "StartupEmbyServerIsLoading": "Jellyfin Serveris lādējas. Lūdzu mēģiniet vēlreiz pēc brīža.",
     "Songs": "Dziesmas",
     "Songs": "Dziesmas",
     "Shows": "Raidījumi",
     "Shows": "Raidījumi",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/mk.json

@@ -86,7 +86,6 @@
     "TvShows": "ТВ Серии",
     "TvShows": "ТВ Серии",
     "System": "Систем",
     "System": "Систем",
     "Sync": "Синхронизација",
     "Sync": "Синхронизација",
-    "SubtitlesDownloadedForItem": "Спуштање превод за {0}",
     "SubtitleDownloadFailureFromForItem": "Преводот неуспешно се спушти од {0} за {1}",
     "SubtitleDownloadFailureFromForItem": "Преводот неуспешно се спушти од {0} за {1}",
     "StartupEmbyServerIsLoading": "Jellyfin Server се пушта. Ве молиме причекајте.",
     "StartupEmbyServerIsLoading": "Jellyfin Server се пушта. Ве молиме причекајте.",
     "Songs": "Песни",
     "Songs": "Песни",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ms.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
     "Sync": "Sync",
     "Sync": "Sync",
     "System": "Sistem",
     "System": "Sistem",
     "TvShows": "TV Shows",
     "TvShows": "TV Shows",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/nb.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
     "StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
     "SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for  {0}",
     "SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for  {0}",
     "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
     "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
-    "SubtitlesDownloadedForItem": "Undertekster lastet ned for {0}",
     "Sync": "Synkroniser",
     "Sync": "Synkroniser",
     "System": "System",
     "System": "System",
     "TvShows": "TV-serier",
     "TvShows": "TV-serier",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/nl.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden, probeer het later opnieuw.",
     "StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden, probeer het later opnieuw.",
     "SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
     "SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
     "SubtitleDownloadFailureFromForItem": "Ondertitels konden niet gedownload worden van {0} voor {1}",
     "SubtitleDownloadFailureFromForItem": "Ondertitels konden niet gedownload worden van {0} voor {1}",
-    "SubtitlesDownloadedForItem": "Ondertiteling voor {0} is gedownload",
     "Sync": "Synchronisatie",
     "Sync": "Synchronisatie",
     "System": "Systeem",
     "System": "Systeem",
     "TvShows": "TV-series",
     "TvShows": "TV-series",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/pl.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
     "StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
     "SubtitleDownloadFailureForItem": "Pobieranie napisów dla {0} zakończone niepowodzeniem",
     "SubtitleDownloadFailureForItem": "Pobieranie napisów dla {0} zakończone niepowodzeniem",
     "SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
     "SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
-    "SubtitlesDownloadedForItem": "Pobrano napisy dla {0}",
     "Sync": "Synchronizacja",
     "Sync": "Synchronizacja",
     "System": "System",
     "System": "System",
     "TvShows": "Seriale",
     "TvShows": "Seriale",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/pt-BR.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "O Servidor Jellyfin está carregando. Por favor, tente novamente mais tarde.",
     "StartupEmbyServerIsLoading": "O Servidor Jellyfin está carregando. Por favor, tente novamente mais tarde.",
     "SubtitleDownloadFailureForItem": "Download de legendas falhou para {0}",
     "SubtitleDownloadFailureForItem": "Download de legendas falhou para {0}",
     "SubtitleDownloadFailureFromForItem": "Houve um problema ao baixar as legendas de {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Houve um problema ao baixar as legendas de {0} para {1}",
-    "SubtitlesDownloadedForItem": "Legendas baixadas para {0}",
     "Sync": "Sincronizar",
     "Sync": "Sincronizar",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Séries",
     "TvShows": "Séries",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/pt-PT.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente mais tarde.",
     "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente mais tarde.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas a partir de {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas a partir de {0} para {1}",
-    "SubtitlesDownloadedForItem": "Transferidas legendas para {0}",
     "Sync": "Sincronização",
     "Sync": "Sincronização",
     "System": "Sistema",
     "System": "Sistema",
     "TvShows": "Programas TV",
     "TvShows": "Programas TV",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/pt.json

@@ -31,7 +31,6 @@
     "User": "Utilizador",
     "User": "Utilizador",
     "TvShows": "Séries",
     "TvShows": "Séries",
     "System": "Sistema",
     "System": "Sistema",
-    "SubtitlesDownloadedForItem": "Legendas transferidas para {0}",
     "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}",
     "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}",
     "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.",
     "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.",
     "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado",
     "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ro.json

@@ -17,7 +17,6 @@
     "TvShows": "Spectacole TV",
     "TvShows": "Spectacole TV",
     "System": "Sistem",
     "System": "Sistem",
     "Sync": "Sincronizare",
     "Sync": "Sincronizare",
-    "SubtitlesDownloadedForItem": "Subtitrari descarcate pentru {0}",
     "SubtitleDownloadFailureFromForItem": "Subtitrările nu au putut fi descărcate de la {0} pentru {1}",
     "SubtitleDownloadFailureFromForItem": "Subtitrările nu au putut fi descărcate de la {0} pentru {1}",
     "StartupEmbyServerIsLoading": "Se încarcă serverul Jellyfin. Încercați din nou în scurt timp.",
     "StartupEmbyServerIsLoading": "Se încarcă serverul Jellyfin. Încercați din nou în scurt timp.",
     "Songs": "Melodii",
     "Songs": "Melodii",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/ru.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
     "StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
     "SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
     "SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
     "SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
     "SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
-    "SubtitlesDownloadedForItem": "Субтитры к {0} загружены",
     "Sync": "Синхро",
     "Sync": "Синхро",
     "System": "Система",
     "System": "Система",
     "TvShows": "ТВ",
     "TvShows": "ТВ",

+ 23 - 2
Emby.Server.Implementations/Localization/Core/sk.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server sa spúšťa. Prosím, skúste to o chvíľu znova.",
     "StartupEmbyServerIsLoading": "Jellyfin Server sa spúšťa. Prosím, skúste to o chvíľu znova.",
     "SubtitleDownloadFailureForItem": "Sťahovanie titulkov pre {0} zlyhalo",
     "SubtitleDownloadFailureForItem": "Sťahovanie titulkov pre {0} zlyhalo",
     "SubtitleDownloadFailureFromForItem": "Sťahovanie titulkov z {0} pre {1} zlyhalo",
     "SubtitleDownloadFailureFromForItem": "Sťahovanie titulkov z {0} pre {1} zlyhalo",
-    "SubtitlesDownloadedForItem": "Titulky pre {0} stiahnuté",
     "Sync": "Synchronizácia",
     "Sync": "Synchronizácia",
     "System": "Systém",
     "System": "Systém",
     "TvShows": "TV seriály",
     "TvShows": "TV seriály",
@@ -93,5 +92,27 @@
     "UserStoppedPlayingItemWithValues": "{0} ukončil prehrávanie {1} na {2}",
     "UserStoppedPlayingItemWithValues": "{0} ukončil prehrávanie {1} na {2}",
     "ValueHasBeenAddedToLibrary": "{0} bol pridané do vašej knižnice médií",
     "ValueHasBeenAddedToLibrary": "{0} bol pridané do vašej knižnice médií",
     "ValueSpecialEpisodeName": "Špeciál - {0}",
     "ValueSpecialEpisodeName": "Špeciál - {0}",
-    "VersionNumber": "Verzia {0}"
+    "VersionNumber": "Verzia {0}",
+    "TaskDownloadMissingSubtitlesDescription": "Vyhľadá na internete chýbajúce titulky podľa toho, ako sú nakonfigurované metadáta.",
+    "TaskDownloadMissingSubtitles": "Stiahnuť chýbajúce titulky",
+    "TaskRefreshChannelsDescription": "Obnoví informácie o internetových kanáloch.",
+    "TaskRefreshChannels": "Obnoviť kanály",
+    "TaskCleanTranscodeDescription": "Vymaže súbory transkódovania, ktoré sú staršie ako jeden deň.",
+    "TaskCleanTranscode": "Vyčistiť priečinok pre transkódovanie",
+    "TaskUpdatePluginsDescription": "Stiahne a nainštaluje aktualizácie pre zásuvné moduly, ktoré sú nastavené tak, aby sa aktualizovali automaticky.",
+    "TaskUpdatePlugins": "Aktualizovať zásuvné moduly",
+    "TaskRefreshPeopleDescription": "Aktualizuje metadáta pre hercov a režisérov vo vašej mediálnej knižnici.",
+    "TaskRefreshPeople": "Obnoviť osoby",
+    "TaskCleanLogsDescription": "Vymaže log súbory, ktoré su staršie ako {0} deň/dni/dní.",
+    "TaskCleanLogs": "Vyčistiť priečinok s logmi",
+    "TaskRefreshLibraryDescription": "Hľadá vo vašej mediálnej knižnici nové súbory a obnovuje metadáta.",
+    "TaskRefreshLibrary": "Prehľadávať knižnicu medií",
+    "TaskRefreshChapterImagesDescription": "Vytvorí náhľady pre videá, ktoré majú kapitoly.",
+    "TaskRefreshChapterImages": "Extrahovať obrázky kapitol",
+    "TaskCleanCacheDescription": "Vymaže cache súbory, ktoré nie sú už potrebné pre systém.",
+    "TaskCleanCache": "Vyčistiť Cache priečinok",
+    "TasksChannelsCategory": "Internetové kanály",
+    "TasksApplicationCategory": "Aplikácia",
+    "TasksLibraryCategory": "Knižnica",
+    "TasksMaintenanceCategory": "Údržba"
 }
 }

+ 0 - 1
Emby.Server.Implementations/Localization/Core/sl-SI.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server se nalaga. Poskusi ponovno kasneje.",
     "StartupEmbyServerIsLoading": "Jellyfin Server se nalaga. Poskusi ponovno kasneje.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "Neuspešen prenos podnapisov iz {0} za {1}",
     "SubtitleDownloadFailureFromForItem": "Neuspešen prenos podnapisov iz {0} za {1}",
-    "SubtitlesDownloadedForItem": "Podnapisi preneseni za {0}",
     "Sync": "Sinhroniziraj",
     "Sync": "Sinhroniziraj",
     "System": "System",
     "System": "System",
     "TvShows": "TV serije",
     "TvShows": "TV serije",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/sr.json

@@ -17,7 +17,6 @@
     "TvShows": "ТВ серије",
     "TvShows": "ТВ серије",
     "System": "Систем",
     "System": "Систем",
     "Sync": "Усклади",
     "Sync": "Усклади",
-    "SubtitlesDownloadedForItem": "Титлови преузети за {0}",
     "SubtitleDownloadFailureFromForItem": "Неуспело преузимање титлова за {1} са {0}",
     "SubtitleDownloadFailureFromForItem": "Неуспело преузимање титлова за {1} са {0}",
     "StartupEmbyServerIsLoading": "Џелифин сервер се подиже. Покушајте поново убрзо.",
     "StartupEmbyServerIsLoading": "Џелифин сервер се подиже. Покушајте поново убрзо.",
     "Songs": "Песме",
     "Songs": "Песме",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/sv.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Server arbetar. Pröva igen snart.",
     "StartupEmbyServerIsLoading": "Jellyfin Server arbetar. Pröva igen snart.",
     "SubtitleDownloadFailureForItem": "Nerladdning av undertexter för {0} misslyckades",
     "SubtitleDownloadFailureForItem": "Nerladdning av undertexter för {0} misslyckades",
     "SubtitleDownloadFailureFromForItem": "Undertexter kunde inte laddas ner från {0} för {1}",
     "SubtitleDownloadFailureFromForItem": "Undertexter kunde inte laddas ner från {0} för {1}",
-    "SubtitlesDownloadedForItem": "Undertexter har laddats ner till {0}",
     "Sync": "Synk",
     "Sync": "Synk",
     "System": "System",
     "System": "System",
     "TvShows": "TV-serier",
     "TvShows": "TV-serier",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/tr.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin Sunucusu yükleniyor. Lütfen kısa süre sonra tekrar deneyin.",
     "StartupEmbyServerIsLoading": "Jellyfin Sunucusu yükleniyor. Lütfen kısa süre sonra tekrar deneyin.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "{1} için alt yazılar {0} 'dan indirilemedi",
     "SubtitleDownloadFailureFromForItem": "{1} için alt yazılar {0} 'dan indirilemedi",
-    "SubtitlesDownloadedForItem": "{0} için altyazılar indirildi",
     "Sync": "Eşitle",
     "Sync": "Eşitle",
     "System": "Sistem",
     "System": "Sistem",
     "TvShows": "Diziler",
     "TvShows": "Diziler",

+ 25 - 4
Emby.Server.Implementations/Localization/Core/zh-CN.json

@@ -3,11 +3,11 @@
     "AppDeviceValues": "应用: {0}, 设备: {1}",
     "AppDeviceValues": "应用: {0}, 设备: {1}",
     "Application": "应用程序",
     "Application": "应用程序",
     "Artists": "艺术家",
     "Artists": "艺术家",
-    "AuthenticationSucceededWithUserName": "{0} 验证成功",
+    "AuthenticationSucceededWithUserName": "成功验证{0} ",
     "Books": "书籍",
     "Books": "书籍",
     "CameraImageUploadedFrom": "新的相机图像已从 {0} 上传",
     "CameraImageUploadedFrom": "新的相机图像已从 {0} 上传",
     "Channels": "频道",
     "Channels": "频道",
-    "ChapterNameValue": "第 {0} ",
+    "ChapterNameValue": "第 {0} ",
     "Collections": "合集",
     "Collections": "合集",
     "DeviceOfflineWithName": "{0} 已断开",
     "DeviceOfflineWithName": "{0} 已断开",
     "DeviceOnlineWithName": "{0} 已连接",
     "DeviceOnlineWithName": "{0} 已连接",
@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin 服务器加载中。请稍后再试。",
     "StartupEmbyServerIsLoading": "Jellyfin 服务器加载中。请稍后再试。",
     "SubtitleDownloadFailureForItem": "为 {0} 下载字幕失败",
     "SubtitleDownloadFailureForItem": "为 {0} 下载字幕失败",
     "SubtitleDownloadFailureFromForItem": "无法从 {0} 下载 {1} 的字幕",
     "SubtitleDownloadFailureFromForItem": "无法从 {0} 下载 {1} 的字幕",
-    "SubtitlesDownloadedForItem": "已为 {0} 下载了字幕",
     "Sync": "同步",
     "Sync": "同步",
     "System": "系统",
     "System": "系统",
     "TvShows": "电视剧",
     "TvShows": "电视剧",
@@ -93,5 +92,27 @@
     "UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
     "UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
     "ValueHasBeenAddedToLibrary": "{0} 已添加至您的媒体库中",
     "ValueHasBeenAddedToLibrary": "{0} 已添加至您的媒体库中",
     "ValueSpecialEpisodeName": "特典 - {0}",
     "ValueSpecialEpisodeName": "特典 - {0}",
-    "VersionNumber": "版本 {0}"
+    "VersionNumber": "版本 {0}",
+    "TaskUpdatePluginsDescription": "为已设置为自动更新的插件下载和安装更新。",
+    "TaskRefreshPeople": "刷新人员",
+    "TasksChannelsCategory": "互联网频道",
+    "TasksLibraryCategory": "媒体库",
+    "TaskDownloadMissingSubtitlesDescription": "根据元数据设置在互联网上搜索缺少的字幕。",
+    "TaskDownloadMissingSubtitles": "下载缺少的字幕",
+    "TaskRefreshChannelsDescription": "刷新互联网频道信息。",
+    "TaskRefreshChannels": "刷新频道",
+    "TaskCleanTranscodeDescription": "删除存在超过 1 天的转码文件。",
+    "TaskCleanTranscode": "清理转码目录",
+    "TaskUpdatePlugins": "更新插件",
+    "TaskRefreshPeopleDescription": "更新媒体库中演员和导演的元数据。",
+    "TaskCleanLogsDescription": "删除存在超过 {0} 天的的日志文件。",
+    "TaskCleanLogs": "清理日志目录",
+    "TaskRefreshLibraryDescription": "扫描你的媒体库以获取新文件并刷新元数据。",
+    "TaskRefreshLibrary": "扫描媒体库",
+    "TaskRefreshChapterImagesDescription": "为包含剧集的视频提取缩略图。",
+    "TaskRefreshChapterImages": "提取剧集图片",
+    "TaskCleanCacheDescription": "删除系统不再需要的缓存文件。",
+    "TaskCleanCache": "清理缓存目录",
+    "TasksApplicationCategory": "应用程序",
+    "TasksMaintenanceCategory": "维护"
 }
 }

+ 0 - 1
Emby.Server.Implementations/Localization/Core/zh-HK.json

@@ -76,7 +76,6 @@
     "StartupEmbyServerIsLoading": "Jellyfin 伺服器載入中,請稍後再試。",
     "StartupEmbyServerIsLoading": "Jellyfin 伺服器載入中,請稍後再試。",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureFromForItem": "無法從 {0} 下載 {1} 的字幕",
     "SubtitleDownloadFailureFromForItem": "無法從 {0} 下載 {1} 的字幕",
-    "SubtitlesDownloadedForItem": "已為 {0} 下載了字幕",
     "Sync": "同步",
     "Sync": "同步",
     "System": "System",
     "System": "System",
     "TvShows": "電視節目",
     "TvShows": "電視節目",

+ 0 - 1
Emby.Server.Implementations/Localization/Core/zh-TW.json

@@ -72,7 +72,6 @@
     "Shows": "節目",
     "Shows": "節目",
     "Songs": "歌曲",
     "Songs": "歌曲",
     "StartupEmbyServerIsLoading": "Jellyfin Server正在啟動,請稍後再試一次。",
     "StartupEmbyServerIsLoading": "Jellyfin Server正在啟動,請稍後再試一次。",
-    "SubtitlesDownloadedForItem": "已為 {0} 下載字幕",
     "Sync": "同步",
     "Sync": "同步",
     "System": "系統",
     "System": "系統",
     "TvShows": "電視節目",
     "TvShows": "電視節目",

+ 14 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs

@@ -15,6 +15,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
@@ -39,11 +40,19 @@ namespace Emby.Server.Implementations.ScheduledTasks
 
 
         private readonly IEncodingManager _encodingManager;
         private readonly IEncodingManager _encodingManager;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
         /// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
         /// </summary>
         /// </summary>
-        public ChapterImagesTask(ILoggerFactory loggerFactory, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager, IFileSystem fileSystem)
+        public ChapterImagesTask(
+            ILoggerFactory loggerFactory,
+            ILibraryManager libraryManager,
+            IItemRepository itemRepo,
+            IApplicationPaths appPaths,
+            IEncodingManager encodingManager,
+            IFileSystem fileSystem,
+            ILocalizationManager localization)
         {
         {
             _logger = loggerFactory.CreateLogger(GetType().Name);
             _logger = loggerFactory.CreateLogger(GetType().Name);
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
@@ -51,6 +60,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
             _appPaths = appPaths;
             _appPaths = appPaths;
             _encodingManager = encodingManager;
             _encodingManager = encodingManager;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -159,11 +169,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
             }
             }
         }
         }
 
 
-        public string Name => "Extract Chapter Images";
+        public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages");
 
 
-        public string Description => "Creates thumbnails for videos that have chapters.";
+        public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription");
 
 
-        public string Category => "Library";
+        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 
 
         public string Key => "RefreshChapterImages";
         public string Key => "RefreshChapterImages";
 
 

+ 8 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 {
 {
@@ -25,6 +26,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
         /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
@@ -32,11 +34,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         public DeleteCacheFileTask(
         public DeleteCacheFileTask(
             IApplicationPaths appPaths,
             IApplicationPaths appPaths,
             ILogger<DeleteCacheFileTask> logger,
             ILogger<DeleteCacheFileTask> logger,
-            IFileSystem fileSystem)
+            IFileSystem fileSystem,
+            ILocalizationManager localization)
         {
         {
             ApplicationPaths = appPaths;
             ApplicationPaths = appPaths;
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -161,11 +165,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             }
             }
         }
         }
 
 
-        public string Name => "Clean Cache Directory";
+        public string Name => _localization.GetLocalizedString("TaskCleanCache");
 
 
-        public string Description => "Deletes cache files no longer needed by the system.";
+        public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription");
 
 
-        public string Category => "Maintenance";
+        public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
 
 
         public string Key => "DeleteCacheFiles";
         public string Key => "DeleteCacheFiles";
 
 

+ 7 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 {
 {
@@ -21,15 +22,17 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         private IConfigurationManager ConfigurationManager { get; set; }
         private IConfigurationManager ConfigurationManager { get; set; }
 
 
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
         /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
         /// </summary>
         /// </summary>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
-        public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem)
+        public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization)
         {
         {
             ConfigurationManager = configurationManager;
             ConfigurationManager = configurationManager;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -79,11 +82,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             return Task.CompletedTask;
             return Task.CompletedTask;
         }
         }
 
 
-        public string Name => "Clean Log Directory";
+        public string Name => _localization.GetLocalizedString("TaskCleanLogs");
 
 
-        public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
+        public string Description => string.Format(_localization.GetLocalizedString("TaskCleanLogsDescription"), ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
 
 
-        public string Category => "Maintenance";
+        public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
 
 
         public string Key => "CleanLogFiles";
         public string Key => "CleanLogFiles";
 
 

+ 8 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 namespace Emby.Server.Implementations.ScheduledTasks.Tasks
 {
 {
@@ -19,6 +20,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IConfigurationManager _configurationManager;
         private readonly IConfigurationManager _configurationManager;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteTranscodeFileTask" /> class.
         /// Initializes a new instance of the <see cref="DeleteTranscodeFileTask" /> class.
@@ -26,11 +28,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
         public DeleteTranscodeFileTask(
         public DeleteTranscodeFileTask(
             ILogger<DeleteTranscodeFileTask> logger,
             ILogger<DeleteTranscodeFileTask> logger,
             IFileSystem fileSystem,
             IFileSystem fileSystem,
-            IConfigurationManager configurationManager)
+            IConfigurationManager configurationManager,
+            ILocalizationManager localization)
         {
         {
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _configurationManager = configurationManager;
             _configurationManager = configurationManager;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -128,11 +132,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             }
             }
         }
         }
 
 
-        public string Name => "Clean Transcode Directory";
+        public string Name => _localization.GetLocalizedString("TaskCleanTranscode");
 
 
-        public string Description => "Deletes transcode files more than one day old.";
+        public string Description => _localization.GetLocalizedString("TaskCleanTranscodeDescription");
 
 
-        public string Category => "Maintenance";
+        public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
 
 
         public string Key => "DeleteTranscodeFiles";
         public string Key => "DeleteTranscodeFiles";
 
 

+ 7 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
@@ -19,16 +20,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
 
 
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
         /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
         /// </summary>
         /// </summary>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="appHost">The server application host</param>
         /// <param name="appHost">The server application host</param>
-        public PeopleValidationTask(ILibraryManager libraryManager, IServerApplicationHost appHost)
+        public PeopleValidationTask(ILibraryManager libraryManager, IServerApplicationHost appHost, ILocalizationManager localization)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _appHost = appHost;
             _appHost = appHost;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -57,11 +60,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
             return _libraryManager.ValidatePeople(cancellationToken, progress);
             return _libraryManager.ValidatePeople(cancellationToken, progress);
         }
         }
 
 
-        public string Name => "Refresh People";
+        public string Name => _localization.GetLocalizedString("TaskRefreshPeople");
 
 
-        public string Description => "Updates metadata for actors and directors in your media library.";
+        public string Description => _localization.GetLocalizedString("TaskRefreshPeopleDescription");
 
 
-        public string Category => "Library";
+        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 
 
         public string Key => "RefreshPeople";
         public string Key => "RefreshPeople";
 
 

+ 7 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Common.Updates;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
@@ -22,11 +23,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
         private readonly IInstallationManager _installationManager;
         private readonly IInstallationManager _installationManager;
+        private readonly ILocalizationManager _localization;
 
 
-        public PluginUpdateTask(ILogger<PluginUpdateTask> logger, IInstallationManager installationManager)
+        public PluginUpdateTask(ILogger<PluginUpdateTask> logger, IInstallationManager installationManager, ILocalizationManager localization)
         {
         {
             _logger = logger;
             _logger = logger;
             _installationManager = installationManager;
             _installationManager = installationManager;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -96,13 +99,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Name => "Update Plugins";
+        public string Name => _localization.GetLocalizedString("TaskUpdatePlugins");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
+        public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public string Category => "Application";
+        public string Category => _localization.GetLocalizedString("TasksApplicationCategory");
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public string Key => "PluginUpdates";
         public string Key => "PluginUpdates";

+ 7 - 4
Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs

@@ -6,6 +6,7 @@ using Emby.Server.Implementations.Library;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Globalization;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
@@ -19,15 +20,17 @@ namespace Emby.Server.Implementations.ScheduledTasks
         /// </summary>
         /// </summary>
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
+        private readonly ILocalizationManager _localization;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class.
         /// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class.
         /// </summary>
         /// </summary>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public RefreshMediaLibraryTask(ILibraryManager libraryManager, IServerConfigurationManager config)
+        public RefreshMediaLibraryTask(ILibraryManager libraryManager, IServerConfigurationManager config, ILocalizationManager localization)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _config = config;
             _config = config;
+            _localization = localization;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -58,11 +61,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
             return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
             return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
         }
         }
 
 
-        public string Name => "Scan Media Library";
+        public string Name => _localization.GetLocalizedString("TaskRefreshLibrary");
 
 
-        public string Description => "Scans your media library for new files and refreshes metadata.";
+        public string Description => _localization.GetLocalizedString("TaskRefreshLibraryDescription");
 
 
-        public string Category => "Library";
+        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 
 
         public string Key => "RefreshLibrary";
         public string Key => "RefreshLibrary";
 
 

+ 10 - 10
Emby.Server.Implementations/Session/SessionManager.cs

@@ -1401,6 +1401,16 @@ namespace Emby.Server.Implementations.Session
                 user = _userManager.GetUserByName(request.Username);
                 user = _userManager.GetUserByName(request.Username);
             }
             }
 
 
+            if (enforcePassword)
+            {
+                user = await _userManager.AuthenticateUser(
+                    request.Username,
+                    request.Password,
+                    request.PasswordSha1,
+                    request.RemoteEndPoint,
+                    true).ConfigureAwait(false);
+            }
+
             if (user == null)
             if (user == null)
             {
             {
                 AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
                 AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
@@ -1413,16 +1423,6 @@ namespace Emby.Server.Implementations.Session
                 throw new SecurityException("User is not allowed access from this device.");
                 throw new SecurityException("User is not allowed access from this device.");
             }
             }
 
 
-            if (enforcePassword)
-            {
-                user = await _userManager.AuthenticateUser(
-                    request.Username,
-                    request.Password,
-                    request.PasswordSha1,
-                    request.RemoteEndPoint,
-                    true).ConfigureAwait(false);
-            }
-
             var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
             var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);
 
 
             var session = LogSessionActivity(
             var session = LogSessionActivity(

+ 1 - 1
Jellyfin.Api/Jellyfin.Api.csproj

@@ -8,7 +8,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
-    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.2" />
+    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.3" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0" />
   </ItemGroup>
   </ItemGroup>

+ 1 - 1
Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj

@@ -14,7 +14,7 @@
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="SkiaSharp" Version="1.68.1" />
     <PackageReference Include="SkiaSharp" Version="1.68.1" />
     <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.1" />
     <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.1" />
-    <PackageReference Include="Jellyfin.SkiaSharp.NativeAssets.LinuxArm" Version="1.68.0" />
+    <PackageReference Include="Jellyfin.SkiaSharp.NativeAssets.LinuxArm" Version="1.68.1" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 2 - 2
Jellyfin.Server/Jellyfin.Server.csproj

@@ -36,8 +36,8 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="CommandLineParser" Version="2.7.82" />
     <PackageReference Include="CommandLineParser" Version="2.7.82" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.3" />
     <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
     <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
     <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
     <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
     <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
     <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />

+ 30 - 22
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -927,61 +927,69 @@ namespace MediaBrowser.Api.Playback.Hls
             }
             }
             else
             else
             {
             {
+                var gopArg = string.Empty;
                 var keyFrameArg = string.Format(
                 var keyFrameArg = string.Format(
                     CultureInfo.InvariantCulture,
                     CultureInfo.InvariantCulture,
                     " -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
                     " -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
                     GetStartNumber(state) * state.SegmentLength,
                     GetStartNumber(state) * state.SegmentLength,
                     state.SegmentLength);
                     state.SegmentLength);
-                if (state.TargetFramerate.HasValue)
+
+                var framerate = state.VideoStream?.RealFrameRate;
+
+                if (framerate != null && framerate.HasValue)
                 {
                 {
                     // This is to make sure keyframe interval is limited to our segment,
                     // This is to make sure keyframe interval is limited to our segment,
                     // as forcing keyframes is not enough.
                     // as forcing keyframes is not enough.
                     // Example: we encoded half of desired length, then codec detected
                     // Example: we encoded half of desired length, then codec detected
                     // scene cut and inserted a keyframe; next forced keyframe would
                     // scene cut and inserted a keyframe; next forced keyframe would
-                    // be created outside of segment, which breaks seeking.
-                    keyFrameArg += string.Format(
+                    // be created outside of segment, which breaks seeking
+                    // -sc_threshold 0 is used to prevent the hardware encoder from post processing to break the set keyframe
+                    gopArg = string.Format(
                         CultureInfo.InvariantCulture,
                         CultureInfo.InvariantCulture,
-                        " -g {0} -keyint_min {0}",
-                        (int)(state.SegmentLength * state.TargetFramerate)
+                        " -g {0} -keyint_min {0} -sc_threshold 0",
+                        Math.Ceiling(state.SegmentLength * framerate.Value)
                     );
                     );
                 }
                 }
 
 
-                var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
-
                 args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultEncoderPreset());
                 args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultEncoderPreset());
 
 
-                // Unable to force key frames to h264_qsv transcode
-                if (string.Equals(codec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+                // Unable to force key frames using these hw encoders, set key frames by GOP
+                if (string.Equals(codec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(codec, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(codec, "h264_amf", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    Logger.LogInformation("Bug Workaround: Disabling force_key_frames for h264_qsv");
+                    args += " " + gopArg;
                 }
                 }
                 else
                 else
                 {
                 {
-                    args += " " + keyFrameArg;
+                    args += " " + keyFrameArg + gopArg;
                 }
                 }
 
 
                 //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
                 //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
 
 
+                var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+
+                // This is for graphical subs
+                if (hasGraphicalSubs)
+                {
+                    args += EncodingHelper.GetGraphicalSubtitleParam(state, encodingOptions, codec);
+                }
                 // Add resolution params, if specified
                 // Add resolution params, if specified
-                if (!hasGraphicalSubs)
+                else
                 {
                 {
-                    args += EncodingHelper.GetOutputSizeParam(state, encodingOptions, codec, true);
+                    args += EncodingHelper.GetOutputSizeParam(state, encodingOptions, codec);
                 }
                 }
 
 
-                // This is for internal graphical subs
-                if (hasGraphicalSubs)
+                // -start_at_zero is necessary to use with -ss when seeking,
+                // otherwise the target position cannot be determined.
+                if (!(state.SubtitleStream != null && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream))
                 {
                 {
-                    args += EncodingHelper.GetGraphicalSubtitleParam(state, encodingOptions, codec);
+                    args += " -start_at_zero";
                 }
                 }
 
 
                 //args += " -flags -global_header";
                 //args += " -flags -global_header";
             }
             }
 
 
-            if (args.IndexOf("-copyts", StringComparison.OrdinalIgnoreCase) == -1)
-            {
-                args += " -copyts";
-            }
-
             if (!string.IsNullOrEmpty(state.OutputVideoSync))
             if (!string.IsNullOrEmpty(state.OutputVideoSync))
             {
             {
                 args += " -vsync " + state.OutputVideoSync;
                 args += " -vsync " + state.OutputVideoSync;
@@ -1025,7 +1033,7 @@ namespace MediaBrowser.Api.Playback.Hls
             }
             }
 
 
             return string.Format(
             return string.Format(
-                "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f hls -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {6} -individual_header_trailer 0 -hls_segment_type {7} -start_number {8} -hls_segment_filename \"{9}\" -hls_playlist_type vod -hls_list_size 0 -y \"{10}\"",
+                "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -f hls -max_delay 5000000 -hls_time {6} -individual_header_trailer 0 -hls_segment_type {7} -start_number {8} -hls_segment_filename \"{9}\" -hls_playlist_type vod -hls_list_size 0 -y \"{10}\"",
                 inputModifier,
                 inputModifier,
                 EncodingHelper.GetInputArgument(state, encodingOptions),
                 EncodingHelper.GetInputArgument(state, encodingOptions),
                 threads,
                 threads,

+ 2 - 2
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -12,8 +12,8 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
     <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
     <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 2 - 2
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -8,8 +8,8 @@
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.3" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 188 - 109
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -460,16 +460,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             if (state.IsVideoRequest
             if (state.IsVideoRequest
                 && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
                 && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
             {
             {
-                var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
-                var hwOutputFormat = "vaapi";
-
-                if (hasGraphicalSubs)
-                {
-                    hwOutputFormat = "yuv420p";
-                }
-
-                arg.Append("-hwaccel vaapi -hwaccel_output_format ")
-                    .Append(hwOutputFormat)
+                arg.Append("-hwaccel vaapi -hwaccel_output_format vaapi")
                     .Append(" -vaapi_device ")
                     .Append(" -vaapi_device ")
                     .Append(encodingOptions.VaapiDevice)
                     .Append(encodingOptions.VaapiDevice)
                     .Append(' ');
                     .Append(' ');
@@ -480,20 +471,26 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
             {
                 var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
                 var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
                 var outputVideoCodec = GetVideoEncoder(state, encodingOptions);
                 var outputVideoCodec = GetVideoEncoder(state, encodingOptions);
+				
+                var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
 
 
-                if (encodingOptions.EnableHardwareEncoding && outputVideoCodec.Contains("qsv", StringComparison.OrdinalIgnoreCase))
+                if (!hasTextSubs)
                 {
                 {
-                    if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase))
-                    {
-                        arg.Append("-hwaccel qsv ");
-                    }
-                    else
+                    // While using QSV encoder
+                    if ((outputVideoCodec ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1)
                     {
                     {
-                        arg.Append("-init_hw_device qsv=hw -filter_hw_device hw ");
+                        // While using QSV decoder
+                        if ((videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1)
+                        {
+                            arg.Append("-hwaccel qsv ");
+                        }
+                        // While using SW decoder
+                        else
+                        {
+                            arg.Append("-init_hw_device qsv=hw -filter_hw_device hw ");
+                        }
                     }
                     }
                 }
                 }
-
-                arg.Append(videoDecoder + " ");
             }
             }
 
 
             arg.Append("-i ")
             arg.Append("-i ")
@@ -503,17 +500,6 @@ namespace MediaBrowser.Controller.MediaEncoding
                 && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
                 && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
                 && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
                 && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
             {
             {
-                if (state.VideoStream != null && state.VideoStream.Width.HasValue)
-                {
-                    // This is hacky but not sure how to get the exact subtitle resolution
-                    int height = Convert.ToInt32(state.VideoStream.Width.Value / 16.0 * 9.0);
-
-                    arg.Append(" -canvas_size ")
-                        .Append(state.VideoStream.Width.Value.ToString(CultureInfo.InvariantCulture))
-                        .Append(':')
-                        .Append(height.ToString(CultureInfo.InvariantCulture));
-                }
-
                 var subtitlePath = state.SubtitleStream.Path;
                 var subtitlePath = state.SubtitleStream.Path;
 
 
                 if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase))
@@ -1546,9 +1532,12 @@ namespace MediaBrowser.Controller.MediaEncoding
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Gets the internal graphical subtitle param.
+        /// Gets the graphical subtitle param.
         /// </summary>
         /// </summary>
-        public string GetGraphicalSubtitleParam(EncodingJobInfo state, EncodingOptions options, string outputVideoCodec)
+        public string GetGraphicalSubtitleParam(
+            EncodingJobInfo state,
+            EncodingOptions options,
+            string outputVideoCodec)
         {
         {
             var outputSizeParam = string.Empty;
             var outputSizeParam = string.Empty;
 
 
@@ -1562,54 +1551,77 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
             {
                 outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
                 outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
 
 
-                if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+                var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase);
+                if (index != -1)
                 {
                 {
-                    var index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
-                    if (index != -1)
-                    {
-                        outputSizeParam = "," + outputSizeParam.Substring(index);
-                    }
+                    outputSizeParam = "," + outputSizeParam.Substring(index);
                 }
                 }
                 else
                 else
                 {
                 {
-                    var index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
+                    index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
                     if (index != -1)
                     if (index != -1)
                     {
                     {
                         outputSizeParam = "," + outputSizeParam.Substring(index);
                         outputSizeParam = "," + outputSizeParam.Substring(index);
                     }
                     }
-                }
-            }
-
-            if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
-                && outputSizeParam.Length == 0)
-            {
-                outputSizeParam = ",format=nv12|vaapi,hwupload";
-
-                // Add parameters to use VAAPI with burn-in subttiles (GH issue #642)
-                if (state.SubtitleStream != null
-                    && state.SubtitleStream.IsTextSubtitleStream
-                    && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
-                {
-                    outputSizeParam += ",hwmap=mode=read+write+direct";
+                    else
+                    {
+                        index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
+                        if (index != -1)
+                        {
+                            outputSizeParam = "," + outputSizeParam.Substring(index);
+                        }
+                        else
+                        {
+                            index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
+                            if (index != -1)
+                            {
+                                outputSizeParam = "," + outputSizeParam.Substring(index);
+                            }
+                        }
+                    }
                 }
                 }
             }
             }
 
 
             var videoSizeParam = string.Empty;
             var videoSizeParam = string.Empty;
+            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options);
 
 
             // Setup subtitle scaling
             // Setup subtitle scaling
             if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue)
             if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue)
             {
             {
+                // force_original_aspect_ratio=decrease
+                // Enable decreasing output video width or height if necessary to keep the original aspect ratio
                 videoSizeParam = string.Format(
                 videoSizeParam = string.Format(
                     CultureInfo.InvariantCulture,
                     CultureInfo.InvariantCulture,
-                    "scale={0}:{1}",
+                    "scale={0}:{1}:force_original_aspect_ratio=decrease",
                     state.VideoStream.Width.Value,
                     state.VideoStream.Width.Value,
                     state.VideoStream.Height.Value);
                     state.VideoStream.Height.Value);
 
 
-                //For QSV, feed it into hardware encoder now
+                // For QSV, feed it into hardware encoder now
                 if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     videoSizeParam += ",hwupload=extra_hw_frames=64";
                     videoSizeParam += ",hwupload=extra_hw_frames=64";
                 }
                 }
+
+                // For VAAPI and CUVID decoder
+                // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video,
+                // thus needs to be manually adjusted.
+                if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+                    || (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1)
+                {
+                    var videoStream = state.VideoStream;
+                    var inputWidth = videoStream?.Width;
+                    var inputHeight = videoStream?.Height;
+                    var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
+
+                    if (width.HasValue && height.HasValue)
+                    {
+                        videoSizeParam = string.Format(
+                        CultureInfo.InvariantCulture,
+                        "scale={0}:{1}:force_original_aspect_ratio=decrease",
+                        width.Value,
+                        height.Value);
+                    }
+                }
             }
             }
 
 
             var mapPrefix = state.SubtitleStream.IsExternal ?
             var mapPrefix = state.SubtitleStream.IsExternal ?
@@ -1620,12 +1632,34 @@ namespace MediaBrowser.Controller.MediaEncoding
                 ? 0
                 ? 0
                 : state.SubtitleStream.Index;
                 : state.SubtitleStream.Index;
 
 
-            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options);
-
             // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
             // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
             var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"";
             var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"";
 
 
-            if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+            // When the input may or may not be hardware VAAPI decodable
+            if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && options.EnableHardwareEncoding)
+            {
+                /*
+                    [base]: HW scaling video to OutputSize
+                    [sub]: SW scaling subtitle to FixedOutputSize
+                    [base][sub]: SW overlay
+                */
+                outputSizeParam = outputSizeParam.TrimStart(',');
+                retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
+            }
+
+            // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
+            else if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && !options.EnableHardwareEncoding)
+            {
+                /*
+                    [base]: SW scaling video to OutputSize
+                    [sub]: SW scaling subtitle to FixedOutputSize
+                    [base][sub]: SW overlay
+                */
+                outputSizeParam = outputSizeParam.TrimStart(',');
+                retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"";
+            }
+
+            else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             {
             {
                 /*
                 /*
                     QSV in FFMpeg can now setup hardware overlay for transcodes.
                     QSV in FFMpeg can now setup hardware overlay for transcodes.
@@ -1689,7 +1723,8 @@ namespace MediaBrowser.Controller.MediaEncoding
             return (Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight));
             return (Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight));
         }
         }
 
 
-        public List<string> GetScalingFilters(int? videoWidth,
+        public List<string> GetScalingFilters(EncodingJobInfo state,
+            int? videoWidth,
             int? videoHeight,
             int? videoHeight,
             Video3DFormat? threedFormat,
             Video3DFormat? threedFormat,
             string videoDecoder,
             string videoDecoder,
@@ -1708,7 +1743,9 @@ namespace MediaBrowser.Controller.MediaEncoding
                 requestedMaxWidth,
                 requestedMaxWidth,
                 requestedMaxHeight);
                 requestedMaxHeight);
 
 
-            if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) || string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+            var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+
+            if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs)
                 && width.HasValue
                 && width.HasValue
                 && height.HasValue)
                 && height.HasValue)
             {
             {
@@ -1738,7 +1775,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                     filters.Add(string.Format(CultureInfo.InvariantCulture, "scale_{0}=format=nv12", vaapi_or_qsv));
                     filters.Add(string.Format(CultureInfo.InvariantCulture, "scale_{0}=format=nv12", vaapi_or_qsv));
                 }
                 }
             }
             }
-            else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1
+            else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1
                 && width.HasValue
                 && width.HasValue
                 && height.HasValue)
                 && height.HasValue)
             {
             {
@@ -1942,8 +1979,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         public string GetOutputSizeParam(
         public string GetOutputSizeParam(
             EncodingJobInfo state,
             EncodingJobInfo state,
             EncodingOptions options,
             EncodingOptions options,
-            string outputVideoCodec,
-            bool allowTimeStampCopy = true)
+            string outputVideoCodec)
         {
         {
             // http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/
             // http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/
 
 
@@ -1952,42 +1988,57 @@ namespace MediaBrowser.Controller.MediaEncoding
             var videoStream = state.VideoStream;
             var videoStream = state.VideoStream;
             var filters = new List<string>();
             var filters = new List<string>();
 
 
+            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options);
+            var inputWidth = videoStream?.Width;
+            var inputHeight = videoStream?.Height;
+            var threeDFormat = state.MediaSource.Video3DFormat;
+
+            var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+
+            // When the input may or may not be hardware VAAPI decodable
+            if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && options.EnableHardwareEncoding)
+            {
+                filters.Add("format=nv12|vaapi");
+                filters.Add("hwupload");
+            }
+
+            // When the input may or may not be hardware QSV decodable            
+            else if (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.EnableHardwareEncoding)
+            {
+                if (!hasTextSubs)
+                {
+                    filters.Add("format=nv12|qsv");
+                    filters.Add("hwupload=extra_hw_frames=64");
+                }
+            }
+
             // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
             // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
-            var hwType = options.HardwareAccelerationType ?? string.Empty;
-            if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !options.EnableHardwareEncoding)
+
+            else if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && !options.EnableHardwareEncoding)
             {
             {
-                filters.Add("hwdownload");
+                var codec = videoStream.Codec.ToLowerInvariant();
+                var pixelFormat = videoStream.PixelFormat.ToLowerInvariant();
 
 
-                // If transcoding from 10 bit, transform colour spaces too
-                if (!string.IsNullOrEmpty(videoStream.PixelFormat)
-                    && videoStream.PixelFormat.IndexOf("p10", StringComparison.OrdinalIgnoreCase) != -1
-                    && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+                // Assert 10-bit hardware VAAPI decodable
+                if ((pixelFormat ?? string.Empty).IndexOf("p10", StringComparison.OrdinalIgnoreCase) != -1
+                    && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+                        || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+                        || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
                 {
                 {
+                    filters.Add("hwdownload");
                     filters.Add("format=p010le");
                     filters.Add("format=p010le");
                     filters.Add("format=nv12");
                     filters.Add("format=nv12");
                 }
                 }
-                else
+
+                // Assert 8-bit hardware VAAPI decodable
+                else if ((pixelFormat ?? string.Empty).IndexOf("p10", StringComparison.OrdinalIgnoreCase) == -1)
                 {
                 {
+                    filters.Add("hwdownload");
                     filters.Add("format=nv12");
                     filters.Add("format=nv12");
                 }
                 }
             }
             }
 
 
-            if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
-            {
-                filters.Add("format=nv12|vaapi");
-                filters.Add("hwupload");
-            }
-
-            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options);
-
-            // If we are software decoding, and hardware encoding
-            if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
-                && (string.IsNullOrEmpty(videoDecoder) || !videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)))
-            {
-                filters.Add("format=nv12|qsv");
-                filters.Add("hwupload=extra_hw_frames=64");
-            }
-
+            // Add hardware deinterlace filter before scaling filter
             if (state.DeInterlace("h264", true))
             if (state.DeInterlace("h264", true))
             {
             {
                 if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
@@ -1996,17 +2047,23 @@ namespace MediaBrowser.Controller.MediaEncoding
                 }
                 }
                 else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
                 else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_qsv"));
+                    if (!hasTextSubs)
+                    {
+                        filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_qsv"));
+                    }
                 }
                 }
             }
             }
 
 
-            if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
-                && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+            // Add software deinterlace filter before scaling filter
+            if (((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
+                && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
+                && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+                    || (hasTextSubs && state.DeInterlace("h264", true) && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)))
             {
             {
                 var inputFramerate = videoStream?.RealFrameRate;
                 var inputFramerate = videoStream?.RealFrameRate;
 
 
                 // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
                 // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
-                if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30)
+                if (string.Equals(options.DeinterlaceMethod, "yadif_bob", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30)
                 {
                 {
                     filters.Add("yadif=1:-1:0");
                     filters.Add("yadif=1:-1:0");
                 }
                 }
@@ -2016,11 +2073,21 @@ namespace MediaBrowser.Controller.MediaEncoding
                 }
                 }
             }
             }
 
 
-            var inputWidth = videoStream?.Width;
-            var inputHeight = videoStream?.Height;
-            var threeDFormat = state.MediaSource.Video3DFormat;
+            // Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr
+            filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
 
 
-            filters.AddRange(GetScalingFilters(inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
+            // Add parameters to use VAAPI with burn-in text subttiles (GH issue #642)
+            if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && options.EnableHardwareEncoding)
+            {
+                if (state.SubtitleStream != null
+                    && state.SubtitleStream.IsTextSubtitleStream
+                    && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
+                {
+                    // Test passed on Intel and AMD gfx
+                    filters.Add("hwmap=mode=read+write");
+                    filters.Add("format=nv12");
+                }
+            }
 
 
             var output = string.Empty;
             var output = string.Empty;
 
 
@@ -2038,11 +2105,6 @@ namespace MediaBrowser.Controller.MediaEncoding
                 {
                 {
                     filters.Add("hwmap");
                     filters.Add("hwmap");
                 }
                 }
-
-                if (allowTimeStampCopy)
-                {
-                    output += " -copyts";
-                }
             }
             }
 
 
             if (filters.Count > 0)
             if (filters.Count > 0)
@@ -2219,7 +2281,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
             {
                 inputModifier += " " + videoDecoder;
                 inputModifier += " " + videoDecoder;
 
 
-                if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1)
+                if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1)
                 {
                 {
                     var videoStream = state.VideoStream;
                     var videoStream = state.VideoStream;
                     var inputWidth = videoStream?.Width;
                     var inputWidth = videoStream?.Width;
@@ -2228,7 +2290,7 @@ namespace MediaBrowser.Controller.MediaEncoding
 
 
                     var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
                     var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
 
 
-                    if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1
+                    if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1
                         && width.HasValue
                         && width.HasValue
                         && height.HasValue)
                         && height.HasValue)
                     {
                     {
@@ -2526,6 +2588,12 @@ namespace MediaBrowser.Controller.MediaEncoding
                         case "h264":
                         case "h264":
                             if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
                             if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
                             {
                             {
+                                // cuvid decoder does not support 10-bit input
+                                if ((videoStream.BitDepth ?? 8) > 8)
+                                {
+                                    encodingOptions.HardwareDecodingCodecs = Array.Empty<string>();
+                                    return null;
+                                }
                                 return "-c:v h264_cuvid ";
                                 return "-c:v h264_cuvid ";
                             }
                             }
                             break;
                             break;
@@ -2773,14 +2841,27 @@ namespace MediaBrowser.Controller.MediaEncoding
                 var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
                 var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
 
 
                 var hasCopyTs = false;
                 var hasCopyTs = false;
+
                 // Add resolution params, if specified
                 // Add resolution params, if specified
                 if (!hasGraphicalSubs)
                 if (!hasGraphicalSubs)
                 {
                 {
                     var outputSizeParam = GetOutputSizeParam(state, encodingOptions, videoCodec);
                     var outputSizeParam = GetOutputSizeParam(state, encodingOptions, videoCodec);
+
                     args += outputSizeParam;
                     args += outputSizeParam;
+
                     hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1;
                     hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1;
                 }
                 }
 
 
+                // This is for graphical subs
+                if (hasGraphicalSubs)
+                {
+                    var graphicalSubtitleParam = GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
+
+                    args += graphicalSubtitleParam;
+
+                    hasCopyTs = graphicalSubtitleParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1;
+                }
+
                 if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
                 if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
                 {
                 {
                     if (!hasCopyTs)
                     if (!hasCopyTs)
@@ -2788,13 +2869,12 @@ namespace MediaBrowser.Controller.MediaEncoding
                         args += " -copyts";
                         args += " -copyts";
                     }
                     }
 
 
-                    args += " -avoid_negative_ts disabled -start_at_zero";
-                }
+                    args += " -avoid_negative_ts disabled";
 
 
-                // This is for internal graphical subs
-                if (hasGraphicalSubs)
-                {
-                    args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
+                    if (!(state.SubtitleStream != null && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream))
+                    {
+                        args += " -start_at_zero";
+                    }
                 }
                 }
 
 
                 var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultPreset);
                 var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultPreset);
@@ -2900,6 +2980,5 @@ namespace MediaBrowser.Controller.MediaEncoding
                 string.Empty,
                 string.Empty,
                 string.Empty).Trim();
                 string.Empty).Trim();
         }
         }
-
     }
     }
 }
 }

+ 12 - 4
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs

@@ -183,9 +183,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
 
 
         private async Task<Stream> GetSubtitleStream(string path, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
         private async Task<Stream> GetSubtitleStream(string path, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
         {
         {
-            using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
+            if (requiresCharset)
             {
             {
-                if (requiresCharset)
+                using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
                 {
                 {
                     var result = CharsetDetector.DetectFromStream(stream).Detected;
                     var result = CharsetDetector.DetectFromStream(stream).Detected;
                     stream.Position = 0;
                     stream.Position = 0;
@@ -200,9 +200,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                         return new MemoryStream(Encoding.UTF8.GetBytes(text));
                         return new MemoryStream(Encoding.UTF8.GetBytes(text));
                     }
                     }
                 }
                 }
-
-                return stream;
             }
             }
+
+            return File.OpenRead(path);
         }
         }
 
 
         private async Task<SubtitleInfo> GetReadableFile(
         private async Task<SubtitleInfo> GetReadableFile(
@@ -731,6 +731,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             {
             {
                 var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName;
                 var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName;
 
 
+                // UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding
+                if ((path.EndsWith(".ass") || path.EndsWith(".ssa"))
+                    && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase)
+                        || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase)))
+                {
+                    charset = "";
+                }
+
                 _logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path);
                 _logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path);
 
 
                 return charset;
                 return charset;

+ 1 - 0
MediaBrowser.Model/Configuration/EncodingOptions.cs

@@ -40,6 +40,7 @@ namespace MediaBrowser.Model.Configuration
             VaapiDevice = "/dev/dri/renderD128";
             VaapiDevice = "/dev/dri/renderD128";
             H264Crf = 23;
             H264Crf = 23;
             H265Crf = 28;
             H265Crf = 28;
+            DeinterlaceMethod = "yadif";
             EnableHardwareEncoding = true;
             EnableHardwareEncoding = true;
             EnableSubtitleExtraction = true;
             EnableSubtitleExtraction = true;
             HardwareDecodingCodecs = new string[] { "h264", "vc1" };
             HardwareDecodingCodecs = new string[] { "h264", "vc1" };

+ 1 - 0
MediaBrowser.Model/Entities/ChapterInfo.cs

@@ -26,6 +26,7 @@ namespace MediaBrowser.Model.Entities
         /// </summary>
         /// </summary>
         /// <value>The image path.</value>
         /// <value>The image path.</value>
         public string ImagePath { get; set; }
         public string ImagePath { get; set; }
+
         public DateTime ImageDateModified { get; set; }
         public DateTime ImageDateModified { get; set; }
 
 
         public string ImageTag { get; set; }
         public string ImageTag { get; set; }

+ 6 - 0
MediaBrowser.Model/Extensions/StringHelper.cs

@@ -22,6 +22,11 @@ namespace MediaBrowser.Model.Extensions
                 return str;
                 return str;
             }
             }
 
 
+#if NETSTANDARD2_0
+            char[] a = str.ToCharArray();
+            a[0] = char.ToUpperInvariant(a[0]);
+            return new string(a);
+#else
             return string.Create(
             return string.Create(
                 str.Length,
                 str.Length,
                 str,
                 str,
@@ -33,6 +38,7 @@ namespace MediaBrowser.Model.Extensions
                         chars[i] = buf[i];
                         chars[i] = buf[i];
                     }
                     }
                 });
                 });
+#endif
         }
         }
     }
     }
 }
 }

+ 3 - 3
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
     <Authors>Jellyfin Contributors</Authors>
     <Authors>Jellyfin Contributors</Authors>
@@ -8,7 +8,7 @@
   </PropertyGroup>
   </PropertyGroup>
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netstandard2.1</TargetFramework>
+    <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
     <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
@@ -16,7 +16,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
-    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.3" />
     <PackageReference Include="System.Globalization" Version="4.3.0" />
     <PackageReference Include="System.Globalization" Version="4.3.0" />
     <PackageReference Include="System.Text.Json" Version="4.7.0" />
     <PackageReference Include="System.Text.Json" Version="4.7.0" />
   </ItemGroup>
   </ItemGroup>

+ 2 - 2
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -11,8 +11,8 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" />
-    <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.3" />
     <PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
     <PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
     <PackageReference Include="PlaylistsNET" Version="1.0.4" />
     <PackageReference Include="PlaylistsNET" Version="1.0.4" />
     <PackageReference Include="TvDbSharper" Version="3.0.1" />
     <PackageReference Include="TvDbSharper" Version="3.0.1" />

+ 8 - 4
MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs

@@ -14,6 +14,7 @@ using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using MediaBrowser.Model.Globalization;
 
 
 namespace MediaBrowser.Providers.MediaInfo
 namespace MediaBrowser.Providers.MediaInfo
 {
 {
@@ -25,6 +26,7 @@ namespace MediaBrowser.Providers.MediaInfo
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IJsonSerializer _json;
         private readonly IJsonSerializer _json;
+        private readonly ILocalizationManager _localization;
 
 
         public SubtitleScheduledTask(
         public SubtitleScheduledTask(
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
@@ -32,7 +34,8 @@ namespace MediaBrowser.Providers.MediaInfo
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             ISubtitleManager subtitleManager,
             ISubtitleManager subtitleManager,
             ILogger<SubtitleScheduledTask> logger,
             ILogger<SubtitleScheduledTask> logger,
-            IMediaSourceManager mediaSourceManager)
+            IMediaSourceManager mediaSourceManager,
+            ILocalizationManager localization)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _config = config;
             _config = config;
@@ -40,6 +43,7 @@ namespace MediaBrowser.Providers.MediaInfo
             _logger = logger;
             _logger = logger;
             _mediaSourceManager = mediaSourceManager;
             _mediaSourceManager = mediaSourceManager;
             _json = json;
             _json = json;
+            _localization = localization;
         }
         }
 
 
         private SubtitleOptions GetOptions()
         private SubtitleOptions GetOptions()
@@ -204,11 +208,11 @@ namespace MediaBrowser.Providers.MediaInfo
             };
             };
         }
         }
 
 
-        public string Name => "Download missing subtitles";
+        public string Name => _localization.GetLocalizedString("TaskDownloadMissingSubtitles");
 
 
-        public string Description => "Searches the internet for missing subtitles based on metadata configuration.";
+        public string Description => _localization.GetLocalizedString("TaskDownloadMissingSubtitlesDescription");
 
 
-        public string Category => "Library";
+        public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
 
 
         public string Key => "DownloadSubtitles";
         public string Key => "DownloadSubtitles";
 
 

+ 5 - 1
MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs

@@ -32,7 +32,11 @@ namespace MediaBrowser.Providers.Plugins.MusicBrainz
             {
             {
                 if (value < Plugin.DefaultRateLimit && _server == Plugin.DefaultServer)
                 if (value < Plugin.DefaultRateLimit && _server == Plugin.DefaultServer)
                 {
                 {
-                    RateLimit = Plugin.DefaultRateLimit;
+                    _rateLimit = Plugin.DefaultRateLimit;
+                }
+                else
+                {
+                    _rateLimit = value;
                 }
                 }
             }
             }
         }
         }

+ 5 - 1
MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs

@@ -344,7 +344,11 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
                 series.ProductionYear = date.Year;
                 series.ProductionYear = date.Year;
             }
             }
 
 
-            series.RunTimeTicks = TimeSpan.FromMinutes(Convert.ToDouble(tvdbSeries.Runtime)).Ticks;
+            if (!string.IsNullOrEmpty(tvdbSeries.Runtime) && double.TryParse(tvdbSeries.Runtime, out double runtime))
+            {
+                series.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
+            }
+
             foreach (var genre in tvdbSeries.Genre)
             foreach (var genre in tvdbSeries.Genre)
             {
             {
                 series.AddGenre(genre);
                 series.AddGenre(genre);

+ 1 - 1
tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

@@ -11,7 +11,7 @@
     <PackageReference Include="AutoFixture" Version="4.11.0" />
     <PackageReference Include="AutoFixture" Version="4.11.0" />
     <PackageReference Include="AutoFixture.AutoMoq" Version="4.11.0" />
     <PackageReference Include="AutoFixture.AutoMoq" Version="4.11.0" />
     <PackageReference Include="AutoFixture.Xunit2" Version="4.11.0" />
     <PackageReference Include="AutoFixture.Xunit2" Version="4.11.0" />
-    <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.3" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />