Переглянути джерело

Merge branch 'master' into fix-env

Joshua M. Boniface 6 роки тому
батько
коміт
20033f2275
70 змінених файлів з 450 додано та 378 видалено
  1. 1 0
      CONTRIBUTORS.md
  2. 5 4
      Emby.Dlna/DlnaManager.cs
  3. 2 2
      Emby.Dlna/Main/DlnaEntryPoint.cs
  4. 3 1
      Emby.Notifications/Notifications.cs
  5. 4 1
      Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
  6. 21 29
      Emby.Server.Implementations/ApplicationHost.cs
  7. 1 1
      Emby.Server.Implementations/Collections/CollectionManager.cs
  8. 1 1
      Emby.Server.Implementations/Devices/DeviceManager.cs
  9. 3 1
      Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
  10. 5 3
      Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  11. 4 1
      Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
  12. 4 1
      Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
  13. 4 1
      Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
  14. 5 2
      Emby.Server.Implementations/EntryPoints/StartupWizard.cs
  15. 4 1
      Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
  16. 3 1
      Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
  17. 2 1
      Emby.Server.Implementations/IO/LibraryMonitor.cs
  18. 8 8
      Emby.Server.Implementations/Library/MediaSourceManager.cs
  19. 3 1
      Emby.Server.Implementations/Library/UserManager.cs
  20. 1 1
      Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  21. 3 2
      Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
  22. 85 102
      Emby.Server.Implementations/Localization/LocalizationManager.cs
  23. 0 0
      Emby.Server.Implementations/Localization/Ratings/br.csv
  24. 0 0
      Emby.Server.Implementations/Localization/Ratings/ca.csv
  25. 0 0
      Emby.Server.Implementations/Localization/Ratings/co.csv
  26. 0 0
      Emby.Server.Implementations/Localization/Ratings/dk.csv
  27. 0 0
      Emby.Server.Implementations/Localization/Ratings/es.csv
  28. 0 0
      Emby.Server.Implementations/Localization/Ratings/fr.csv
  29. 0 0
      Emby.Server.Implementations/Localization/Ratings/gb.csv
  30. 0 0
      Emby.Server.Implementations/Localization/Ratings/ie.csv
  31. 0 0
      Emby.Server.Implementations/Localization/Ratings/jp.csv
  32. 0 0
      Emby.Server.Implementations/Localization/Ratings/kz.csv
  33. 0 0
      Emby.Server.Implementations/Localization/Ratings/mx.csv
  34. 0 0
      Emby.Server.Implementations/Localization/Ratings/nl.csv
  35. 0 0
      Emby.Server.Implementations/Localization/Ratings/nz.csv
  36. 0 0
      Emby.Server.Implementations/Localization/Ratings/ro.csv
  37. 0 0
      Emby.Server.Implementations/Localization/Ratings/uk.csv
  38. 0 0
      Emby.Server.Implementations/Localization/Ratings/us.csv
  39. 0 63
      Emby.Server.Implementations/Localization/TextLocalizer.cs
  40. 8 14
      Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
  41. 3 19
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  42. 3 19
      Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  43. 8 14
      Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
  44. 119 0
      Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
  45. 6 12
      Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
  46. 0 0
      Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
  47. 0 0
      Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
  48. 0 0
      Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
  49. 0 0
      Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
  50. 5 9
      Emby.Server.Implementations/Updates/InstallationManager.cs
  51. 1 5
      Jellyfin.Server/Program.cs
  52. 4 3
      MediaBrowser.Api/ApiEntryPoint.cs
  53. 4 3
      MediaBrowser.Api/ItemUpdateService.cs
  54. 2 2
      MediaBrowser.Common/IApplicationHost.cs
  55. 42 4
      MediaBrowser.Controller/Extensions/StringExtensions.cs
  56. 2 1
      MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
  57. 4 4
      MediaBrowser.Model/Globalization/ILocalizationManager.cs
  58. 1 2
      MediaBrowser.Providers/Manager/MetadataService.cs
  59. 5 10
      MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
  60. 12 6
      MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
  61. 2 4
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  62. 4 1
      MediaBrowser.WebDashboard/ServerEntryPoint.cs
  63. 4 1
      MediaBrowser.XbmcMetadata/EntryPoint.cs
  64. 1 2
      bump_version
  65. 15 0
      deployment/centos-package-x64/Dockerfile
  66. 1 0
      deployment/centos-package-x64/clean.sh
  67. 1 0
      deployment/centos-package-x64/package.sh
  68. 1 0
      deployment/centos-package-x64/pkg-src
  69. 1 1
      deployment/fedora-package-x64/pkg-src/jellyfin.env
  70. 19 14
      deployment/fedora-package-x64/pkg-src/jellyfin.spec

+ 1 - 0
CONTRIBUTORS.md

