diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index eca16ad382..5e3455fba5 100644 --- a/CONTRIBUTORS.md +++ b/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) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index a43888270b..c507b14e9f 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/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); } } } diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index ad90da49b7..7398b24cd8 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/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(); diff --git a/Emby.Notifications/Notifications.cs b/Emby.Notifications/Notifications.cs index fbdc39f94f..045aa6f16d 100644 --- a/Emby.Notifications/Notifications.cs +++ b/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) diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 54b70d3b5b..739f687678 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/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 e) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c59a648e59..365eb58564 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/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 /// /// Runs the startup tasks. /// - public Task RunStartupTasks() + public async Task RunStartupTasks() { + Logger.LogInformation("Running startup tasks"); + Resolve().AddTasks(GetExports(false)); ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated; @@ -666,20 +667,20 @@ namespace Emby.Server.Implementations Logger.LogInformation("ServerId: {0}", SystemId); var entryPoints = GetExports(); - 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 entryPoints, bool isBeforeStartup) + private IEnumerable StartEntryPoints(IEnumerable 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 /// /// Registers resources that classes will depend on /// - protected void RegisterResources() + protected async Task RegisterResources() { RegisterSingleInstance(ConfigurationManager); RegisterSingleInstance(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(LocalizationManager); BlurayExaminer = new BdInfoExaminer(FileSystemManager); RegisterSingleInstance(BlurayExaminer); diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index c8b8229704..812e48a1f8 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/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) { diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index e94a649bfb..ec3649bcac 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/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) { diff --git a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs index 0fc4c38583..361656ff2f 100644 --- a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs +++ b/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) diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 8755ee3a7d..56c730c800 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/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() diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index a670a289c8..9b61809c75 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/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 _lastProgressMessageTimes = new Dictionary(); diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index e37ea96a12..0186da9e1e 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/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 e) diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 92ea3a8f4a..091dd6a45b 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/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) diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs index bb96120f41..8be6db87d9 100644 --- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs +++ b/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 /// /// Runs this instance. /// - 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; } /// diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 2c8246d13b..5b90dc1fb0 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/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 /// /// Runs this instance. /// - 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; } /// diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index 69784e4106..d91a2d5817 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/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) diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index ed5fddb52f..3a746ef603 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/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() diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index b83fb9b397..4f72651d49 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/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(); + } - return new string[] { language }; + var culture = _localizationManager.FindLanguageInfo(language); + if (culture != null) + { + return culture.ThreeLetterISOLanguageNames; } - return Array.Empty(); + return new string[] { language }; } private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index b33ae72b70..6dd9366b05 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/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 e) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index bce9c240d5..c5ab568ae3 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/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(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs index 982a54b68d..9c9ba09f5f 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs +++ b/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() diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 3c2f9b427a..262ca24ec5 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -4,12 +4,14 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; @@ -36,8 +38,7 @@ namespace Emby.Server.Implementations.Localization private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; - private readonly IAssemblyInfo _assemblyInfo; - private readonly ITextLocalizer _textLocalizer; + private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; /// /// Initializes a new instance of the class. @@ -49,67 +50,57 @@ namespace Emby.Server.Implementations.Localization IServerConfigurationManager configurationManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, - ILoggerFactory loggerFactory, - IAssemblyInfo assemblyInfo, - ITextLocalizer textLocalizer) + ILoggerFactory loggerFactory) { _configurationManager = configurationManager; _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; _logger = loggerFactory.CreateLogger(nameof(LocalizationManager)); - _assemblyInfo = assemblyInfo; - _textLocalizer = textLocalizer; - - ExtractAll(); } - private void ExtractAll() + public async Task LoadAll() { - var type = GetType(); - var resourcePath = type.Namespace + ".Ratings."; - - var localizationPath = LocalizationPath; + const string ratingsResource = "Emby.Server.Implementations.Ratings."; - Directory.CreateDirectory(localizationPath); + Directory.CreateDirectory(LocalizationPath); - var existingFiles = GetRatingsFiles(localizationPath) - .Select(Path.GetFileName) - .ToList(); + var existingFiles = GetRatingsFiles(LocalizationPath).Select(Path.GetFileName); // Extract from the assembly - foreach (var resource in _assemblyInfo - .GetManifestResourceNames(type) - .Where(i => i.StartsWith(resourcePath))) + foreach (var resource in _assembly.GetManifestResourceNames() + .Where(i => i.StartsWith(ratingsResource))) { - var filename = "ratings-" + resource.Substring(resourcePath.Length); + string filename = "ratings-" + resource.Substring(ratingsResource.Length); if (!existingFiles.Contains(filename)) { - using (var stream = _assemblyInfo.GetManifestResourceStream(type, resource)) + using (var stream = _assembly.GetManifestResourceStream(resource)) { - var target = Path.Combine(localizationPath, filename); + string target = Path.Combine(LocalizationPath, filename); _logger.LogInformation("Extracting ratings to {0}", target); using (var fs = _fileSystem.GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { - stream.CopyTo(fs); + await stream.CopyToAsync(fs); } } } } - foreach (var file in GetRatingsFiles(localizationPath)) + foreach (var file in GetRatingsFiles(LocalizationPath)) { - LoadRatings(file); + await LoadRatings(file); } LoadAdditionalRatings(); + + await LoadCultures(); } private void LoadAdditionalRatings() { - LoadRatings("au", new[] { - + LoadRatings("au", new[] + { new ParentalRating("AU-G", 1), new ParentalRating("AU-PG", 5), new ParentalRating("AU-M", 6), @@ -120,8 +111,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("AU-RC", 11) }); - LoadRatings("be", new[] { - + LoadRatings("be", new[] + { new ParentalRating("BE-AL", 1), new ParentalRating("BE-MG6", 2), new ParentalRating("BE-6", 3), @@ -130,8 +121,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("BE-16", 8) }); - LoadRatings("de", new[] { - + LoadRatings("de", new[] + { new ParentalRating("DE-0", 1), new ParentalRating("FSK-0", 1), new ParentalRating("DE-6", 5), @@ -144,8 +135,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("FSK-18", 9) }); - LoadRatings("ru", new[] { - + LoadRatings("ru", new[] + { new ParentalRating("RU-0+", 1), new ParentalRating("RU-6+", 3), new ParentalRating("RU-12+", 7), @@ -159,29 +150,20 @@ namespace Emby.Server.Implementations.Localization _allParentalRatings[country] = ratings.ToDictionary(i => i.Name); } - private List GetRatingsFiles(string directory) - { - return _fileSystem.GetFilePaths(directory, false) - .Where(i => string.Equals(Path.GetExtension(i), ".txt", StringComparison.OrdinalIgnoreCase)) - .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase)) - .ToList(); - } + private IEnumerable GetRatingsFiles(string directory) + => _fileSystem.GetFilePaths(directory, false) + .Where(i => string.Equals(Path.GetExtension(i), ".csv", StringComparison.OrdinalIgnoreCase)) + .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase)); /// /// Gets the localization path. /// /// The localization path. - public string LocalizationPath => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization"); - - public string RemoveDiacritics(string text) - { - return _textLocalizer.RemoveDiacritics(text); - } + public string LocalizationPath + => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization"); public string NormalizeFormKD(string text) - { - return _textLocalizer.NormalizeFormKD(text); - } + => text.Normalize(NormalizationForm.FormKD); private CultureDto[] _cultures; @@ -190,90 +172,88 @@ namespace Emby.Server.Implementations.Localization /// /// IEnumerable{CultureDto}. public CultureDto[] GetCultures() - { - var result = _cultures; - if (result != null) - { - return result; - } + => _cultures; - var type = GetType(); - var path = type.Namespace + ".iso6392.txt"; + private async Task LoadCultures() + { + List list = new List(); - var list = new List(); + const string path = "Emby.Server.Implementations.Localization.iso6392.txt"; - using (var stream = _assemblyInfo.GetManifestResourceStream(type, path)) + using (var stream = _assembly.GetManifestResourceStream(path)) + using (var reader = new StreamReader(stream)) { - using (var reader = new StreamReader(stream)) + while (!reader.EndOfStream) { - while (!reader.EndOfStream) + var line = await reader.ReadLineAsync(); + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + var parts = line.Split('|'); + + if (parts.Length == 5) { - var line = reader.ReadLine(); + string name = parts[3]; + if (string.IsNullOrWhiteSpace(name)) + { + continue; + } - if (!string.IsNullOrWhiteSpace(line)) + string twoCharName = parts[2]; + if (string.IsNullOrWhiteSpace(twoCharName)) + { + continue; + } + + string[] threeletterNames; + if (string.IsNullOrWhiteSpace(parts[1])) + { + threeletterNames = new [] { parts[0] }; + } + else { - var parts = line.Split('|'); - - if (parts.Length == 5) - { - var threeletterNames = new List { parts[0] }; - if (!string.IsNullOrWhiteSpace(parts[1])) - { - threeletterNames.Add(parts[1]); - } - - list.Add(new CultureDto - { - DisplayName = parts[3], - Name = parts[3], - ThreeLetterISOLanguageNames = threeletterNames.ToArray(), - TwoLetterISOLanguageName = parts[2] - }); - } + threeletterNames = new [] { parts[0], parts[1] }; } + + list.Add(new CultureDto + { + DisplayName = name, + Name = name, + ThreeLetterISOLanguageNames = threeletterNames, + TwoLetterISOLanguageName = twoCharName + }); } } } - result = list.Where(i => !string.IsNullOrWhiteSpace(i.Name) && - !string.IsNullOrWhiteSpace(i.DisplayName) && - i.ThreeLetterISOLanguageNames.Length > 0 && - !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray(); - - _cultures = result; - - return result; + _cultures = list.ToArray(); } public CultureDto FindLanguageInfo(string language) - { - return GetCultures() - .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || - string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || - i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase) || - string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); - } + => GetCultures() + .FirstOrDefault(i => + string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) + || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) + || i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase) + || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); /// /// Gets the countries. /// /// IEnumerable{CountryInfo}. - public CountryInfo[] GetCountries() - { - // ToDo: DeserializeFromStream seems broken in this case - string jsonCountries = "[{\"Name\":\"AF\",\"DisplayName\":\"Afghanistan\",\"TwoLetterISORegionName\":\"AF\",\"ThreeLetterISORegionName\":\"AFG\"},{\"Name\":\"AL\",\"DisplayName\":\"Albania\",\"TwoLetterISORegionName\":\"AL\",\"ThreeLetterISORegionName\":\"ALB\"},{\"Name\":\"DZ\",\"DisplayName\":\"Algeria\",\"TwoLetterISORegionName\":\"DZ\",\"ThreeLetterISORegionName\":\"DZA\"},{\"Name\":\"AR\",\"DisplayName\":\"Argentina\",\"TwoLetterISORegionName\":\"AR\",\"ThreeLetterISORegionName\":\"ARG\"},{\"Name\":\"AM\",\"DisplayName\":\"Armenia\",\"TwoLetterISORegionName\":\"AM\",\"ThreeLetterISORegionName\":\"ARM\"},{\"Name\":\"AU\",\"DisplayName\":\"Australia\",\"TwoLetterISORegionName\":\"AU\",\"ThreeLetterISORegionName\":\"AUS\"},{\"Name\":\"AT\",\"DisplayName\":\"Austria\",\"TwoLetterISORegionName\":\"AT\",\"ThreeLetterISORegionName\":\"AUT\"},{\"Name\":\"AZ\",\"DisplayName\":\"Azerbaijan\",\"TwoLetterISORegionName\":\"AZ\",\"ThreeLetterISORegionName\":\"AZE\"},{\"Name\":\"BH\",\"DisplayName\":\"Bahrain\",\"TwoLetterISORegionName\":\"BH\",\"ThreeLetterISORegionName\":\"BHR\"},{\"Name\":\"BD\",\"DisplayName\":\"Bangladesh\",\"TwoLetterISORegionName\":\"BD\",\"ThreeLetterISORegionName\":\"BGD\"},{\"Name\":\"BY\",\"DisplayName\":\"Belarus\",\"TwoLetterISORegionName\":\"BY\",\"ThreeLetterISORegionName\":\"BLR\"},{\"Name\":\"BE\",\"DisplayName\":\"Belgium\",\"TwoLetterISORegionName\":\"BE\",\"ThreeLetterISORegionName\":\"BEL\"},{\"Name\":\"BZ\",\"DisplayName\":\"Belize\",\"TwoLetterISORegionName\":\"BZ\",\"ThreeLetterISORegionName\":\"BLZ\"},{\"Name\":\"VE\",\"DisplayName\":\"Bolivarian Republic of Venezuela\",\"TwoLetterISORegionName\":\"VE\",\"ThreeLetterISORegionName\":\"VEN\"},{\"Name\":\"BO\",\"DisplayName\":\"Bolivia\",\"TwoLetterISORegionName\":\"BO\",\"ThreeLetterISORegionName\":\"BOL\"},{\"Name\":\"BA\",\"DisplayName\":\"Bosnia and Herzegovina\",\"TwoLetterISORegionName\":\"BA\",\"ThreeLetterISORegionName\":\"BIH\"},{\"Name\":\"BW\",\"DisplayName\":\"Botswana\",\"TwoLetterISORegionName\":\"BW\",\"ThreeLetterISORegionName\":\"BWA\"},{\"Name\":\"BR\",\"DisplayName\":\"Brazil\",\"TwoLetterISORegionName\":\"BR\",\"ThreeLetterISORegionName\":\"BRA\"},{\"Name\":\"BN\",\"DisplayName\":\"Brunei Darussalam\",\"TwoLetterISORegionName\":\"BN\",\"ThreeLetterISORegionName\":\"BRN\"},{\"Name\":\"BG\",\"DisplayName\":\"Bulgaria\",\"TwoLetterISORegionName\":\"BG\",\"ThreeLetterISORegionName\":\"BGR\"},{\"Name\":\"KH\",\"DisplayName\":\"Cambodia\",\"TwoLetterISORegionName\":\"KH\",\"ThreeLetterISORegionName\":\"KHM\"},{\"Name\":\"CM\",\"DisplayName\":\"Cameroon\",\"TwoLetterISORegionName\":\"CM\",\"ThreeLetterISORegionName\":\"CMR\"},{\"Name\":\"CA\",\"DisplayName\":\"Canada\",\"TwoLetterISORegionName\":\"CA\",\"ThreeLetterISORegionName\":\"CAN\"},{\"Name\":\"029\",\"DisplayName\":\"Caribbean\",\"TwoLetterISORegionName\":\"029\",\"ThreeLetterISORegionName\":\"029\"},{\"Name\":\"CL\",\"DisplayName\":\"Chile\",\"TwoLetterISORegionName\":\"CL\",\"ThreeLetterISORegionName\":\"CHL\"},{\"Name\":\"CO\",\"DisplayName\":\"Colombia\",\"TwoLetterISORegionName\":\"CO\",\"ThreeLetterISORegionName\":\"COL\"},{\"Name\":\"CD\",\"DisplayName\":\"Congo [DRC]\",\"TwoLetterISORegionName\":\"CD\",\"ThreeLetterISORegionName\":\"COD\"},{\"Name\":\"CR\",\"DisplayName\":\"Costa Rica\",\"TwoLetterISORegionName\":\"CR\",\"ThreeLetterISORegionName\":\"CRI\"},{\"Name\":\"HR\",\"DisplayName\":\"Croatia\",\"TwoLetterISORegionName\":\"HR\",\"ThreeLetterISORegionName\":\"HRV\"},{\"Name\":\"CZ\",\"DisplayName\":\"Czech Republic\",\"TwoLetterISORegionName\":\"CZ\",\"ThreeLetterISORegionName\":\"CZE\"},{\"Name\":\"DK\",\"DisplayName\":\"Denmark\",\"TwoLetterISORegionName\":\"DK\",\"ThreeLetterISORegionName\":\"DNK\"},{\"Name\":\"DO\",\"DisplayName\":\"Dominican Republic\",\"TwoLetterISORegionName\":\"DO\",\"ThreeLetterISORegionName\":\"DOM\"},{\"Name\":\"EC\",\"DisplayName\":\"Ecuador\",\"TwoLetterISORegionName\":\"EC\",\"ThreeLetterISORegionName\":\"ECU\"},{\"Name\":\"EG\",\"DisplayName\":\"Egypt\",\"TwoLetterISORegionName\":\"EG\",\"ThreeLetterISORegionName\":\"EGY\"},{\"Name\":\"SV\",\"DisplayName\":\"El Salvador\",\"TwoLetterISORegionName\":\"SV\",\"ThreeLetterISORegionName\":\"SLV\"},{\"Name\":\"ER\",\"DisplayName\":\"Eritrea\",\"TwoLetterISORegionName\":\"ER\",\"ThreeLetterISORegionName\":\"ERI\"},{\"Name\":\"EE\",\"DisplayName\":\"Estonia\",\"TwoLetterISORegionName\":\"EE\",\"ThreeLetterISORegionName\":\"EST\"},{\"Name\":\"ET\",\"DisplayName\":\"Ethiopia\",\"TwoLetterISORegionName\":\"ET\",\"ThreeLetterISORegionName\":\"ETH\"},{\"Name\":\"FO\",\"DisplayName\":\"Faroe Islands\",\"TwoLetterISORegionName\":\"FO\",\"ThreeLetterISORegionName\":\"FRO\"},{\"Name\":\"FI\",\"DisplayName\":\"Finland\",\"TwoLetterISORegionName\":\"FI\",\"ThreeLetterISORegionName\":\"FIN\"},{\"Name\":\"FR\",\"DisplayName\":\"France\",\"TwoLetterISORegionName\":\"FR\",\"ThreeLetterISORegionName\":\"FRA\"},{\"Name\":\"GE\",\"DisplayName\":\"Georgia\",\"TwoLetterISORegionName\":\"GE\",\"ThreeLetterISORegionName\":\"GEO\"},{\"Name\":\"DE\",\"DisplayName\":\"Germany\",\"TwoLetterISORegionName\":\"DE\",\"ThreeLetterISORegionName\":\"DEU\"},{\"Name\":\"GR\",\"DisplayName\":\"Greece\",\"TwoLetterISORegionName\":\"GR\",\"ThreeLetterISORegionName\":\"GRC\"},{\"Name\":\"GL\",\"DisplayName\":\"Greenland\",\"TwoLetterISORegionName\":\"GL\",\"ThreeLetterISORegionName\":\"GRL\"},{\"Name\":\"GT\",\"DisplayName\":\"Guatemala\",\"TwoLetterISORegionName\":\"GT\",\"ThreeLetterISORegionName\":\"GTM\"},{\"Name\":\"HT\",\"DisplayName\":\"Haiti\",\"TwoLetterISORegionName\":\"HT\",\"ThreeLetterISORegionName\":\"HTI\"},{\"Name\":\"HN\",\"DisplayName\":\"Honduras\",\"TwoLetterISORegionName\":\"HN\",\"ThreeLetterISORegionName\":\"HND\"},{\"Name\":\"HK\",\"DisplayName\":\"Hong Kong S.A.R.\",\"TwoLetterISORegionName\":\"HK\",\"ThreeLetterISORegionName\":\"HKG\"},{\"Name\":\"HU\",\"DisplayName\":\"Hungary\",\"TwoLetterISORegionName\":\"HU\",\"ThreeLetterISORegionName\":\"HUN\"},{\"Name\":\"IS\",\"DisplayName\":\"Iceland\",\"TwoLetterISORegionName\":\"IS\",\"ThreeLetterISORegionName\":\"ISL\"},{\"Name\":\"IN\",\"DisplayName\":\"India\",\"TwoLetterISORegionName\":\"IN\",\"ThreeLetterISORegionName\":\"IND\"},{\"Name\":\"ID\",\"DisplayName\":\"Indonesia\",\"TwoLetterISORegionName\":\"ID\",\"ThreeLetterISORegionName\":\"IDN\"},{\"Name\":\"IR\",\"DisplayName\":\"Iran\",\"TwoLetterISORegionName\":\"IR\",\"ThreeLetterISORegionName\":\"IRN\"},{\"Name\":\"IQ\",\"DisplayName\":\"Iraq\",\"TwoLetterISORegionName\":\"IQ\",\"ThreeLetterISORegionName\":\"IRQ\"},{\"Name\":\"IE\",\"DisplayName\":\"Ireland\",\"TwoLetterISORegionName\":\"IE\",\"ThreeLetterISORegionName\":\"IRL\"},{\"Name\":\"PK\",\"DisplayName\":\"Islamic Republic of Pakistan\",\"TwoLetterISORegionName\":\"PK\",\"ThreeLetterISORegionName\":\"PAK\"},{\"Name\":\"IL\",\"DisplayName\":\"Israel\",\"TwoLetterISORegionName\":\"IL\",\"ThreeLetterISORegionName\":\"ISR\"},{\"Name\":\"IT\",\"DisplayName\":\"Italy\",\"TwoLetterISORegionName\":\"IT\",\"ThreeLetterISORegionName\":\"ITA\"},{\"Name\":\"CI\",\"DisplayName\":\"Ivory Coast\",\"TwoLetterISORegionName\":\"CI\",\"ThreeLetterISORegionName\":\"CIV\"},{\"Name\":\"JM\",\"DisplayName\":\"Jamaica\",\"TwoLetterISORegionName\":\"JM\",\"ThreeLetterISORegionName\":\"JAM\"},{\"Name\":\"JP\",\"DisplayName\":\"Japan\",\"TwoLetterISORegionName\":\"JP\",\"ThreeLetterISORegionName\":\"JPN\"},{\"Name\":\"JO\",\"DisplayName\":\"Jordan\",\"TwoLetterISORegionName\":\"JO\",\"ThreeLetterISORegionName\":\"JOR\"},{\"Name\":\"KZ\",\"DisplayName\":\"Kazakhstan\",\"TwoLetterISORegionName\":\"KZ\",\"ThreeLetterISORegionName\":\"KAZ\"},{\"Name\":\"KE\",\"DisplayName\":\"Kenya\",\"TwoLetterISORegionName\":\"KE\",\"ThreeLetterISORegionName\":\"KEN\"},{\"Name\":\"KR\",\"DisplayName\":\"Korea\",\"TwoLetterISORegionName\":\"KR\",\"ThreeLetterISORegionName\":\"KOR\"},{\"Name\":\"KW\",\"DisplayName\":\"Kuwait\",\"TwoLetterISORegionName\":\"KW\",\"ThreeLetterISORegionName\":\"KWT\"},{\"Name\":\"KG\",\"DisplayName\":\"Kyrgyzstan\",\"TwoLetterISORegionName\":\"KG\",\"ThreeLetterISORegionName\":\"KGZ\"},{\"Name\":\"LA\",\"DisplayName\":\"Lao P.D.R.\",\"TwoLetterISORegionName\":\"LA\",\"ThreeLetterISORegionName\":\"LAO\"},{\"Name\":\"419\",\"DisplayName\":\"Latin America\",\"TwoLetterISORegionName\":\"419\",\"ThreeLetterISORegionName\":\"419\"},{\"Name\":\"LV\",\"DisplayName\":\"Latvia\",\"TwoLetterISORegionName\":\"LV\",\"ThreeLetterISORegionName\":\"LVA\"},{\"Name\":\"LB\",\"DisplayName\":\"Lebanon\",\"TwoLetterISORegionName\":\"LB\",\"ThreeLetterISORegionName\":\"LBN\"},{\"Name\":\"LY\",\"DisplayName\":\"Libya\",\"TwoLetterISORegionName\":\"LY\",\"ThreeLetterISORegionName\":\"LBY\"},{\"Name\":\"LI\",\"DisplayName\":\"Liechtenstein\",\"TwoLetterISORegionName\":\"LI\",\"ThreeLetterISORegionName\":\"LIE\"},{\"Name\":\"LT\",\"DisplayName\":\"Lithuania\",\"TwoLetterISORegionName\":\"LT\",\"ThreeLetterISORegionName\":\"LTU\"},{\"Name\":\"LU\",\"DisplayName\":\"Luxembourg\",\"TwoLetterISORegionName\":\"LU\",\"ThreeLetterISORegionName\":\"LUX\"},{\"Name\":\"MO\",\"DisplayName\":\"Macao S.A.R.\",\"TwoLetterISORegionName\":\"MO\",\"ThreeLetterISORegionName\":\"MAC\"},{\"Name\":\"MK\",\"DisplayName\":\"Macedonia (FYROM)\",\"TwoLetterISORegionName\":\"MK\",\"ThreeLetterISORegionName\":\"MKD\"},{\"Name\":\"MY\",\"DisplayName\":\"Malaysia\",\"TwoLetterISORegionName\":\"MY\",\"ThreeLetterISORegionName\":\"MYS\"},{\"Name\":\"MV\",\"DisplayName\":\"Maldives\",\"TwoLetterISORegionName\":\"MV\",\"ThreeLetterISORegionName\":\"MDV\"},{\"Name\":\"ML\",\"DisplayName\":\"Mali\",\"TwoLetterISORegionName\":\"ML\",\"ThreeLetterISORegionName\":\"MLI\"},{\"Name\":\"MT\",\"DisplayName\":\"Malta\",\"TwoLetterISORegionName\":\"MT\",\"ThreeLetterISORegionName\":\"MLT\"},{\"Name\":\"MX\",\"DisplayName\":\"Mexico\",\"TwoLetterISORegionName\":\"MX\",\"ThreeLetterISORegionName\":\"MEX\"},{\"Name\":\"MN\",\"DisplayName\":\"Mongolia\",\"TwoLetterISORegionName\":\"MN\",\"ThreeLetterISORegionName\":\"MNG\"},{\"Name\":\"ME\",\"DisplayName\":\"Montenegro\",\"TwoLetterISORegionName\":\"ME\",\"ThreeLetterISORegionName\":\"MNE\"},{\"Name\":\"MA\",\"DisplayName\":\"Morocco\",\"TwoLetterISORegionName\":\"MA\",\"ThreeLetterISORegionName\":\"MAR\"},{\"Name\":\"NP\",\"DisplayName\":\"Nepal\",\"TwoLetterISORegionName\":\"NP\",\"ThreeLetterISORegionName\":\"NPL\"},{\"Name\":\"NL\",\"DisplayName\":\"Netherlands\",\"TwoLetterISORegionName\":\"NL\",\"ThreeLetterISORegionName\":\"NLD\"},{\"Name\":\"NZ\",\"DisplayName\":\"New Zealand\",\"TwoLetterISORegionName\":\"NZ\",\"ThreeLetterISORegionName\":\"NZL\"},{\"Name\":\"NI\",\"DisplayName\":\"Nicaragua\",\"TwoLetterISORegionName\":\"NI\",\"ThreeLetterISORegionName\":\"NIC\"},{\"Name\":\"NG\",\"DisplayName\":\"Nigeria\",\"TwoLetterISORegionName\":\"NG\",\"ThreeLetterISORegionName\":\"NGA\"},{\"Name\":\"NO\",\"DisplayName\":\"Norway\",\"TwoLetterISORegionName\":\"NO\",\"ThreeLetterISORegionName\":\"NOR\"},{\"Name\":\"OM\",\"DisplayName\":\"Oman\",\"TwoLetterISORegionName\":\"OM\",\"ThreeLetterISORegionName\":\"OMN\"},{\"Name\":\"PA\",\"DisplayName\":\"Panama\",\"TwoLetterISORegionName\":\"PA\",\"ThreeLetterISORegionName\":\"PAN\"},{\"Name\":\"PY\",\"DisplayName\":\"Paraguay\",\"TwoLetterISORegionName\":\"PY\",\"ThreeLetterISORegionName\":\"PRY\"},{\"Name\":\"CN\",\"DisplayName\":\"People's Republic of China\",\"TwoLetterISORegionName\":\"CN\",\"ThreeLetterISORegionName\":\"CHN\"},{\"Name\":\"PE\",\"DisplayName\":\"Peru\",\"TwoLetterISORegionName\":\"PE\",\"ThreeLetterISORegionName\":\"PER\"},{\"Name\":\"PH\",\"DisplayName\":\"Philippines\",\"TwoLetterISORegionName\":\"PH\",\"ThreeLetterISORegionName\":\"PHL\"},{\"Name\":\"PL\",\"DisplayName\":\"Poland\",\"TwoLetterISORegionName\":\"PL\",\"ThreeLetterISORegionName\":\"POL\"},{\"Name\":\"PT\",\"DisplayName\":\"Portugal\",\"TwoLetterISORegionName\":\"PT\",\"ThreeLetterISORegionName\":\"PRT\"},{\"Name\":\"MC\",\"DisplayName\":\"Principality of Monaco\",\"TwoLetterISORegionName\":\"MC\",\"ThreeLetterISORegionName\":\"MCO\"},{\"Name\":\"PR\",\"DisplayName\":\"Puerto Rico\",\"TwoLetterISORegionName\":\"PR\",\"ThreeLetterISORegionName\":\"PRI\"},{\"Name\":\"QA\",\"DisplayName\":\"Qatar\",\"TwoLetterISORegionName\":\"QA\",\"ThreeLetterISORegionName\":\"QAT\"},{\"Name\":\"MD\",\"DisplayName\":\"Republica Moldova\",\"TwoLetterISORegionName\":\"MD\",\"ThreeLetterISORegionName\":\"MDA\"},{\"Name\":\"RE\",\"DisplayName\":\"Réunion\",\"TwoLetterISORegionName\":\"RE\",\"ThreeLetterISORegionName\":\"REU\"},{\"Name\":\"RO\",\"DisplayName\":\"Romania\",\"TwoLetterISORegionName\":\"RO\",\"ThreeLetterISORegionName\":\"ROU\"},{\"Name\":\"RU\",\"DisplayName\":\"Russia\",\"TwoLetterISORegionName\":\"RU\",\"ThreeLetterISORegionName\":\"RUS\"},{\"Name\":\"RW\",\"DisplayName\":\"Rwanda\",\"TwoLetterISORegionName\":\"RW\",\"ThreeLetterISORegionName\":\"RWA\"},{\"Name\":\"SA\",\"DisplayName\":\"Saudi Arabia\",\"TwoLetterISORegionName\":\"SA\",\"ThreeLetterISORegionName\":\"SAU\"},{\"Name\":\"SN\",\"DisplayName\":\"Senegal\",\"TwoLetterISORegionName\":\"SN\",\"ThreeLetterISORegionName\":\"SEN\"},{\"Name\":\"RS\",\"DisplayName\":\"Serbia\",\"TwoLetterISORegionName\":\"RS\",\"ThreeLetterISORegionName\":\"SRB\"},{\"Name\":\"CS\",\"DisplayName\":\"Serbia and Montenegro (Former)\",\"TwoLetterISORegionName\":\"CS\",\"ThreeLetterISORegionName\":\"SCG\"},{\"Name\":\"SG\",\"DisplayName\":\"Singapore\",\"TwoLetterISORegionName\":\"SG\",\"ThreeLetterISORegionName\":\"SGP\"},{\"Name\":\"SK\",\"DisplayName\":\"Slovakia\",\"TwoLetterISORegionName\":\"SK\",\"ThreeLetterISORegionName\":\"SVK\"},{\"Name\":\"SI\",\"DisplayName\":\"Slovenia\",\"TwoLetterISORegionName\":\"SI\",\"ThreeLetterISORegionName\":\"SVN\"},{\"Name\":\"SO\",\"DisplayName\":\"Soomaaliya\",\"TwoLetterISORegionName\":\"SO\",\"ThreeLetterISORegionName\":\"SOM\"},{\"Name\":\"ZA\",\"DisplayName\":\"South Africa\",\"TwoLetterISORegionName\":\"ZA\",\"ThreeLetterISORegionName\":\"ZAF\"},{\"Name\":\"ES\",\"DisplayName\":\"Spain\",\"TwoLetterISORegionName\":\"ES\",\"ThreeLetterISORegionName\":\"ESP\"},{\"Name\":\"LK\",\"DisplayName\":\"Sri Lanka\",\"TwoLetterISORegionName\":\"LK\",\"ThreeLetterISORegionName\":\"LKA\"},{\"Name\":\"SE\",\"DisplayName\":\"Sweden\",\"TwoLetterISORegionName\":\"SE\",\"ThreeLetterISORegionName\":\"SWE\"},{\"Name\":\"CH\",\"DisplayName\":\"Switzerland\",\"TwoLetterISORegionName\":\"CH\",\"ThreeLetterISORegionName\":\"CHE\"},{\"Name\":\"SY\",\"DisplayName\":\"Syria\",\"TwoLetterISORegionName\":\"SY\",\"ThreeLetterISORegionName\":\"SYR\"},{\"Name\":\"TW\",\"DisplayName\":\"Taiwan\",\"TwoLetterISORegionName\":\"TW\",\"ThreeLetterISORegionName\":\"TWN\"},{\"Name\":\"TJ\",\"DisplayName\":\"Tajikistan\",\"TwoLetterISORegionName\":\"TJ\",\"ThreeLetterISORegionName\":\"TAJ\"},{\"Name\":\"TH\",\"DisplayName\":\"Thailand\",\"TwoLetterISORegionName\":\"TH\",\"ThreeLetterISORegionName\":\"THA\"},{\"Name\":\"TT\",\"DisplayName\":\"Trinidad and Tobago\",\"TwoLetterISORegionName\":\"TT\",\"ThreeLetterISORegionName\":\"TTO\"},{\"Name\":\"TN\",\"DisplayName\":\"Tunisia\",\"TwoLetterISORegionName\":\"TN\",\"ThreeLetterISORegionName\":\"TUN\"},{\"Name\":\"TR\",\"DisplayName\":\"Turkey\",\"TwoLetterISORegionName\":\"TR\",\"ThreeLetterISORegionName\":\"TUR\"},{\"Name\":\"TM\",\"DisplayName\":\"Turkmenistan\",\"TwoLetterISORegionName\":\"TM\",\"ThreeLetterISORegionName\":\"TKM\"},{\"Name\":\"AE\",\"DisplayName\":\"U.A.E.\",\"TwoLetterISORegionName\":\"AE\",\"ThreeLetterISORegionName\":\"ARE\"},{\"Name\":\"UA\",\"DisplayName\":\"Ukraine\",\"TwoLetterISORegionName\":\"UA\",\"ThreeLetterISORegionName\":\"UKR\"},{\"Name\":\"GB\",\"DisplayName\":\"United Kingdom\",\"TwoLetterISORegionName\":\"GB\",\"ThreeLetterISORegionName\":\"GBR\"},{\"Name\":\"US\",\"DisplayName\":\"United States\",\"TwoLetterISORegionName\":\"US\",\"ThreeLetterISORegionName\":\"USA\"},{\"Name\":\"UY\",\"DisplayName\":\"Uruguay\",\"TwoLetterISORegionName\":\"UY\",\"ThreeLetterISORegionName\":\"URY\"},{\"Name\":\"UZ\",\"DisplayName\":\"Uzbekistan\",\"TwoLetterISORegionName\":\"UZ\",\"ThreeLetterISORegionName\":\"UZB\"},{\"Name\":\"VN\",\"DisplayName\":\"Vietnam\",\"TwoLetterISORegionName\":\"VN\",\"ThreeLetterISORegionName\":\"VNM\"},{\"Name\":\"YE\",\"DisplayName\":\"Yemen\",\"TwoLetterISORegionName\":\"YE\",\"ThreeLetterISORegionName\":\"YEM\"},{\"Name\":\"ZW\",\"DisplayName\":\"Zimbabwe\",\"TwoLetterISORegionName\":\"ZW\",\"ThreeLetterISORegionName\":\"ZWE\"}]"; - - return _jsonSerializer.DeserializeFromString(jsonCountries); - } + public Task GetCountries() + => _jsonSerializer.DeserializeFromStreamAsync( + _assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); /// /// Gets the parental ratings. /// /// IEnumerable{ParentalRating}. - public ParentalRating[] GetParentalRatings() - { - return GetParentalRatingsDictionary().Values.ToArray(); - } + public IEnumerable GetParentalRatings() + => GetParentalRatingsDictionary().Values; /// /// Gets the parental ratings dictionary. @@ -288,14 +268,7 @@ namespace Emby.Server.Implementations.Localization countryCode = "us"; } - var ratings = GetRatings(countryCode); - - if (ratings == null) - { - ratings = GetRatings("us"); - } - - return ratings; + return GetRatings(countryCode) ?? GetRatings("us"); } /// @@ -314,37 +287,39 @@ namespace Emby.Server.Implementations.Localization /// /// The file. /// Dictionary{System.StringParentalRating}. - private void LoadRatings(string file) + private async Task LoadRatings(string file) { - var dict = File.ReadAllLines(file).Select(i => + Dictionary dict = new Dictionary(StringComparer.OrdinalIgnoreCase); + + using (var str = File.OpenRead(file)) + using (var reader = new StreamReader(str)) { - if (!string.IsNullOrWhiteSpace(i)) + string line; + while ((line = await reader.ReadLineAsync()) != null) { - var parts = i.Split(','); + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } - if (parts.Length == 2) + string[] parts = line.Split(','); + if (parts.Length == 2 + && int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value)) { - if (int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value)) - { - return new ParentalRating { Name = parts[0], Value = value }; - } + dict.Add(parts[0], (new ParentalRating { Name = parts[0], Value = value })); } +#if DEBUG + _logger.LogWarning("Misformed line in {Path}", file); +#endif } + } - return null; - - }) - .Where(i => i != null) - .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); - - var countryCode = Path.GetFileNameWithoutExtension(file) - .Split('-') - .Last(); + var countryCode = Path.GetFileNameWithoutExtension(file).Split('-')[1]; _allParentalRatings[countryCode] = dict; } - private readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; + private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; /// /// Gets the rating level. @@ -435,7 +410,7 @@ namespace Emby.Server.Implementations.Localization return phrase; } - const string DefaultCulture = "en-US"; + private const string DefaultCulture = "en-US"; private readonly ConcurrentDictionary> _dictionaries = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); @@ -450,10 +425,11 @@ namespace Emby.Server.Implementations.Localization const string prefix = "Core"; var key = prefix + culture; - return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, DefaultCulture + ".json")); + return _dictionaries.GetOrAdd(key, + f => GetDictionary(prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); } - private Dictionary GetDictionary(string prefix, string culture, string baseFilename) + private async Task> GetDictionary(string prefix, string culture, string baseFilename) { if (string.IsNullOrEmpty(culture)) { @@ -464,24 +440,21 @@ namespace Emby.Server.Implementations.Localization var namespaceName = GetType().Namespace + "." + prefix; - CopyInto(dictionary, namespaceName + "." + baseFilename); - CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)); + await CopyInto(dictionary, namespaceName + "." + baseFilename); + await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)); return dictionary; } - private void CopyInto(IDictionary dictionary, string resourcePath) + private async Task CopyInto(IDictionary dictionary, string resourcePath) { - using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), resourcePath)) + using (var stream = _assembly.GetManifestResourceStream(resourcePath)) { - if (stream != null) - { - var dict = _jsonSerializer.DeserializeFromStream>(stream); + var dict = await _jsonSerializer.DeserializeFromStreamAsync>(stream); - foreach (var key in dict.Keys) - { - dictionary[key] = dict[key]; - } + foreach (var key in dict.Keys) + { + dictionary[key] = dict[key]; } } } @@ -552,11 +525,4 @@ namespace Emby.Server.Implementations.Localization new LocalizationOption("Vietnamese", "vi") }; } - - public interface ITextLocalizer - { - string RemoveDiacritics(string text); - - string NormalizeFormKD(string text); - } } diff --git a/Emby.Server.Implementations/Localization/Ratings/br.txt b/Emby.Server.Implementations/Localization/Ratings/br.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/br.txt rename to Emby.Server.Implementations/Localization/Ratings/br.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.txt b/Emby.Server.Implementations/Localization/Ratings/ca.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/ca.txt rename to Emby.Server.Implementations/Localization/Ratings/ca.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/co.txt b/Emby.Server.Implementations/Localization/Ratings/co.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/co.txt rename to Emby.Server.Implementations/Localization/Ratings/co.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.txt b/Emby.Server.Implementations/Localization/Ratings/dk.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/dk.txt rename to Emby.Server.Implementations/Localization/Ratings/dk.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/es.txt b/Emby.Server.Implementations/Localization/Ratings/es.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/es.txt rename to Emby.Server.Implementations/Localization/Ratings/es.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.txt b/Emby.Server.Implementations/Localization/Ratings/fr.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/fr.txt rename to Emby.Server.Implementations/Localization/Ratings/fr.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.txt b/Emby.Server.Implementations/Localization/Ratings/gb.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/gb.txt rename to Emby.Server.Implementations/Localization/Ratings/gb.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.txt b/Emby.Server.Implementations/Localization/Ratings/ie.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/ie.txt rename to Emby.Server.Implementations/Localization/Ratings/ie.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.txt b/Emby.Server.Implementations/Localization/Ratings/jp.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/jp.txt rename to Emby.Server.Implementations/Localization/Ratings/jp.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.txt b/Emby.Server.Implementations/Localization/Ratings/kz.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/kz.txt rename to Emby.Server.Implementations/Localization/Ratings/kz.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.txt b/Emby.Server.Implementations/Localization/Ratings/mx.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/mx.txt rename to Emby.Server.Implementations/Localization/Ratings/mx.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.txt b/Emby.Server.Implementations/Localization/Ratings/nl.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/nl.txt rename to Emby.Server.Implementations/Localization/Ratings/nl.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.txt b/Emby.Server.Implementations/Localization/Ratings/nz.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/nz.txt rename to Emby.Server.Implementations/Localization/Ratings/nz.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.txt b/Emby.Server.Implementations/Localization/Ratings/ro.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/ro.txt rename to Emby.Server.Implementations/Localization/Ratings/ro.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.txt b/Emby.Server.Implementations/Localization/Ratings/uk.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/uk.txt rename to Emby.Server.Implementations/Localization/Ratings/uk.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/us.txt b/Emby.Server.Implementations/Localization/Ratings/us.csv similarity index 100% rename from Emby.Server.Implementations/Localization/Ratings/us.txt rename to Emby.Server.Implementations/Localization/Ratings/us.csv diff --git a/Emby.Server.Implementations/Localization/TextLocalizer.cs b/Emby.Server.Implementations/Localization/TextLocalizer.cs deleted file mode 100644 index 96591e5e67..0000000000 --- a/Emby.Server.Implementations/Localization/TextLocalizer.cs +++ /dev/null @@ -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]))|((? "RefreshChapterImages"; - /// /// Returns the task to be executed /// @@ -161,22 +159,18 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// - /// Gets the name of the task - /// - /// The name. public string Name => "Chapter image extraction"; - /// - /// Gets the description. - /// - /// The description. public string Description => "Creates thumbnails for videos that have chapters."; - /// - /// Gets the category. - /// - /// The category. public string Category => "Library"; + + public string Key => "RefreshChapterImages"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 52077b242e..6ec83b5c0c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -158,31 +158,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } } - /// - /// Gets the name of the task - /// - /// The name. public string Name => "Cache file cleanup"; - public string Key => "DeleteCacheFiles"; - - /// - /// Gets the description. - /// - /// The description. public string Description => "Deletes cache files no longer needed by the system"; - /// - /// Gets the category. - /// - /// The category. public string Category => "Maintenance"; - /// - /// Gets a value indicating whether this instance is hidden. - /// - /// true if this instance is hidden; otherwise, false. - public bool IsHidden => true; + public string Key => "DeleteCacheFiles"; + + public bool IsHidden => false; public bool IsEnabled => true; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index a57fe49457..e468c301a9 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -81,31 +81,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks return Task.CompletedTask; } - public string Key => "CleanLogFiles"; - - /// - /// Gets the name of the task - /// - /// The name. public string Name => "Log file cleanup"; - /// - /// Gets the description. - /// - /// The description. public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays); - /// - /// Gets the category. - /// - /// The category. public string Category => "Maintenance"; - /// - /// Gets a value indicating whether this instance is hidden. - /// - /// true if this instance is hidden; otherwise, false. - public bool IsHidden => true; + public string Key => "CleanLogFiles"; + + public bool IsHidden => false; public bool IsEnabled => true; diff --git a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs similarity index 86% rename from Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs rename to Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs index 68031170fd..d70799c479 100644 --- a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs @@ -47,8 +47,6 @@ namespace Emby.Server.Implementations.ScheduledTasks }; } - public string Key => "RefreshPeople"; - /// /// Returns the task to be executed /// @@ -60,22 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks return _libraryManager.ValidatePeople(cancellationToken, progress); } - /// - /// Gets the name of the task - /// - /// The name. public string Name => "Refresh people"; - /// - /// Gets the description. - /// - /// The description. public string Description => "Updates metadata for actors and directors in your media library."; - /// - /// Gets the category. - /// - /// The category. public string Category => "Library"; + + public string Key => "RefreshPeople"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs new file mode 100644 index 0000000000..c6431c311c --- /dev/null +++ b/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 +{ + /// + /// Plugin Update Task + /// + public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask + { + /// + /// The _logger + /// + 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; + } + + /// + /// Creates the triggers that define when the task will run + /// + /// IEnumerable{BaseTaskTrigger}. + public IEnumerable GetDefaultTriggers() + { + return new[] { + + // At startup + new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup}, + + // Every so often + new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} + }; + } + + /// + /// Update installed plugins + /// + /// The cancellation token. + /// The progress. + /// Task. + public async Task Execute(CancellationToken cancellationToken, IProgress 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(), 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; + } +} diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs similarity index 87% rename from Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs rename to Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs index f6fa64d136..1a3d85ad7f 100644 --- a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs @@ -58,24 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken); } - /// - /// Gets the name. - /// - /// The name. public string Name => "Scan media library"; - /// - /// Gets the description. - /// - /// The description. public string Description => "Scans your media library and refreshes metatata based on configuration."; - /// - /// Gets the category. - /// - /// The category. public string Category => "Library"; public string Key => "RefreshLibrary"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs similarity index 100% rename from Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs rename to Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs similarity index 100% rename from Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs rename to Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs similarity index 100% rename from Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs rename to Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs similarity index 100% rename from Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs rename to Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 9a49b97c71..dc7f57f27d 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -164,15 +164,13 @@ namespace Emby.Server.Implementations.Updates /// Gets all available packages. /// /// Task{List{PackageInfo}}. - public Task> GetAvailablePackages(CancellationToken cancellationToken, + public async Task> 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()); //FilterPackages(packages, packageType, applicationVersion); + var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); + return FilterPackages(packages, packageType, applicationVersion); } /// @@ -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(), - CacheLength = GetCacheLength(), - CacheMode = CacheMode.Unconditional - + CacheLength = GetCacheLength() }, "GET").ConfigureAwait(false)) { using (var stream = response.Content) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index bb0eff2919..7826fde35b 100644 --- a/Jellyfin.Server/Program.cs +++ b/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) diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index a212d3f3a7..88654a42cf 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -130,7 +130,7 @@ namespace MediaBrowser.Api /// /// Runs this instance. /// - 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); } diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 3c8d4b4ff1..825732888e 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/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 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() }; diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 385127c54b..59e3c17674 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.Common /// /// if set to true [manage liftime]. /// IEnumerable{``0}. - IEnumerable GetExports(bool manageLiftime = true); + IEnumerable GetExports(bool manageLifetime = true); /// /// Updates the application. @@ -131,7 +131,7 @@ namespace MediaBrowser.Common /// /// Inits this instance. /// - void Init(); + Task Init(); /// /// Creates the instance. diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs index 73f529fc01..b1aaf6534e 100644 --- a/MediaBrowser.Controller/Extensions/StringExtensions.cs +++ b/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 /// 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]))|((? /// Runs this instance. /// - void Run(); + Task RunAsync(); } public interface IRunBeforeStartup diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index 05efb6681b..a9ce60a2ab 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/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. /// /// IEnumerable{CountryInfo}. - CountryInfo[] GetCountries(); + Task GetCountries(); /// /// Gets the parental ratings. /// /// IEnumerable{ParentalRating}. - ParentalRating[] GetParentalRatings(); + IEnumerable GetParentalRatings(); /// /// Gets the rating level. /// @@ -51,8 +53,6 @@ namespace MediaBrowser.Model.Globalization /// IEnumerable{LocalizatonOption}. LocalizationOption[] GetLocalizationOptions(); - string RemoveDiacritics(string text); - string NormalizeFormKD(string text); bool HasUnicodeCategory(string value, UnicodeCategory category); diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 1972ad290c..77028e526a 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/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); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index afc760dd4c..4e11fcbb2a 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/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; diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index b7598ef22f..74f41f9df0 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/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("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; } } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 2f4e21443b..531978e1dd 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/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); } } diff --git a/MediaBrowser.WebDashboard/ServerEntryPoint.cs b/MediaBrowser.WebDashboard/ServerEntryPoint.cs index 221fa62c79..18ed54a786 100644 --- a/MediaBrowser.WebDashboard/ServerEntryPoint.cs +++ b/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().ToList(); + + return Task.CompletedTask; } public void Dispose() diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs index 37a1d4c350..992991a7ed 100644 --- a/MediaBrowser.XbmcMetadata/EntryPoint.cs +++ b/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) diff --git a/bump_version b/bump_version index c3f1a78d50..a63fbf7353 100755 --- a/bump_version +++ b/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 diff --git a/deployment/centos-package-x64/Dockerfile b/deployment/centos-package-x64/Dockerfile new file mode 100644 index 0000000000..bbe5ffd277 --- /dev/null +++ b/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; \ No newline at end of file diff --git a/deployment/centos-package-x64/clean.sh b/deployment/centos-package-x64/clean.sh new file mode 120000 index 0000000000..d6d2d1c091 --- /dev/null +++ b/deployment/centos-package-x64/clean.sh @@ -0,0 +1 @@ +../fedora-package-x64/clean.sh \ No newline at end of file diff --git a/deployment/centos-package-x64/package.sh b/deployment/centos-package-x64/package.sh new file mode 120000 index 0000000000..a79de21eba --- /dev/null +++ b/deployment/centos-package-x64/package.sh @@ -0,0 +1 @@ +../fedora-package-x64/package.sh \ No newline at end of file diff --git a/deployment/centos-package-x64/pkg-src b/deployment/centos-package-x64/pkg-src new file mode 120000 index 0000000000..dfd6497cfd --- /dev/null +++ b/deployment/centos-package-x64/pkg-src @@ -0,0 +1 @@ +../fedora-package-x64/pkg-src \ No newline at end of file diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env index 11d5b0ab04..abfa670e4a 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.env +++ b/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" diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec index 6a4a5870b8..851c400445 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec +++ b/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