diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index d7411af502..da0013f128 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _streamHelper = streamHelper; _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers.json")); - _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers.json"), _logger); + _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers.json")); _timerProvider.TimerFired += _timerProvider_TimerFired; _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 9c45ee36a2..9055a70a67 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -10,67 +10,64 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public class ItemDataProvider where T : class { - private readonly object _fileDataLock = new object(); - private List _items; private readonly IJsonSerializer _jsonSerializer; - protected readonly ILogger Logger; private readonly string _dataPath; - protected readonly Func EqualityComparer; + private readonly object _fileDataLock = new object(); + private T[] _items; - public ItemDataProvider(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func equalityComparer) + public ItemDataProvider( + IJsonSerializer jsonSerializer, + ILogger logger, + string dataPath, + Func equalityComparer) { + _jsonSerializer = jsonSerializer; Logger = logger; _dataPath = dataPath; EqualityComparer = equalityComparer; - _jsonSerializer = jsonSerializer; + } + + protected ILogger Logger { get; } + + protected Func EqualityComparer { get; } + + private void EnsureLoaded() + { + if (_items != null) + { + return; + } + + if (File.Exists(_dataPath)) + { + Logger.LogInformation("Loading live tv data from {Path}", _dataPath); + + try + { + _items = _jsonSerializer.DeserializeFromFile(_dataPath); + return; + } + catch (Exception ex) + { + Logger.LogError(ex, "Error deserializing {Path}", _dataPath); + } + } + + _items = Array.Empty(); + } + + private void SaveList() + { + Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); + _jsonSerializer.SerializeToFile(_items, _dataPath); } public IReadOnlyList GetAll() { lock (_fileDataLock) { - if (_items == null) - { - if (!File.Exists(_dataPath)) - { - return new List(); - } - - Logger.LogInformation("Loading live tv data from {0}", _dataPath); - _items = GetItemsFromFile(_dataPath); - } - - return _items.ToList(); - } - } - - private List GetItemsFromFile(string path) - { - try - { - return _jsonSerializer.DeserializeFromFile>(path); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error deserializing {Path}", path); - } - - return new List(); - } - - private void UpdateList(List newList) - { - if (newList == null) - { - throw new ArgumentNullException(nameof(newList)); - } - - Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); - - lock (_fileDataLock) - { - _jsonSerializer.SerializeToFile(newList, _dataPath); - _items = newList; + EnsureLoaded(); + return (T[])_items.Clone(); } } @@ -81,18 +78,20 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV throw new ArgumentNullException(nameof(item)); } - var list = GetAll().ToList(); - - var index = list.FindIndex(i => EqualityComparer(i, item)); - - if (index == -1) + lock (_fileDataLock) { - throw new ArgumentException("item not found"); + EnsureLoaded(); + + var index = Array.FindIndex(_items, i => EqualityComparer(i, item)); + if (index == -1) + { + throw new ArgumentException("item not found"); + } + + _items[index] = item; + + SaveList(); } - - list[index] = item; - - UpdateList(list); } public virtual void Add(T item) @@ -102,37 +101,58 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV throw new ArgumentNullException(nameof(item)); } - var list = GetAll().ToList(); - - if (list.Any(i => EqualityComparer(i, item))) + lock (_fileDataLock) { - throw new ArgumentException("item already exists"); + EnsureLoaded(); + + if (_items.Any(i => EqualityComparer(i, item))) + { + throw new ArgumentException("item already exists", nameof(item)); + } + + int oldLen = _items.Length; + var newList = new T[oldLen + 1]; + _items.CopyTo(newList, 0); + newList[oldLen] = item; + _items = newList; + + SaveList(); } - - list.Add(item); - - UpdateList(list); } - public void AddOrUpdate(T item) + public virtual void AddOrUpdate(T item) { - var list = GetAll().ToList(); + lock (_fileDataLock) + { + EnsureLoaded(); - if (!list.Any(i => EqualityComparer(i, item))) - { - Add(item); - } - else - { - Update(item); + int index = Array.FindIndex(_items, i => EqualityComparer(i, item)); + if (index == -1) + { + int oldLen = _items.Length; + var newList = new T[oldLen + 1]; + _items.CopyTo(newList, 0); + newList[oldLen] = item; + _items = newList; + } + else + { + _items[index] = item; + } + + SaveList(); } } public virtual void Delete(T item) { - var list = GetAll().Where(i => !EqualityComparer(i, item)).ToList(); + lock (_fileDataLock) + { + EnsureLoaded(); + _items = _items.Where(i => !EqualityComparer(i, item)).ToArray(); - UpdateList(list); + SaveList(); + } } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 3c807a8ead..d09b281d4c 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -14,21 +14,19 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public class TimerManager : ItemDataProvider { private readonly ConcurrentDictionary _timers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - private readonly ILogger _logger; - public event EventHandler> TimerFired; - - public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, ILogger logger1) + public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath) : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) { - _logger = logger1; } + public event EventHandler> TimerFired; + public void RestartTimers() { StopTimers(); - foreach (var item in GetAll().ToList()) + foreach (var item in GetAll()) { AddOrUpdateSystemTimer(item); } @@ -64,16 +62,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - var list = GetAll().ToList(); + base.AddOrUpdate(item); + } - if (!list.Any(i => EqualityComparer(i, item))) - { - base.Add(item); - } - else - { - base.Update(item); - } + public override void AddOrUpdate(TimerInfo item) + { + base.AddOrUpdate(item); + AddOrUpdateSystemTimer(item); } public override void Add(TimerInfo item) @@ -89,8 +84,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private static bool ShouldStartTimer(TimerInfo item) { - if (item.Status == RecordingStatus.Completed || - item.Status == RecordingStatus.Cancelled) + if (item.Status == RecordingStatus.Completed + || item.Status == RecordingStatus.Cancelled) { return false; } @@ -126,12 +121,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (_timers.TryAdd(item.Id, timer)) { - _logger.LogInformation("Creating recording timer for {id}, {name}. Timer will fire in {minutes} minutes", item.Id, item.Name, dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture)); + Logger.LogInformation( + "Creating recording timer for {Id}, {Name}. Timer will fire in {Minutes} minutes", + item.Id, + item.Name, + dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture)); } else { timer.Dispose(); - _logger.LogWarning("Timer already exists for item {id}", item.Id); + Logger.LogWarning("Timer already exists for item {Id}", item.Id); } }