@@ -15,6 +15,7 @@
  - [cvium](https://github.com/cvium)
  - [wtayl0r](https://github.com/wtayl0r)
  - [TtheCreator](https://github.com/Tthecreator)
+ - [dkanada](https://github.com/dkanada)
  - [LogicalPhallacy](https://github.com/LogicalPhallacy/)
  - [RazeLighter777](https://github.com/RazeLighter777)
 

+ 5 - 4
Emby.Dlna/DlnaManager.cs

@@ -4,6 +4,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
+using System.Threading.Tasks;
 using Emby.Dlna.Profiles;
 using Emby.Dlna.Server;
 using MediaBrowser.Common.Configuration;
@@ -48,11 +49,11 @@ namespace Emby.Dlna
             _assemblyInfo = assemblyInfo;
         }
 
-        public void InitProfiles()
+        public async Task InitProfilesAsync()
         {
             try
             {
-                ExtractSystemProfiles();
+                await ExtractSystemProfilesAsync();
                 LoadProfiles();
             }
             catch (Exception ex)
@@ -359,7 +360,7 @@ namespace Emby.Dlna
             };
         }
 
-        private void ExtractSystemProfiles()
+        private async Task ExtractSystemProfilesAsync()
         {
             var namespaceName = GetType().Namespace + ".Profiles.Xml.";
 
@@ -383,7 +384,7 @@ namespace Emby.Dlna
 
                         using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
                         {
-                            stream.CopyTo(fileStream);
+                            await stream.CopyToAsync(fileStream);
                         }
                     }
                 }

+ 2 - 2
Emby.Dlna/Main/DlnaEntryPoint.cs

@@ -125,9 +125,9 @@ namespace Emby.Dlna.Main
             Current = this;
         }
 
-        public void Run()
+        public async Task RunAsync()
         {
-            ((DlnaManager)_dlnaManager).InitProfiles();
+            await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
 
             ReloadComponents();
 

+ 3 - 1
Emby.Notifications/Notifications.cs

@@ -71,12 +71,14 @@ namespace Emby.Notifications
             _coreNotificationTypes = new CoreNotificationTypes(localization, appHost).GetNotificationTypes().Select(i => i.Type).ToArray();
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _libraryManager.ItemAdded += _libraryManager_ItemAdded;
             _appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
             _appHost.HasUpdateAvailableChanged += _appHost_HasUpdateAvailableChanged;
             _activityManager.EntryCreated += _activityManager_EntryCreated;
+
+            return Task.CompletedTask;
         }
 
         private async void _appHost_HasPendingRestartChanged(object sender, EventArgs e)

+ 4 - 1
Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Updates;
@@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.Activity
             _deviceManager = deviceManager;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _taskManager.TaskCompleted += _taskManager_TaskCompleted;
 
@@ -90,6 +91,8 @@ namespace Emby.Server.Implementations.Activity
             _deviceManager.CameraImageUploaded += _deviceManager_CameraImageUploaded;
 
             _appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
+
+            return Task.CompletedTask;
         }
 
         void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)

+ 21 - 29
Emby.Server.Implementations/ApplicationHost.cs

@@ -110,7 +110,6 @@ using MediaBrowser.XbmcMetadata.Providers;
 using Microsoft.Extensions.Logging;
 using ServiceStack;
 using ServiceStack.Text.Jsv;
-using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
 using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
 
 namespace Emby.Server.Implementations
@@ -302,7 +301,7 @@ namespace Emby.Server.Implementations
 
         private ILiveTvManager LiveTvManager { get; set; }
 
-        public ILocalizationManager LocalizationManager { get; set; }
+        public LocalizationManager LocalizationManager { get; set; }
 
         private IEncodingManager EncodingManager { get; set; }
         private IChannelManager ChannelManager { get; set; }
@@ -646,8 +645,10 @@ namespace Emby.Server.Implementations
         /// <summary>
         /// Runs the startup tasks.
         /// </summary>
-        public Task RunStartupTasks()
+        public async Task RunStartupTasks()
         {
+            Logger.LogInformation("Running startup tasks");
+
             Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
 
             ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
@@ -666,20 +667,20 @@ namespace Emby.Server.Implementations
             Logger.LogInformation("ServerId: {0}", SystemId);
 
             var entryPoints = GetExports<IServerEntryPoint>();
-            RunEntryPoints(entryPoints, true);
+
+            var now = DateTime.UtcNow;
+            await Task.WhenAll(StartEntryPoints(entryPoints, true));
+            Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
 
             Logger.LogInformation("Core startup complete");
             HttpServer.GlobalResponse = null;
 
-            Logger.LogInformation("Post-init migrations complete");
-
-            RunEntryPoints(entryPoints, false);
-            Logger.LogInformation("All entry points have started");
-
-            return Task.CompletedTask;
+            now = DateTime.UtcNow;
+            await Task.WhenAll(StartEntryPoints(entryPoints, false));
+            Logger.LogInformation("Executed all post-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
         }
 
-        private void RunEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
+        private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
         {
             foreach (var entryPoint in entryPoints)
             {
@@ -688,22 +689,13 @@ namespace Emby.Server.Implementations
                     continue;
                 }
 
-                var name = entryPoint.GetType().FullName;
-                Logger.LogInformation("Starting entry point {Name}", name);
-                var now = DateTime.UtcNow;
-                try
-                {
-                    entryPoint.Run();
-                }
-                catch (Exception ex)
-                {
-                    Logger.LogError(ex, "Error while running entrypoint {Name}", name);
-                }
-                Logger.LogInformation("Entry point completed: {Name}. Duration: {Duration} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
+                Logger.LogDebug("Starting entry point {Type}", entryPoint.GetType());
+
+                yield return entryPoint.RunAsync();
             }
         }
 
-        public void Init()
+        public async Task Init()
         {
             HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
             HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -733,7 +725,7 @@ namespace Emby.Server.Implementations
 
             SetHttpLimit();
 
-            RegisterResources();
+            await RegisterResources();
 
             FindParts();
         }
@@ -748,7 +740,7 @@ namespace Emby.Server.Implementations
         /// <summary>
         /// Registers resources that classes will depend on
         /// </summary>
-        protected void RegisterResources()
+        protected async Task RegisterResources()
         {
             RegisterSingleInstance(ConfigurationManager);
             RegisterSingleInstance<IApplicationHost>(this);
@@ -809,9 +801,9 @@ namespace Emby.Server.Implementations
             IAssemblyInfo assemblyInfo = new AssemblyInfo();
             RegisterSingleInstance(assemblyInfo);
 
-            LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory, assemblyInfo, new TextLocalizer());
-            StringExtensions.LocalizationManager = LocalizationManager;
-            RegisterSingleInstance(LocalizationManager);
+            LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory);
+            await LocalizationManager.LoadAll();
+            RegisterSingleInstance<ILocalizationManager>(LocalizationManager);
 
             BlurayExaminer = new BdInfoExaminer(FileSystemManager);
             RegisterSingleInstance(BlurayExaminer);

