From 7e8428e588b3f0a0574da44081098c64fe1a47d7 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 20 May 2021 21:28:18 +0200 Subject: Enable nullable reference types for Emby.Server.Implementations --- Emby.Server.Implementations/AppBase/ConfigurationHelper.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'Emby.Server.Implementations/AppBase/ConfigurationHelper.cs') diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 29bac6634..de770f59e 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using System.IO; using System.Linq; -- cgit v1.2.3 From 0bc06014427e36a770adeda66392d08147658ea8 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 28 May 2021 14:33:54 +0200 Subject: Fix some warnings --- .../AppBase/BaseConfigurationManager.cs | 10 +-- .../AppBase/ConfigurationHelper.cs | 3 +- .../EntryPoints/UdpServerEntryPoint.cs | 4 +- .../EntryPoints/UserDataChangeNotifier.cs | 10 ++- .../LiveTv/EmbyTV/RecordingHelper.cs | 2 - .../LiveTv/LiveTvConfigurationFactory.cs | 10 +-- .../LiveTv/LiveTvManager.cs | 8 +-- .../LiveTv/RefreshChannelsScheduledTask.cs | 63 ------------------ .../LiveTv/RefreshGuideScheduledTask.cs | 75 ++++++++++++++++++++++ .../LiveTv/TunerHosts/BaseTunerHost.cs | 1 + .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 - .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 6 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 20 +++--- .../LiveTv/TunerHosts/M3uParser.cs | 8 +-- .../LiveTv/TunerHosts/SharedHttpStream.cs | 4 +- .../Plugins/PluginManager.cs | 3 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 21 ++---- .../ScheduledTasks/Triggers/DailyTrigger.cs | 41 ++++++------ .../ScheduledTasks/Triggers/IntervalTrigger.cs | 40 ++++++------ .../ScheduledTasks/Triggers/StartupTrigger.cs | 28 ++++---- .../ScheduledTasks/Triggers/WeeklyTrigger.cs | 54 +++++++--------- .../Session/WebSocketController.cs | 1 - Emby.Server.Implementations/Udp/UdpServer.cs | 67 ++++++++++--------- .../Events/EventManager.cs | 7 +- MediaBrowser.Common/IApplicationHost.cs | 8 +-- .../Subtitles/ParserValues.cs | 9 --- MediaBrowser.Model/Tasks/ITaskTrigger.cs | 4 +- jellyfin.ruleset | 3 + 28 files changed, 247 insertions(+), 265 deletions(-) delete mode 100644 Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs create mode 100644 Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs (limited to 'Emby.Server.Implementations/AppBase/ConfigurationHelper.cs') diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 8c919db43..4c442a473 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -25,6 +25,11 @@ namespace Emby.Server.Implementations.AppBase private readonly ConcurrentDictionary _configurations = new ConcurrentDictionary(); + /// + /// The _configuration sync lock. + /// + private readonly object _configurationSyncLock = new object(); + private ConfigurationStore[] _configurationStores = Array.Empty(); private IConfigurationFactory[] _configurationFactories = Array.Empty(); @@ -33,11 +38,6 @@ namespace Emby.Server.Implementations.AppBase /// private bool _configurationLoaded; - /// - /// The _configuration sync lock. - /// - private readonly object _configurationSyncLock = new object(); - /// /// The _configuration. /// diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index de770f59e..0308a68e4 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -33,7 +33,8 @@ namespace Emby.Server.Implementations.AppBase } catch (Exception) { - configuration = Activator.CreateInstance(type) ?? throw new ArgumentException($"Provided path ({type}) is not valid.", nameof(type)); + // Note: CreateInstance returns null for Nullable, e.g. CreateInstance(typeof(int?)) returns null. + configuration = Activator.CreateInstance(type)!; } using var stream = new MemoryStream(buffer?.Length ?? 0); diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 211941f44..2e72b18f5 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -54,8 +54,8 @@ namespace Emby.Server.Implementations.EntryPoints try { - _udpServer = new UdpServer(_logger, _appHost, _config); - _udpServer.Start(PortNumber, _cancellationTokenSource.Token); + _udpServer = new UdpServer(_logger, _appHost, _config, PortNumber); + _udpServer.Start(_cancellationTokenSource.Token); } catch (SocketException ex) { diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index 332fb3385..d3bcd5e13 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -28,7 +26,7 @@ namespace Emby.Server.Implementations.EntryPoints private readonly Dictionary> _changedItems = new Dictionary>(); private readonly object _syncLock = new object(); - private Timer _updateTimer; + private Timer? _updateTimer; public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IUserManager userManager) { @@ -44,7 +42,7 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - void OnUserDataManagerUserDataSaved(object sender, UserDataSaveEventArgs e) + private void OnUserDataManagerUserDataSaved(object? sender, UserDataSaveEventArgs e) { if (e.SaveReason == UserDataSaveReason.PlaybackProgress) { @@ -66,7 +64,7 @@ namespace Emby.Server.Implementations.EntryPoints _updateTimer.Change(UpdateDuration, Timeout.Infinite); } - if (!_changedItems.TryGetValue(e.UserId, out List keys)) + if (!_changedItems.TryGetValue(e.UserId, out List? keys)) { keys = new List(); _changedItems[e.UserId] = keys; @@ -89,7 +87,7 @@ namespace Emby.Server.Implementations.EntryPoints } } - private void UpdateTimerCallback(object state) + private void UpdateTimerCallback(object? state) { lock (_syncLock) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index 108863869..32245f899 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs b/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs index ba916af38..098f193fb 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs @@ -1,21 +1,23 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.LiveTv; namespace Emby.Server.Implementations.LiveTv { + /// + /// implementation for . + /// public class LiveTvConfigurationFactory : IConfigurationFactory { + /// public IEnumerable GetConfigurations() { return new ConfigurationStore[] { new ConfigurationStore { - ConfigurationType = typeof(LiveTvOptions), - Key = "livetv" + ConfigurationType = typeof(LiveTvOptions), + Key = "livetv" } }; } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 1f1628900..d964769b5 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2266,7 +2266,7 @@ namespace Emby.Server.Implementations.LiveTv if (dataSourceChanged) { - _taskManager.CancelIfRunningAndQueue(); + _taskManager.CancelIfRunningAndQueue(); } return info; @@ -2309,7 +2309,7 @@ namespace Emby.Server.Implementations.LiveTv _config.SaveConfiguration("livetv", config); - _taskManager.CancelIfRunningAndQueue(); + _taskManager.CancelIfRunningAndQueue(); return info; } @@ -2321,7 +2321,7 @@ namespace Emby.Server.Implementations.LiveTv config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray(); _config.SaveConfiguration("livetv", config); - _taskManager.CancelIfRunningAndQueue(); + _taskManager.CancelIfRunningAndQueue(); } public async Task SetChannelMapping(string providerId, string tunerChannelId, string providerChannelId) @@ -2355,7 +2355,7 @@ namespace Emby.Server.Implementations.LiveTv var tunerChannelMappings = tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(); - _taskManager.CancelIfRunningAndQueue(); + _taskManager.CancelIfRunningAndQueue(); return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase)); } diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs deleted file mode 100644 index 582b64923..000000000 --- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ /dev/null @@ -1,63 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.LiveTv; -using MediaBrowser.Model.Tasks; - -namespace Emby.Server.Implementations.LiveTv -{ - public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask - { - private readonly ILiveTvManager _liveTvManager; - private readonly IConfigurationManager _config; - - public RefreshChannelsScheduledTask(ILiveTvManager liveTvManager, IConfigurationManager config) - { - _liveTvManager = liveTvManager; - _config = config; - } - - public string Name => "Refresh Guide"; - - public string Description => "Downloads channel information from live tv services."; - - public string Category => "Live TV"; - - public Task Execute(System.Threading.CancellationToken cancellationToken, IProgress progress) - { - var manager = (LiveTvManager)_liveTvManager; - - return manager.RefreshChannels(progress, cancellationToken); - } - - /// - /// Creates the triggers that define when the task will run. - /// - /// IEnumerable{BaseTaskTrigger}. - public IEnumerable GetDefaultTriggers() - { - return new[] - { - // Every so often - new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks } - }; - } - - private LiveTvOptions GetConfiguration() - { - return _config.GetConfiguration("livetv"); - } - - public bool IsHidden => _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Length == 0; - - public bool IsEnabled => true; - - public bool IsLogged => true; - - public string Key => "RefreshGuide"; - } -} diff --git a/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs new file mode 100644 index 000000000..15df0dcf1 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Tasks; + +namespace Emby.Server.Implementations.LiveTv +{ + /// + /// The "Refresh Guide" scheduled task. + /// + public class RefreshGuideScheduledTask : IScheduledTask, IConfigurableScheduledTask + { + private readonly ILiveTvManager _liveTvManager; + private readonly IConfigurationManager _config; + + /// + /// Initializes a new instance of the class. + /// + /// The live tv manager. + /// The configuration manager. + public RefreshGuideScheduledTask(ILiveTvManager liveTvManager, IConfigurationManager config) + { + _liveTvManager = liveTvManager; + _config = config; + } + + /// + public string Name => "Refresh Guide"; + + /// + public string Description => "Downloads channel information from live tv services."; + + /// + public string Category => "Live TV"; + + /// + public bool IsHidden => _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Length == 0; + + /// + public bool IsEnabled => true; + + /// + public bool IsLogged => true; + + /// + public string Key => "RefreshGuide"; + + /// + public Task Execute(CancellationToken cancellationToken, IProgress progress) + { + var manager = (LiveTvManager)_liveTvManager; + + return manager.RefreshChannels(progress, cancellationToken); + } + + /// + public IEnumerable GetDefaultTriggers() + { + return new[] + { + // Every so often + new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks } + }; + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 00a37bb02..5941613cf 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -40,6 +40,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public virtual bool IsSupported => true; protected abstract Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); + public abstract string Type { get; } public async Task> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index c5700db71..54de841fe 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -583,7 +583,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Logger, Config, _appHost, - _networkManager, _streamHelper); } @@ -624,7 +623,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Logger, Config, _appHost, - _networkManager, _streamHelper); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 50a2d9abb..58e0c7448 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -12,7 +12,6 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; @@ -30,7 +29,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly IServerApplicationHost _appHost; private readonly IHdHomerunChannelCommands _channelCommands; private readonly int _numTuners; - private readonly INetworkManager _networkManager; public HdHomerunUdpStream( MediaSourceInfo mediaSource, @@ -42,12 +40,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun ILogger logger, IConfigurationManager configurationManager, IServerApplicationHost appHost, - INetworkManager networkManager, IStreamHelper streamHelper) : base(mediaSource, tunerHostInfo, fileSystem, logger, configurationManager, streamHelper) { _appHost = appHost; - _networkManager = networkManager; OriginalStreamId = originalStreamId; _channelCommands = channelCommands; _numTuners = numTuners; @@ -128,7 +124,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (udpClient) using (hdHomerunManager) { - if (!(ex is OperationCanceledException)) + if (ex is not OperationCanceledException) { Logger.LogError(ex, "Error opening live stream:"); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 69035dac9..8fa6f5ad6 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -29,6 +29,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost { + private static readonly string[] _disallowedSharedStreamExtensions = + { + ".mkv", + ".mp4", + ".m3u8", + ".mpd" + }; + private readonly IHttpClientFactory _httpClientFactory; private readonly IServerApplicationHost _appHost; private readonly INetworkManager _networkManager; @@ -67,7 +75,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { var channelIdPrefix = GetFullChannelIdPrefix(info); - return await new M3uParser(Logger, _httpClientFactory, _appHost) + return await new M3uParser(Logger, _httpClientFactory) .Parse(info, channelIdPrefix, cancellationToken) .ConfigureAwait(false); } @@ -88,14 +96,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return Task.FromResult(list); } - private static readonly string[] _disallowedSharedStreamExtensions = - { - ".mkv", - ".mp4", - ".m3u8", - ".mpd" - }; - protected override async Task GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List currentLiveStreams, CancellationToken cancellationToken) { var tunerCount = info.TunerCount; @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public async Task Validate(TunerHostInfo info) { - using (var stream = await new M3uParser(Logger, _httpClientFactory, _appHost).GetListingsStream(info, CancellationToken.None).ConfigureAwait(false)) + using (var stream = await new M3uParser(Logger, _httpClientFactory).GetListingsStream(info, CancellationToken.None).ConfigureAwait(false)) { } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 48a0c3cd3..40a162890 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -21,15 +21,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { public class M3uParser { + private const string ExtInfPrefix = "#EXTINF:"; + private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; - private readonly IServerApplicationHost _appHost; - public M3uParser(ILogger logger, IHttpClientFactory httpClientFactory, IServerApplicationHost appHost) + public M3uParser(ILogger logger, IHttpClientFactory httpClientFactory) { _logger = logger; _httpClientFactory = httpClientFactory; - _appHost = appHost; } public async Task> Parse(TunerHostInfo info, string channelIdPrefix, CancellationToken cancellationToken) @@ -61,8 +61,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return File.OpenRead(info.Url); } - private const string ExtInfPrefix = "#EXTINF:"; - private async Task> GetChannelsAsync(TextReader reader, string channelIdPrefix, string tunerHostId) { var channels = new List(); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 137ed27e2..f572151b8 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -91,8 +91,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts var taskCompletionSource = new TaskCompletionSource(); - var now = DateTime.UtcNow; - _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); // OpenedMediaSource.Protocol = MediaProtocol.File; @@ -120,7 +118,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (!taskCompletionSource.Task.Result) { Logger.LogWarning("Zero bytes copied from stream {0} to {1} but no exception raised", GetType().Name, TempFilePath); - throw new EndOfStreamException(String.Format(CultureInfo.InvariantCulture, "Zero bytes copied from stream {0}", GetType().Name)); + throw new EndOfStreamException(string.Format(CultureInfo.InvariantCulture, "Zero bytes copied from stream {0}", GetType().Name)); } } diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs index 48281b75f..16a2bd615 100644 --- a/Emby.Server.Implementations/Plugins/PluginManager.cs +++ b/Emby.Server.Implementations/Plugins/PluginManager.cs @@ -455,7 +455,8 @@ namespace Emby.Server.Implementations.Plugins try { _logger.LogDebug("Creating instance of {Type}", type); - var instance = (IPlugin)ActivatorUtilities.CreateInstance(_appHost.ServiceProvider, type); + // _appHost.ServiceProvider is already assigned when we create the plugins + var instance = (IPlugin)ActivatorUtilities.CreateInstance(_appHost.ServiceProvider!, type); if (plugin == null) { // Create a dummy record for the providers. diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index ccbd4289e..d7e320754 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -711,11 +711,7 @@ namespace Emby.Server.Implementations.ScheduledTasks throw new ArgumentException("Info did not contain a TimeOfDayTicks.", nameof(info)); } - return new DailyTrigger - { - TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value), - TaskOptions = options - }; + return new DailyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), options); } if (info.Type.Equals(nameof(WeeklyTrigger), StringComparison.OrdinalIgnoreCase)) @@ -730,12 +726,7 @@ namespace Emby.Server.Implementations.ScheduledTasks throw new ArgumentException("Info did not contain a DayOfWeek.", nameof(info)); } - return new WeeklyTrigger - { - TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value), - DayOfWeek = info.DayOfWeek.Value, - TaskOptions = options - }; + return new WeeklyTrigger(TimeSpan.FromTicks(info.TimeOfDayTicks.Value), info.DayOfWeek.Value, options); } if (info.Type.Equals(nameof(IntervalTrigger), StringComparison.OrdinalIgnoreCase)) @@ -745,16 +736,12 @@ namespace Emby.Server.Implementations.ScheduledTasks throw new ArgumentException("Info did not contain a IntervalTicks.", nameof(info)); } - return new IntervalTrigger - { - Interval = TimeSpan.FromTicks(info.IntervalTicks.Value), - TaskOptions = options - }; + return new IntervalTrigger(TimeSpan.FromTicks(info.IntervalTicks.Value), options); } if (info.Type.Equals(nameof(StartupTrigger), StringComparison.OrdinalIgnoreCase)) { - return new StartupTrigger(); + return new StartupTrigger(options); } throw new ArgumentException("Unrecognized trigger type: " + info.Type); diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs index 3b63536a4..29ab6a73d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Threading; using MediaBrowser.Model.Tasks; @@ -10,29 +8,31 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Represents a task trigger that fires everyday. /// - public class DailyTrigger : ITaskTrigger + public sealed class DailyTrigger : ITaskTrigger { - /// - /// Occurs when [triggered]. - /// - public event EventHandler Triggered; + private readonly TimeSpan _timeOfDay; + private Timer? _timer; /// - /// Gets or sets the time of day to trigger the task to run. + /// Initializes a new instance of the class. /// - /// The time of day. - public TimeSpan TimeOfDay { get; set; } + /// The time of day to trigger the task to run. + /// The options of this task. + public DailyTrigger(TimeSpan timeofDay, TaskOptions taskOptions) + { + _timeOfDay = timeofDay; + TaskOptions = taskOptions; + } /// - /// Gets or sets the options of this task. + /// Occurs when [triggered]. /// - public TaskOptions TaskOptions { get; set; } + public event EventHandler? Triggered; /// - /// Gets or sets the timer. + /// Gets the options of this task. /// - /// The timer. - private Timer Timer { get; set; } + public TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. @@ -47,14 +47,14 @@ namespace Emby.Server.Implementations.ScheduledTasks var now = DateTime.Now; - var triggerDate = now.TimeOfDay > TimeOfDay ? now.Date.AddDays(1) : now.Date; - triggerDate = triggerDate.Add(TimeOfDay); + var triggerDate = now.TimeOfDay > _timeOfDay ? now.Date.AddDays(1) : now.Date; + triggerDate = triggerDate.Add(_timeOfDay); var dueTime = triggerDate - now; logger.LogInformation("Daily trigger for {Task} set to fire at {TriggerDate:yyyy-MM-dd HH:mm:ss.fff zzz}, which is {DueTime:c} from now.", taskName, triggerDate, dueTime); - Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); + _timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); } /// @@ -70,10 +70,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private void DisposeTimer() { - if (Timer != null) - { - Timer.Dispose(); - } + _timer?.Dispose(); } /// diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs index e13782fe0..30568e809 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Linq; using System.Threading; @@ -11,31 +9,32 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Represents a task trigger that runs repeatedly on an interval. /// - public class IntervalTrigger : ITaskTrigger + public sealed class IntervalTrigger : ITaskTrigger { + private readonly TimeSpan _interval; private DateTime _lastStartDate; + private Timer? _timer; /// - /// Occurs when [triggered]. - /// - public event EventHandler Triggered; - - /// - /// Gets or sets the interval. + /// Initializes a new instance of the class. /// - /// The interval. - public TimeSpan Interval { get; set; } + /// The interval. + /// The options of this task. + public IntervalTrigger(TimeSpan interval, TaskOptions taskOptions) + { + _interval = interval; + TaskOptions = taskOptions; + } /// - /// Gets or sets the options of this task. + /// Occurs when [triggered]. /// - public TaskOptions TaskOptions { get; set; } + public event EventHandler? Triggered; /// - /// Gets or sets the timer. + /// Gets the options of this task. /// - /// The timer. - private Timer Timer { get; set; } + public TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. @@ -57,7 +56,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } else { - triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(Interval); + triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(_interval); } if (DateTime.UtcNow > triggerDate) @@ -73,7 +72,7 @@ namespace Emby.Server.Implementations.ScheduledTasks dueTime = maxDueTime; } - Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); + _timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1)); } /// @@ -89,10 +88,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private void DisposeTimer() { - if (Timer != null) - { - Timer.Dispose(); - } + _timer?.Dispose(); } /// diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs index ced14195b..18b9a8b75 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -12,24 +10,28 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Class StartupTaskTrigger. /// - public class StartupTrigger : ITaskTrigger + public sealed class StartupTrigger : ITaskTrigger { + public const int DelayMs = 3000; + /// - /// Occurs when [triggered]. + /// Initializes a new instance of the class. /// - public event EventHandler Triggered; - - public int DelayMs { get; set; } + /// The options of this task. + public StartupTrigger(TaskOptions taskOptions) + { + TaskOptions = taskOptions; + } /// - /// Gets or sets the options of this task. + /// Occurs when [triggered]. /// - public TaskOptions TaskOptions { get; set; } + public event EventHandler? Triggered; - public StartupTrigger() - { - DelayMs = 3000; - } + /// + /// Gets the options of this task. + /// + public TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs index a67f940b7..36ae190b0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Threading; using MediaBrowser.Model.Tasks; @@ -10,35 +8,34 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Represents a task trigger that fires on a weekly basis. /// - public class WeeklyTrigger : ITaskTrigger + public sealed class WeeklyTrigger : ITaskTrigger { - /// - /// Occurs when [triggered]. - /// - public event EventHandler Triggered; - - /// - /// Gets or sets the time of day to trigger the task to run. - /// - /// The time of day. - public TimeSpan TimeOfDay { get; set; } + private readonly TimeSpan _timeOfDay; + private readonly DayOfWeek _dayOfWeek; + private Timer? _timer; /// - /// Gets or sets the day of week. + /// Initializes a new instance of the class. /// - /// The day of week. - public DayOfWeek DayOfWeek { get; set; } + /// The time of day to trigger the task to run. + /// The day of week. + /// The options of this task. + public WeeklyTrigger(TimeSpan timeofDay, DayOfWeek dayOfWeek, TaskOptions taskOptions) + { + _timeOfDay = timeofDay; + _dayOfWeek = dayOfWeek; + TaskOptions = taskOptions; + } /// - /// Gets or sets the options of this task. + /// Occurs when [triggered]. /// - public TaskOptions TaskOptions { get; set; } + public event EventHandler? Triggered; /// - /// Gets or sets the timer. + /// Gets the options of this task. /// - /// The timer. - private Timer Timer { get; set; } + public TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. @@ -53,7 +50,7 @@ namespace Emby.Server.Implementations.ScheduledTasks var triggerDate = GetNextTriggerDateTime(); - Timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.Now, TimeSpan.FromMilliseconds(-1)); + _timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.Now, TimeSpan.FromMilliseconds(-1)); } /// @@ -65,22 +62,22 @@ namespace Emby.Server.Implementations.ScheduledTasks var now = DateTime.Now; // If it's on the same day - if (now.DayOfWeek == DayOfWeek) + if (now.DayOfWeek == _dayOfWeek) { // It's either later today, or a week from now - return now.TimeOfDay < TimeOfDay ? now.Date.Add(TimeOfDay) : now.Date.AddDays(7).Add(TimeOfDay); + return now.TimeOfDay < _timeOfDay ? now.Date.Add(_timeOfDay) : now.Date.AddDays(7).Add(_timeOfDay); } var triggerDate = now.Date; // Walk the date forward until we get to the trigger day - while (triggerDate.DayOfWeek != DayOfWeek) + while (triggerDate.DayOfWeek != _dayOfWeek) { triggerDate = triggerDate.AddDays(1); } // Return the trigger date plus the time offset - return triggerDate.Add(TimeOfDay); + return triggerDate.Add(_timeOfDay); } /// @@ -96,10 +93,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private void DisposeTimer() { - if (Timer != null) - { - Timer.Dispose(); - } + _timer?.Dispose(); } /// diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index ed1dfca59..9fa92a53a 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -1,5 +1,4 @@ #pragma warning disable CS1591 -#pragma warning disable SA1600 using System; using System.Collections.Generic; diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index 750f00168..8179e26c5 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Net; using System.Net.Sockets; @@ -19,6 +17,11 @@ namespace Emby.Server.Implementations.Udp /// public sealed class UdpServer : IDisposable { + /// + /// Address Override Configuration Key. + /// + public const string AddressOverrideConfigKey = "PublishedServerUrl"; + /// /// The _logger. /// @@ -26,11 +29,6 @@ namespace Emby.Server.Implementations.Udp private readonly IServerApplicationHost _appHost; private readonly IConfiguration _config; - /// - /// Address Override Configuration Key. - /// - public const string AddressOverrideConfigKey = "PublishedServerUrl"; - private Socket _udpSocket; private IPEndPoint _endpoint; private readonly byte[] _receiveBuffer = new byte[8192]; @@ -40,49 +38,58 @@ namespace Emby.Server.Implementations.Udp /// /// Initializes a new instance of the class. /// - public UdpServer(ILogger logger, IServerApplicationHost appHost, IConfiguration configuration) + /// The logger. + /// The application host. + /// The configuration manager. + /// The port. + public UdpServer( + ILogger logger, + IServerApplicationHost appHost, + IConfiguration configuration, + int port) { _logger = logger; _appHost = appHost; _config = configuration; + + _endpoint = new IPEndPoint(IPAddress.Any, port); + + _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); } private async Task RespondToV2Message(string messageText, EndPoint endpoint, CancellationToken cancellationToken) { - string localUrl = !string.IsNullOrEmpty(_config[AddressOverrideConfigKey]) - ? _config[AddressOverrideConfigKey] - : _appHost.GetSmartApiUrl(((IPEndPoint)endpoint).Address); + string? localUrl = _config[AddressOverrideConfigKey]; + if (string.IsNullOrEmpty(localUrl)) + { + localUrl = _appHost.GetSmartApiUrl(((IPEndPoint)endpoint).Address); + } - if (!string.IsNullOrEmpty(localUrl)) + if (string.IsNullOrEmpty(localUrl)) { - var response = new ServerDiscoveryInfo(localUrl, _appHost.SystemId, _appHost.FriendlyName); + _logger.LogWarning("Unable to respond to udp request because the local ip address could not be determined."); + return; + } - try - { - await _udpSocket.SendToAsync(JsonSerializer.SerializeToUtf8Bytes(response), SocketFlags.None, endpoint).ConfigureAwait(false); - } - catch (SocketException ex) - { - _logger.LogError(ex, "Error sending response message"); - } + var response = new ServerDiscoveryInfo(localUrl, _appHost.SystemId, _appHost.FriendlyName); + + try + { + await _udpSocket.SendToAsync(JsonSerializer.SerializeToUtf8Bytes(response), SocketFlags.None, endpoint).ConfigureAwait(false); } - else + catch (SocketException ex) { - _logger.LogWarning("Unable to respond to udp request because the local ip address could not be determined."); + _logger.LogError(ex, "Error sending response message"); } } /// /// Starts the specified port. /// - /// The port. /// The cancellation token to cancel operation. - public void Start(int port, CancellationToken cancellationToken) + public void Start(CancellationToken cancellationToken) { - _endpoint = new IPEndPoint(IPAddress.Any, port); - - _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _udpSocket.Bind(_endpoint); _ = Task.Run(async () => await BeginReceiveAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); @@ -90,9 +97,9 @@ namespace Emby.Server.Implementations.Udp private async Task BeginReceiveAsync(CancellationToken cancellationToken) { + var infiniteTask = Task.Delay(-1, cancellationToken); while (!cancellationToken.IsCancellationRequested) { - var infiniteTask = Task.Delay(-1, cancellationToken); try { var task = _udpSocket.ReceiveFromAsync(_receiveBuffer, SocketFlags.None, _endpoint); diff --git a/Jellyfin.Server.Implementations/Events/EventManager.cs b/Jellyfin.Server.Implementations/Events/EventManager.cs index 707002442..c5e66112d 100644 --- a/Jellyfin.Server.Implementations/Events/EventManager.cs +++ b/Jellyfin.Server.Implementations/Events/EventManager.cs @@ -43,7 +43,12 @@ namespace Jellyfin.Server.Implementations.Events private async Task PublishInternal(T eventArgs) where T : EventArgs { - using var scope = _appHost.ServiceProvider.CreateScope(); + using var scope = _appHost.ServiceProvider?.CreateScope(); + if (scope == null) + { + return; + } + foreach (var service in scope.ServiceProvider.GetServices>()) { try diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 46d93e494..192a77611 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using System.Reflection; @@ -12,7 +10,7 @@ namespace MediaBrowser.Common /// /// Type to create. /// New instance of type type. - public delegate object CreationDelegateFactory(Type type); + public delegate object? CreationDelegateFactory(Type type); /// /// An interface to be implemented by the applications hosting a kernel. @@ -22,7 +20,7 @@ namespace MediaBrowser.Common /// /// Occurs when [has pending restart changed]. /// - event EventHandler HasPendingRestartChanged; + event EventHandler? HasPendingRestartChanged; /// /// Gets the name. @@ -63,7 +61,7 @@ namespace MediaBrowser.Common /// /// Gets or sets the service provider. /// - IServiceProvider ServiceProvider { get; set; } + IServiceProvider? ServiceProvider { get; set; } /// /// Gets the application version. diff --git a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs deleted file mode 100644 index cec1aaf08..000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs +++ /dev/null @@ -1,9 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - public static class ParserValues - { - public const string NewLine = "\r\n"; - } -} diff --git a/MediaBrowser.Model/Tasks/ITaskTrigger.cs b/MediaBrowser.Model/Tasks/ITaskTrigger.cs index db9fba696..999db9605 100644 --- a/MediaBrowser.Model/Tasks/ITaskTrigger.cs +++ b/MediaBrowser.Model/Tasks/ITaskTrigger.cs @@ -14,9 +14,9 @@ namespace MediaBrowser.Model.Tasks event EventHandler? Triggered; /// - /// Gets or sets the options of this task. + /// Gets the options of this task. /// - TaskOptions TaskOptions { get; set; } + TaskOptions TaskOptions { get; } /// /// Stars waiting for the trigger action. diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 1a9f2bf96..44bc34369 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -1,6 +1,9 @@ + + + -- cgit v1.2.3 From 9af16fcb6c892238b734c267873b1fc137d38e66 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 3 Oct 2021 19:52:38 +0200 Subject: Remove workaround for dotnet/runtime#42790 --- Emby.Dlna/DlnaManager.cs | 9 ++++--- Emby.Drawing/ImageProcessor.cs | 2 +- .../AppBase/ConfigurationHelper.cs | 9 +++---- .../LiveTv/EmbyTV/DirectRecorder.cs | 6 ++--- .../LiveTv/EmbyTV/EmbyTV.cs | 12 +++------ .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 31 ---------------------- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 12 +++++++-- .../Subtitles/SubtitleEncoder.cs | 1 - MediaBrowser.Model/IO/AsyncFile.cs | 19 +++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +++-- .../Manager/ItemImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 3 +-- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 7 +++-- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 6 +++-- .../Studios/StudiosImageProvider.cs | 7 ++--- .../Subtitles/SubtitleManager.cs | 6 +++-- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 11 ++++++-- 18 files changed, 77 insertions(+), 74 deletions(-) (limited to 'Emby.Server.Implementations/AppBase/ConfigurationHelper.cs') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 8fe9d484e..73e8a0008 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -359,14 +359,17 @@ namespace Emby.Dlna // The stream should exist as we just got its name from GetManifestResourceNames using (var stream = _assembly.GetManifestResourceStream(name)!) { + var length = stream.Length; var fileInfo = _fileSystem.GetFileInfo(path); - if (!fileInfo.Exists || fileInfo.Length != stream.Length) + if (!fileInfo.Exists || fileInfo.Length != length) { Directory.CreateDirectory(systemProfilesPath); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = length; + using (var fileStream = new FileStream(path, fileOptions)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 9b130fdfd..ac73cfa42 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var fileStream = AsyncFile.OpenRead(file.Item1)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 0308a68e4..3a916e5c0 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -41,20 +41,19 @@ namespace Emby.Server.Implementations.AppBase xmlSerializer.SerializeToStream(configuration, stream); // Take the object we just got and serialize it back to bytes - byte[] newBytes = stream.GetBuffer(); - int newBytesLen = (int)stream.Length; + Span newBytes = stream.GetBuffer().AsSpan(0, (int)stream.Length); // If the file didn't exist before, or if something has changed, re-save - if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer)) + if (buffer == null || !newBytes.SequenceEqual(buffer)) { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // Save it after load in case we got new items - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { - fs.Write(newBytes, 0, newBytesLen); + fs.Write(newBytes); } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 41381d55b..6937cc097 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,8 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -79,8 +78,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); + await using var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 64e54aa99..980b42729 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1848,14 +1848,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; using (var writer = XmlWriter.Create(stream, settings)) @@ -1913,14 +1911,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; var options = _config.GetNfoConfiguration(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3633fa3e1..016a3e83f 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + _logFileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 8a33b12f4..35921ede8 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -183,36 +183,5 @@ namespace Jellyfin.Api.Controllers { return Path.Combine(_applicationPaths.CachePath, "remote-images", filename.Substring(0, 1), filename); } - - /// - /// Downloads the image. - /// - /// The URL. - /// The URL hash. - /// The pointer cache path. - /// Task. - private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using var response = await httpClient.GetAsync(url).ConfigureAwait(false); - if (response.Content.Headers.ContentType?.MediaType == null) - { - throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType)); - } - - var ext = response.Content.Headers.ContentType.MediaType.AsSpan().RightPart('/').ToString(); - var fullCachePath = GetFullCachePath(urlHash + "." + ext); - - var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); - Directory.CreateDirectory(fullCacheDirectory); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); - - var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); - Directory.CreateDirectory(pointerCacheDirectory); - await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None) - .ConfigureAwait(false); - } } } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 6f66fd61b..5e7af23fc 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -113,11 +113,19 @@ namespace MediaBrowser.LocalMetadata.Savers { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // On Windows, savint the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 022cdbe9d..bfc17904c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -679,7 +679,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) using (var writer = new StreamWriter(fileStream, encoding)) { diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index caee9c528..3c8007d1c 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -7,6 +7,25 @@ namespace MediaBrowser.Model.IO /// public static class AsyncFile { + /// + /// Gets the default for reading files async. + /// + public static FileStreamOptions ReadOptions => new FileStreamOptions() + { + Options = FileOptions.Asynchronous + }; + + /// + /// Gets the default for writing files async. + /// + public static FileStreamOptions WriteOptions => new FileStreamOptions() + { + Mode = FileMode.OpenOrCreate, + Access = FileAccess.Write, + Share = FileShare.None, + Options = FileOptions.Asynchronous + }; + /// /// Opens an existing file for reading. /// diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 4b05edd67..3d8dd1486 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -261,8 +261,10 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = source.Length; + await using (var fs = new FileStream(path, fileStreamOptions)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 73bca5aa5..3593697d7 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var stream = AsyncFile.OpenRead(response.Path); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index b51a25417..9be887e9c 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -210,8 +210,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(source)); } - var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - + var fileStream = AsyncFile.OpenRead(source); return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index 3e0b0014e..ebdcb94eb 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -172,8 +172,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index e0b2f9c58..321013b17 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -154,8 +154,10 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 7b2454efc..a1873eaae 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -172,19 +172,16 @@ namespace MediaBrowser.Providers.Studios public IEnumerable GetAvailableImages(string file) { - using var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var fileStream = File.OpenRead(file); using var reader = new StreamReader(fileStream); - var lines = new List(); foreach (var line in reader.ReadAllLines()) { if (!string.IsNullOrWhiteSpace(line)) { - lines.Add(line); + yield return line; } } - - return lines; } } } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 772e617ab..e625b0dd2 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -244,8 +244,10 @@ namespace MediaBrowser.Providers.Subtitles { Directory.CreateDirectory(Path.GetDirectoryName(savePath)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = stream.Length; + using var fs = new FileStream(savePath, fileOptions); await stream.CopyToAsync(fs).ConfigureAwait(false); return; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 38726a6f0..594402258 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -203,8 +203,15 @@ namespace MediaBrowser.XbmcMetadata.Savers // On Windows, saving the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } -- cgit v1.2.3