diff options
Diffstat (limited to 'src/Jellyfin.LiveTv/Timers/TimerManager.cs')
| -rw-r--r-- | src/Jellyfin.LiveTv/Timers/TimerManager.cs | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/Jellyfin.LiveTv/Timers/TimerManager.cs b/src/Jellyfin.LiveTv/Timers/TimerManager.cs new file mode 100644 index 000000000..6bcbd3324 --- /dev/null +++ b/src/Jellyfin.LiveTv/Timers/TimerManager.cs @@ -0,0 +1,172 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using Jellyfin.Data.Events; +using Jellyfin.LiveTv.EmbyTV; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.LiveTv; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.LiveTv.Timers +{ + public class TimerManager : ItemDataProvider<TimerInfo> + { + private readonly ConcurrentDictionary<string, Timer> _timers = new(StringComparer.OrdinalIgnoreCase); + + public TimerManager(ILogger<TimerManager> logger, IConfigurationManager config) + : base( + logger, + Path.Combine(config.CommonApplicationPaths.DataPath, "livetv"), + (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) + { + } + + public event EventHandler<GenericEventArgs<TimerInfo>>? TimerFired; + + public void RestartTimers() + { + StopTimers(); + + foreach (var item in GetAll()) + { + AddOrUpdateSystemTimer(item); + } + } + + public void StopTimers() + { + foreach (var pair in _timers.ToList()) + { + pair.Value.Dispose(); + } + + _timers.Clear(); + } + + public override void Delete(TimerInfo item) + { + base.Delete(item); + StopTimer(item); + } + + public override void Update(TimerInfo item) + { + base.Update(item); + AddOrUpdateSystemTimer(item); + } + + public void AddOrUpdate(TimerInfo item, bool resetTimer) + { + if (resetTimer) + { + AddOrUpdate(item); + return; + } + + base.AddOrUpdate(item); + } + + public override void AddOrUpdate(TimerInfo item) + { + base.AddOrUpdate(item); + AddOrUpdateSystemTimer(item); + } + + public override void Add(TimerInfo item) + { + ArgumentException.ThrowIfNullOrEmpty(item.Id); + + base.Add(item); + AddOrUpdateSystemTimer(item); + } + + private void AddOrUpdateSystemTimer(TimerInfo item) + { + StopTimer(item); + + if (item.Status is RecordingStatus.Completed or RecordingStatus.Cancelled) + { + return; + } + + var startDate = RecordingHelper.GetStartTime(item); + var now = DateTime.UtcNow; + + if (startDate < now) + { + TimerFired?.Invoke(this, new GenericEventArgs<TimerInfo>(item)); + return; + } + + var dueTime = startDate - now; + StartTimer(item, dueTime); + } + + private void StartTimer(TimerInfo item, TimeSpan dueTime) + { + var timer = new Timer(TimerCallback, item.Id, dueTime, TimeSpan.Zero); + + if (_timers.TryAdd(item.Id, timer)) + { + if (item.IsSeries) + { + Logger.LogInformation( + "Creating recording timer for {Id}, {Name} {SeasonNumber}x{EpisodeNumber:D2} on channel {ChannelId}. Timer will fire in {Minutes} minutes at {StartDate}", + item.Id, + item.Name, + item.SeasonNumber, + item.EpisodeNumber, + item.ChannelId, + dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture), + item.StartDate); + } + else + { + Logger.LogInformation( + "Creating recording timer for {Id}, {Name} on channel {ChannelId}. Timer will fire in {Minutes} minutes at {StartDate}", + item.Id, + item.Name, + item.ChannelId, + dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture), + item.StartDate); + } + } + else + { + timer.Dispose(); + Logger.LogWarning("Timer already exists for item {Id}", item.Id); + } + } + + private void StopTimer(TimerInfo item) + { + if (_timers.TryRemove(item.Id, out var timer)) + { + timer.Dispose(); + } + } + + private void TimerCallback(object? state) + { + var timerId = (string?)state ?? throw new ArgumentNullException(nameof(state)); + + var timer = GetAll().FirstOrDefault(i => string.Equals(i.Id, timerId, StringComparison.OrdinalIgnoreCase)); + if (timer is not null) + { + TimerFired?.Invoke(this, new GenericEventArgs<TimerInfo>(timer)); + } + } + + public TimerInfo? GetTimer(string id) + => GetAll().FirstOrDefault(r => string.Equals(r.Id, id, StringComparison.OrdinalIgnoreCase)); + + public TimerInfo? GetTimerByProgramId(string programId) + => GetAll().FirstOrDefault(r => string.Equals(r.ProgramId, programId, StringComparison.OrdinalIgnoreCase)); + } +} |