+ 1 - 1
Emby.Server.Implementations/Collections/CollectionManager.cs

@@ -353,7 +353,7 @@ namespace Emby.Server.Implementations.Collections
             _logger = logger;
         }
 
-        public async void Run()
+        public async Task RunAsync()
         {
             if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
             {

+ 1 - 1
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -425,7 +425,7 @@ namespace Emby.Server.Implementations.Devices
             _logger = logger;
         }
 
-        public async void Run()
+        public async Task RunAsync()
         {
             if (!_config.Configuration.CameraUploadUpgraded && _config.Configuration.IsStartupWizardCompleted)
             {

+ 3 - 1
Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs

@@ -37,12 +37,14 @@ namespace Emby.Server.Implementations.EntryPoints
             _timerFactory = timerFactory;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             if (_appHost.CanSelfRestart)
             {
                 _appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
             }
+
+            return Task.CompletedTask;
         }
 
         void _appHost_HasPendingRestartChanged(object sender, EventArgs e)

+ 5 - 3
Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -61,17 +61,17 @@ namespace Emby.Server.Implementations.EntryPoints
             return string.Join("|", values.ToArray());
         }
 
-        void _config_ConfigurationUpdated(object sender, EventArgs e)
+        private async void _config_ConfigurationUpdated(object sender, EventArgs e)
         {
             if (!string.Equals(_lastConfigIdentifier, GetConfigIdentifier(), StringComparison.OrdinalIgnoreCase))
             {
                 DisposeNat();
 
-                Run();
+                await RunAsync();
             }
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             if (_config.Configuration.EnableUPnP && _config.Configuration.EnableRemoteAccess)
             {
@@ -80,6 +80,8 @@ namespace Emby.Server.Implementations.EntryPoints
 
             _config.ConfigurationUpdated -= _config_ConfigurationUpdated;
             _config.ConfigurationUpdated += _config_ConfigurationUpdated;
+
+            return Task.CompletedTask;
         }
 
         private void Start()

+ 4 - 1
Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Threading;
+using System.Threading.Tasks;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -65,7 +66,7 @@ namespace Emby.Server.Implementations.EntryPoints
             _providerManager = providerManager;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _libraryManager.ItemAdded += libraryManager_ItemAdded;
             _libraryManager.ItemUpdated += libraryManager_ItemUpdated;
@@ -74,6 +75,8 @@ namespace Emby.Server.Implementations.EntryPoints
             _providerManager.RefreshCompleted += _providerManager_RefreshCompleted;
             _providerManager.RefreshStarted += _providerManager_RefreshStarted;
             _providerManager.RefreshProgress += _providerManager_RefreshProgress;
+
+            return Task.CompletedTask;
         }
 
         private Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>();

+ 4 - 1
Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Threading;
+using System.Threading.Tasks;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Plugins;
@@ -24,12 +25,14 @@ namespace Emby.Server.Implementations.EntryPoints
             _liveTvManager = liveTvManager;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
             _liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
             _liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
             _liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+
+            return Task.CompletedTask;
         }
 
         private void _liveTvManager_SeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)

+ 4 - 1
Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Threading;
+using System.Threading.Tasks;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Controller;
@@ -49,7 +50,7 @@ namespace Emby.Server.Implementations.EntryPoints
             _sessionManager = sessionManager;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _userManager.UserDeleted += userManager_UserDeleted;
             _userManager.UserUpdated += userManager_UserUpdated;
@@ -65,6 +66,8 @@ namespace Emby.Server.Implementations.EntryPoints
             _installationManager.PackageInstallationFailed += _installationManager_PackageInstallationFailed;
 
             _taskManager.TaskCompleted += _taskManager_TaskCompleted;
+
+            return Task.CompletedTask;
         }
 
         void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)

+ 5 - 2
Emby.Server.Implementations/EntryPoints/StartupWizard.cs

@@ -1,3 +1,4 @@
+using System.Threading.Tasks;
 using Emby.Server.Implementations.Browser;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
@@ -32,11 +33,11 @@ namespace Emby.Server.Implementations.EntryPoints
         /// <summary>
         /// Runs this instance.
         /// </summary>
-        public void Run()
+        public Task RunAsync()
         {
             if (!_appHost.CanLaunchWebBrowser)
             {
-                return;
+                return Task.CompletedTask;
             }
 
             if (!_config.Configuration.IsStartupWizardCompleted)
@@ -52,6 +53,8 @@ namespace Emby.Server.Implementations.EntryPoints
                     BrowserLauncher.OpenWebApp(_appHost);
                 }
             }
+
+            return Task.CompletedTask;
         }
 
         /// <summary>

+ 4 - 1
Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Threading.Tasks;
 using Emby.Server.Implementations.Udp;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Plugins;
@@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.EntryPoints
         /// <summary>
         /// Runs this instance.
         /// </summary>
-        public void Run()
+        public Task RunAsync()
         {
             var udpServer = new UdpServer(_logger, _appHost, _json, _socketFactory);
 
@@ -57,6 +58,8 @@ namespace Emby.Server.Implementations.EntryPoints
             {
                 _logger.LogError(ex, "Failed to start UDP Server");
             }
+
+            return Task.CompletedTask;
         }
 
         /// <summary>

+ 3 - 1
Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs

@@ -38,9 +38,11 @@ namespace Emby.Server.Implementations.EntryPoints
             _timerFactory = timerFactory;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
+
+            return Task.CompletedTask;
         }
 
         void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)

+ 2 - 1
Emby.Server.Implementations/IO/LibraryMonitor.cs

@@ -633,9 +633,10 @@ namespace Emby.Server.Implementations.IO
             _monitor = monitor;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _monitor.Start();
+            return Task.CompletedTask;
         }
 
         public void Dispose()

+ 8 - 8
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -322,18 +322,18 @@ namespace Emby.Server.Implementations.Library
 
         private string[] NormalizeLanguage(string language)
         {
-            if (language != null)
+            if (language == null)
             {
-                var culture = _localizationManager.FindLanguageInfo(language);
-                if (culture != null)
-                {
-                    return culture.ThreeLetterISOLanguageNames;
-                }
+                return Array.Empty<string>();
+            }
 
-                return new string[] { language };
+            var culture = _localizationManager.FindLanguageInfo(language);
+            if (culture != null)
+            {
+                return culture.ThreeLetterISOLanguageNames;
             }
 
-            return Array.Empty<string>();
+            return new string[] { language };
         }
 
         private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)

+ 3 - 1
Emby.Server.Implementations/Library/UserManager.cs

@@ -1182,9 +1182,11 @@ namespace Emby.Server.Implementations.Library
             _sessionManager = sessionManager;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated;
+
+            return Task.CompletedTask;
         }
 
         private void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)

+ 1 - 1
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -123,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             }
         }
 
-        public async void Start()
+        public async Task Start()
         {
             _timerProvider.RestartTimers();
 

+ 3 - 2
Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs

@@ -1,12 +1,13 @@
+using System.Threading.Tasks;
 using MediaBrowser.Controller.Plugins;
 
 namespace Emby.Server.Implementations.LiveTv.EmbyTV
 {
     public class EntryPoint : IServerEntryPoint
     {
-        public void Run()
+        public Task RunAsync()
         {
-            EmbyTV.Current.Start();
+            return EmbyTV.Current.Start();
         }
 
         public void Dispose()

Різницю між файлами не показано, бо вона завелика
+ 85 - 102
Emby.Server.Implementations/Localization/LocalizationManager.cs


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/br.txt → Emby.Server.Implementations/Localization/Ratings/br.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/ca.txt → Emby.Server.Implementations/Localization/Ratings/ca.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/co.txt → Emby.Server.Implementations/Localization/Ratings/co.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/dk.txt → Emby.Server.Implementations/Localization/Ratings/dk.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/es.txt → Emby.Server.Implementations/Localization/Ratings/es.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/fr.txt → Emby.Server.Implementations/Localization/Ratings/fr.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/gb.txt → Emby.Server.Implementations/Localization/Ratings/gb.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/ie.txt → Emby.Server.Implementations/Localization/Ratings/ie.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/jp.txt → Emby.Server.Implementations/Localization/Ratings/jp.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/kz.txt → Emby.Server.Implementations/Localization/Ratings/kz.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/mx.txt → Emby.Server.Implementations/Localization/Ratings/mx.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/nl.txt → Emby.Server.Implementations/Localization/Ratings/nl.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/nz.txt → Emby.Server.Implementations/Localization/Ratings/nz.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/ro.txt → Emby.Server.Implementations/Localization/Ratings/ro.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/uk.txt → Emby.Server.Implementations/Localization/Ratings/uk.csv


+ 0 - 0
Emby.Server.Implementations/Localization/Ratings/us.txt → Emby.Server.Implementations/Localization/Ratings/us.csv


+ 0 - 63
Emby.Server.Implementations/Localization/TextLocalizer.cs

@@ -1,63 +0,0 @@
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Localization
-{
-    public class TextLocalizer : ITextLocalizer
-    {
-        public string RemoveDiacritics(string text)
-        {
-            if (text == null)
-            {
-                throw new ArgumentNullException(nameof(text));
-            }
-
-            var chars = Normalize(text, NormalizationForm.FormD)
-                .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
-
-            return Normalize(string.Concat(chars), NormalizationForm.FormC);
-        }
-
-        private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
-        {
-            if (stripStringOnFailure)
-            {
-                try
-                {
-                    return text.Normalize(form);
-                }
-                catch (ArgumentException)
-                {
-                    // will throw if input contains invalid unicode chars
-                    // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
-                    text = StripInvalidUnicodeCharacters(text);
-                    return Normalize(text, form, false);
-                }
-            }
-
-            try
-            {
-                return text.Normalize(form);
-            }
-            catch (ArgumentException)
-            {
-                // if it still fails, return the original text
-                return text;
-            }
-        }
-
-        private static string StripInvalidUnicodeCharacters(string str)
-        {
-            var invalidCharactersRegex = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])");
-            return invalidCharactersRegex.Replace(str, "");
-        }
-
-        public string NormalizeFormKD(string text)
-        {
-            return text.Normalize(NormalizationForm.FormKD);
-        }
-    }
-}

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

@@ -68,8 +68,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
             };
         }
 
-        public string Key => "RefreshChapterImages";
-
         /// <summary>
         /// Returns the task to be executed
         /// </summary>
@@ -161,22 +159,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
             }
         }
 
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
         public string Name => "Chapter image extraction";
 
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
         public string Description => "Creates thumbnails for videos that have chapters.";
 
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
         public string Category => "Library";
+
+        public string Key => "RefreshChapterImages";
+
+        public bool IsHidden => false;
+
+        public bool IsEnabled => true;
+
+        public bool IsLogged => true;
     }
 }

+ 3 - 19
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -158,31 +158,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             }
         }
 
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
         public string Name => "Cache file cleanup";
 
-        public string Key => "DeleteCacheFiles";
-
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
         public string Description => "Deletes cache files no longer needed by the system";
 
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
         public string Category => "Maintenance";
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is hidden.
-        /// </summary>
-        /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
-        public bool IsHidden => true;
+        public string Key => "DeleteCacheFiles";
+
+        public bool IsHidden => false;
 
         public bool IsEnabled => true;
 

+ 3 - 19
Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -81,31 +81,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
             return Task.CompletedTask;
         }
 
-        public string Key => "CleanLogFiles";
-
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
         public string Name => "Log file cleanup";
 
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
         public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
 
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
         public string Category => "Maintenance";
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is hidden.
-        /// </summary>
-        /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
-        public bool IsHidden => true;
+        public string Key => "CleanLogFiles";
+
+        public bool IsHidden => false;
 
         public bool IsEnabled => true;
 

+ 8 - 14
Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs → Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs

@@ -47,8 +47,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
             };
         }
 
-        public string Key => "RefreshPeople";
-
         /// <summary>
         /// Returns the task to be executed
         /// </summary>
@@ -60,22 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
             return _libraryManager.ValidatePeople(cancellationToken, progress);
         }
 
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
         public string Name => "Refresh people";
 
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
         public string Description => "Updates metadata for actors and directors in your media library.";
 
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
         public string Category => "Library";
+
+        public string Key => "RefreshPeople";
+
+        public bool IsHidden => false;
+
+        public bool IsEnabled => true;
+
+        public bool IsLogged => true;
     }
 }

+ 119 - 0
Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs

@@ -0,0 +1,119 @@
+using MediaBrowser.Common;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Server.Implementations.ScheduledTasks
+{
+    /// <summary>
+    /// Plugin Update Task
+    /// </summary>
+    public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
+    {
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly ILogger _logger;
+
+        private readonly IInstallationManager _installationManager;
+
+        private readonly IApplicationHost _appHost;
+
+        public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
+        {
+            _logger = logger;
+            _installationManager = installationManager;
+            _appHost = appHost;
+        }
+
+        /// <summary>
+        /// Creates the triggers that define when the task will run
+        /// </summary>
+        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+        {
+            return new[] { 
+            
+                // At startup
+                new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
+
+                // Every so often
+                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
+            };
+        }
+
+        /// <summary>
+        /// Update installed plugins
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task.</returns>
+        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            progress.Report(0);
+
+            var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList();
+
+            progress.Report(10);
+
+            var numComplete = 0;
+
+            foreach (var package in packagesToInstall)
+            {
+                cancellationToken.ThrowIfCancellationRequested();
+
+                try
+                {
+                    await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
+                }
+                catch (OperationCanceledException)
+                {
+                    // InstallPackage has it's own inner cancellation token, so only throw this if it's ours
+                    if (cancellationToken.IsCancellationRequested)
+                    {
+                        throw;
+                    }
+                }
+                catch (HttpException ex)
+                {
+                    _logger.LogError(ex, "Error downloading {0}", package.name);
+                }
+                catch (IOException ex)
+                {
+                    _logger.LogError(ex, "Error updating {0}", package.name);
+                }
+
+                // Update progress
+                lock (progress)
+                {
+                    numComplete++;
+                    progress.Report(90.0 * numComplete / packagesToInstall.Count + 10);
+                }
+            }
+
+            progress.Report(100);
+        }
+
+        public string Name => "Check for plugin updates";
+
+        public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
+
+        public string Category => "Application";
+
+        public string Key => "PluginUpdates";
+
+        public bool IsHidden => false;
+
+        public bool IsEnabled => true;
+
+        public bool IsLogged => true;
+    }
+}

+ 6 - 12
Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs → Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs

@@ -58,24 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
             return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
         }
 
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
         public string Name => "Scan media library";
 
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
         public string Description => "Scans your media library and refreshes metatata based on configuration.";
 
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
         public string Category => "Library";
 
         public string Key => "RefreshLibrary";
+
+        public bool IsHidden => false;
+
+        public bool IsEnabled => true;
+
+        public bool IsLogged => true;
     }
 }

+ 0 - 0
Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs → Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs


+ 0 - 0
Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs → Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs


+ 0 - 0
Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs → Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs


+ 0 - 0
Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs → Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs


+ 5 - 9
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -164,15 +164,13 @@ namespace Emby.Server.Implementations.Updates
         /// Gets all available packages.
         /// </summary>
         /// <returns>Task{List{PackageInfo}}.</returns>
-        public Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
+        public async Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
             bool withRegistration = true,
             string packageType = null,
             Version applicationVersion = null)
         {
-            // TODO cvium: when plugins get back this would need to be fixed
-            // var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
-
-            return Task.FromResult(new List<PackageInfo>()); //FilterPackages(packages, packageType, applicationVersion);
+            var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
+            return FilterPackages(packages, packageType, applicationVersion);
         }
 
         /// <summary>
@@ -184,12 +182,10 @@ namespace Emby.Server.Implementations.Updates
         {
             using (var response = await _httpClient.SendAsync(new HttpRequestOptions
             {
-                Url = "https://www.mb3admin.local/admin/service/EmbyPackages.json",
+                Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
                 CancellationToken = cancellationToken,
                 Progress = new SimpleProgress<double>(),
-                CacheLength = GetCacheLength(),
-                CacheMode = CacheMode.Unconditional
-
+                CacheLength = GetCacheLength()
             }, "GET").ConfigureAwait(false))
             {
                 using (var stream = response.Content)

+ 1 - 5
Jellyfin.Server/Program.cs

@@ -114,12 +114,10 @@ namespace Jellyfin.Server
                 new NullImageEncoder(),
                 new NetworkManager(_loggerFactory, environmentInfo)))
             {
-                appHost.Init();
+                await appHost.Init();
 
                 appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
 
-                _logger.LogInformation("Running startup tasks");
-
                 await appHost.RunStartupTasks();
 
                 // TODO: read input for a stop command
@@ -133,8 +131,6 @@ namespace Jellyfin.Server
                 {
                     // Don't throw on cancellation
                 }
-
-                _logger.LogInformation("Disposing app host");
             }
 
             if (_restartOnShutdown)

+ 4 - 3
MediaBrowser.Api/ApiEntryPoint.cs

@@ -130,7 +130,7 @@ namespace MediaBrowser.Api
         /// <summary>
         /// Runs this instance.
         /// </summary>
-        public void Run()
+        public Task RunAsync()
         {
             try
             {
@@ -148,6 +148,8 @@ namespace MediaBrowser.Api
             {
                 Logger.LogError(ex, "Error deleting encoded media cache");
             }
+
+            return Task.CompletedTask;
         }
 
         public EncodingOptions GetEncodingOptions()
@@ -162,8 +164,7 @@ namespace MediaBrowser.Api
         {
             var path = _config.ApplicationPaths.TranscodingTempPath;
 
-            foreach (var file in _fileSystem.GetFilePaths(path, true)
-                .ToList())
+            foreach (var file in _fileSystem.GetFilePaths(path, true))
             {
                 _fileSystem.DeleteFile(file);
             }

+ 4 - 3
MediaBrowser.Api/ItemUpdateService.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
+using System.Threading.Tasks;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -60,15 +61,15 @@ namespace MediaBrowser.Api
             _fileSystem = fileSystem;
         }
 
-        public object Get(GetMetadataEditorInfo request)
+        public async Task<object> Get(GetMetadataEditorInfo request)
         {
             var item = _libraryManager.GetItemById(request.ItemId);
 
             var info = new MetadataEditorInfo
             {
-                ParentalRatingOptions = _localizationManager.GetParentalRatings(),
+                ParentalRatingOptions = _localizationManager.GetParentalRatings().ToArray(),
                 ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
-                Countries = _localizationManager.GetCountries(),
+                Countries = await _localizationManager.GetCountries(),
                 Cultures = _localizationManager.GetCultures()
             };
 

+ 2 - 2
MediaBrowser.Common/IApplicationHost.cs

@@ -89,7 +89,7 @@ namespace MediaBrowser.Common
         /// <typeparam name="T"></typeparam>
         /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
         /// <returns>IEnumerable{``0}.</returns>
-        IEnumerable<T> GetExports<T>(bool manageLiftime = true);
+        IEnumerable<T> GetExports<T>(bool manageLifetime = true);
 
         /// <summary>
         /// Updates the application.
@@ -131,7 +131,7 @@ namespace MediaBrowser.Common
         /// <summary>
         /// Inits this instance.
         /// </summary>
-        void Init();
+        Task Init();
 
         /// <summary>
         /// Creates the instance.

+ 42 - 4
MediaBrowser.Controller/Extensions/StringExtensions.cs

@@ -1,4 +1,8 @@
-using MediaBrowser.Model.Globalization;
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
 
 namespace MediaBrowser.Controller.Extensions
 {
@@ -7,11 +11,45 @@ namespace MediaBrowser.Controller.Extensions
     /// </summary>
     public static class StringExtensions
     {
-        public static ILocalizationManager LocalizationManager { get; set; }
-
         public static string RemoveDiacritics(this string text)
         {
-            return LocalizationManager.RemoveDiacritics(text);
+            if (text == null)
+            {
+                throw new ArgumentNullException(nameof(text));
+            }
+
+            var chars = Normalize(text, NormalizationForm.FormD)
+                .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
+
+            return Normalize(string.Concat(chars), NormalizationForm.FormC);
+        }
+
+        private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
+        {
+            if (stripStringOnFailure)
+            {
+                try
+                {
+                    return text.Normalize(form);
+                }
+                catch (ArgumentException)
+                {
+                    // will throw if input contains invalid unicode chars
+                    // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
+                    text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", "");
+                    return Normalize(text, form, false);
+                }
+            }
+
+            try
+            {
+                return text.Normalize(form);
+            }
+            catch (ArgumentException)
+            {
+                // if it still fails, return the original text
+                return text;
+            }
         }
     }
 }

+ 2 - 1
MediaBrowser.Controller/Plugins/IServerEntryPoint.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Plugins
 {
@@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Plugins
         /// <summary>
         /// Runs this instance.
         /// </summary>
-        void Run();
+        Task RunAsync();
     }
 
     public interface IRunBeforeStartup

+ 4 - 4
MediaBrowser.Model/Globalization/ILocalizationManager.cs

@@ -1,4 +1,6 @@
+using System.Collections.Generic;
 using System.Globalization;
+using System.Threading.Tasks;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Model.Globalization
@@ -17,12 +19,12 @@ namespace MediaBrowser.Model.Globalization
         /// Gets the countries.
         /// </summary>
         /// <returns>IEnumerable{CountryInfo}.</returns>
-        CountryInfo[] GetCountries();
+        Task<CountryInfo[]> GetCountries();
         /// <summary>
         /// Gets the parental ratings.
         /// </summary>
         /// <returns>IEnumerable{ParentalRating}.</returns>
-        ParentalRating[] GetParentalRatings();
+        IEnumerable<ParentalRating> GetParentalRatings();
         /// <summary>
         /// Gets the rating level.
         /// </summary>
@@ -51,8 +53,6 @@ namespace MediaBrowser.Model.Globalization
         /// <returns>IEnumerable{LocalizatonOption}.</returns>
         LocalizationOption[] GetLocalizationOptions();
 
-        string RemoveDiacritics(string text);
-
         string NormalizeFormKD(string text);
 
         bool HasUnicodeCategory(string value, UnicodeCategory category);

+ 1 - 2
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -566,8 +566,7 @@ namespace MediaBrowser.Providers.Manager
                 var providersWithChanges = providers
                     .Where(i =>
                     {
-                        var hasFileChangeMonitor = i as IHasItemChangeMonitor;
-                        if (hasFileChangeMonitor != null)
+                        if (i is IHasItemChangeMonitor hasFileChangeMonitor)
                         {
                             return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
                         }

+ 5 - 10
MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs

@@ -74,17 +74,12 @@ namespace MediaBrowser.Providers.MediaInfo
                 }
             }
 
-            if (item.SupportsLocalMetadata)
+            if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder
+                && !video.SubtitleFiles.SequenceEqual(
+                        _subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
             {
-                if (video != null && !video.IsPlaceHolder)
-                {
-                    if (!video.SubtitleFiles
-                        .SequenceEqual(_subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
-                    {
-                        _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
-                        return true;
-                    }
-                }
+                _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
+                return true;
             }
 
             return false;

+ 12 - 6
MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs

@@ -36,12 +36,6 @@ namespace MediaBrowser.Providers.MediaInfo
             _json = json;
         }
 
-        public string Name => "Download missing subtitles";
-
-        public string Description => "Searches the internet for missing subtitles based on metadata configuration.";
-
-        public string Category => "Library";
-
         private SubtitleOptions GetOptions()
         {
             return _config.GetConfiguration<SubtitleOptions>("subtitles");
@@ -204,6 +198,18 @@ namespace MediaBrowser.Providers.MediaInfo
             };
         }
 
+        public string Name => "Download missing subtitles";
+
+        public string Description => "Searches the internet for missing subtitles based on metadata configuration.";
+
+        public string Category => "Library";
+
         public string Key => "DownloadSubtitles";
+
+        public bool IsHidden => false;
+
+        public bool IsEnabled => true;
+
+        public bool IsLogged => true;
     }
 }

+ 2 - 4
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -425,11 +425,9 @@ namespace MediaBrowser.WebDashboard.Api
         private async Task DumpFile(PackageCreator packageCreator, string resourceVirtualPath, string destinationFilePath, string mode, string appVersion)
         {
             using (var stream = await packageCreator.GetResource(resourceVirtualPath, mode, null, appVersion).ConfigureAwait(false))
+            using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
             {
-                using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
-                {
-                    stream.CopyTo(fs);
-                }
+                await stream.CopyToAsync(fs);
             }
         }
 

+ 4 - 1
MediaBrowser.WebDashboard/ServerEntryPoint.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading.Tasks;
 using MediaBrowser.Common;
 using MediaBrowser.Controller.Plugins;
 
@@ -23,9 +24,11 @@ namespace MediaBrowser.WebDashboard
             Instance = this;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             PluginConfigurationPages = _appHost.GetExports<IPluginConfigurationPage>().ToList();
+
+            return Task.CompletedTask;
         }
 
         public void Dispose()

+ 4 - 1
MediaBrowser.XbmcMetadata/EntryPoint.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -28,9 +29,11 @@ namespace MediaBrowser.XbmcMetadata
             _config = config;
         }
 
-        public void Run()
+        public Task RunAsync()
         {
             _userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
+
+            return Task.CompletedTask;
         }
 
         void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)

+ 1 - 2
bump_version

@@ -68,8 +68,7 @@ new_version="$1"
 # Parse the version from the AssemblyVersion
 old_version="$(
     grep "AssemblyVersion" ${shared_version_file} \
-        | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/' \
-        | sed -E 's/.0$//'
+        | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/'
 )"
 
 # Set the shared version to the specified new_version

+ 15 - 0
deployment/centos-package-x64/Dockerfile

@@ -0,0 +1,15 @@
+FROM centos:7
+ARG HOME=/build
+RUN mkdir /build && \
+    yum install -y @buildsys-build rpmdevtools yum-plugins-core && \
+    rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm && \
+    rpmdev-setuptree
+
+WORKDIR /build/rpmbuild
+COPY ./deployment/centos-package-x64/pkg-src/jellyfin.spec SPECS
+COPY ./deployment/centos-package-x64/pkg-src/ SOURCES
+
+RUN spectool -g -R SPECS/jellyfin.spec && \
+    rpmbuild -bs SPECS/jellyfin.spec && \
+    yum-builddep  -y SRPMS/jellyfin-*.src.rpm && \
+    rpmbuild -bb SPECS/jellyfin.spec;

+ 1 - 0
deployment/centos-package-x64/clean.sh

@@ -0,0 +1 @@
+../fedora-package-x64/clean.sh

+ 1 - 0
deployment/centos-package-x64/package.sh

@@ -0,0 +1 @@
+../fedora-package-x64/package.sh

+ 1 - 0
deployment/centos-package-x64/pkg-src

@@ -0,0 +1 @@
+../fedora-package-x64/pkg-src

+ 1 - 1
deployment/fedora-package-x64/pkg-src/jellyfin.env

@@ -18,7 +18,7 @@
 JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin"
 JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin"
 JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin"
-JELLYFIN_CACHE_DIRECTORY="/var/log/jellyfin"
+JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin"
 
 # In-App service control
 JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh"

+ 19 - 14
deployment/fedora-package-x64/pkg-src/jellyfin.spec

@@ -1,11 +1,11 @@
 %global         debug_package %{nil}
-# jellyfin tag to package
-%global         gittag v10.1.0
-# Taglib-sharp commit of the submodule since github archive doesn't include submodules
-%global         taglib_commit ee5ab21742b71fd1b87ee24895582327e9e04776
-%global         taglib_shortcommit %(c=%{taglib_commit}; echo ${c:0:7})
+# Set the dotnet runtime
+%if 0%{?fedora}
+%global         dotnet_runtime  fedora-x64
+%else
+%global         dotnet_runtime  centos-x64
+%endif
 
-AutoReq:        no
 Name:           jellyfin
 Version:        10.1.0
 Release:        1%{?dist}
@@ -31,13 +31,11 @@ BuildRequires:  dotnet-sdk-2.2
 # RPMfusion free
 Requires:       ffmpeg
 
-# For the update-db-paths.sh script to fix emby paths to jellyfin
-%{?fedora:Recommends: sqlite}
-
 # Fedora has openssl1.1 which is incompatible with dotnet 
 %{?fedora:Requires: compat-openssl10}
-# Disable Automatic Dependency Processing for Centos
-%{?el7:AutoReqProv: no}
+
+# Disable Automatic Dependency Processing
+AutoReqProv:    no
 
 %description
 Jellyfin is a free software media system that puts you in control of managing and streaming your media.
@@ -51,7 +49,7 @@ Jellyfin is a free software media system that puts you in control of managing an
 %install
 export DOTNET_CLI_TELEMETRY_OPTOUT=1
 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
-dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime fedora-x64 Jellyfin.Server
+dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime %{dotnet_runtime} Jellyfin.Server
 %{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/%{name}/LICENSE
 %{__install} -D -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
 %{__install} -D -m 0644 Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/%{name}/logging.json
@@ -63,6 +61,7 @@ EOF
 %{__mkdir} -p %{buildroot}%{_sharedstatedir}/jellyfin
 %{__mkdir} -p %{buildroot}%{_sysconfdir}/%{name}
 %{__mkdir} -p %{buildroot}%{_var}/log/jellyfin
+%{__mkdir} -p %{buildroot}%{_var}/cache/jellyfin
 
 %{__install} -D -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/%{name}.service
 %{__install} -D -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/%{name}
@@ -90,8 +89,9 @@ EOF
 %config(noreplace) %attr(600,root,root) %{_sysconfdir}/sudoers.d/%{name}-sudoers
 %config(noreplace) %{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
 %config(noreplace) %attr(644,jellyfin,jellyfin) %{_sysconfdir}/%{name}/logging.json
-%attr(-,jellyfin,jellyfin) %dir %{_sharedstatedir}/jellyfin
+%attr(750,jellyfin,jellyfin) %dir %{_sharedstatedir}/jellyfin
 %attr(-,jellyfin,jellyfin) %dir %{_var}/log/jellyfin
+%attr(750,jellyfin,jellyfin) %dir %{_var}/cache/jellyfin
 %if 0%{?fedora}
 %license LICENSE
 %else
@@ -106,7 +106,7 @@ getent passwd jellyfin >/dev/null || \
 exit 0
 
 %post
-# Move existing configuration to /etc/jellyfin and symlink config to /etc/jellyfin
+# Move existing configuration cache and logs to their new locations and symlink them.
 if [ $1 -gt 1 ] ; then
     service_state=$(systemctl is-active jellyfin.service)
     if [ "${service_state}" = "active" ]; then
@@ -122,6 +122,11 @@ if [ $1 -gt 1 ] ; then
         rmdir %{_sharedstatedir}/%{name}/logs
         ln -sf %{_var}/log/jellyfin  %{_sharedstatedir}/%{name}/logs
     fi
+    if [ ! -L %{_sharedstatedir}/%{name}/cache ]; then
+        mv %{_sharedstatedir}/%{name}/cache/* %{_var}/cache/jellyfin
+        rmdir %{_sharedstatedir}/%{name}/cache
+        ln -sf %{_var}/cache/jellyfin  %{_sharedstatedir}/%{name}/cache
+    fi
     if [ "${service_state}" = "active" ]; then
         systemctl start jellyfin.service
     fi

Деякі файли не було показано, через те що забагато файлів було змінено