aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/LiveTv
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-02-01 14:24:15 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-02-01 14:24:15 -0500
commit37352785acef4db99301c1e88624cf48133ec979 (patch)
tree15638d697cc56a0a774bf261de9814c9034f8e42 /MediaBrowser.Server.Implementations/LiveTv
parentf14e9b8d3af98f6ffbe243b105f96f46e8cf3b06 (diff)
parentf5ebeddbf5104092ce584486689af6640125054f (diff)
Merge branch 'beta'
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv')
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs100
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs1
4 files changed, 116 insertions, 24 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 356d0d83d5..cd91684ce1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -22,12 +22,15 @@ using MediaBrowser.Server.Implementations.FileOrganization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Power;
+using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -55,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public static EmbyTV Current;
- public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
+ public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
{
Current = this;
@@ -75,13 +78,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
_seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+ _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), powerManagement, _logger);
_timerProvider.TimerFired += _timerProvider_TimerFired;
}
public void Start()
{
_timerProvider.RestartTimers();
+
+ SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+
+ }
+
+ void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ _logger.Info("Power mode changed to {0}", e.Mode);
+
+ if (e.Mode == PowerModes.Resume)
+ {
+ _timerProvider.RestartTimers();
+ }
}
public event EventHandler DataSourceChanged;
@@ -155,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
epgData = GetEpgDataForChannel(timer.ChannelId);
}
- await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
+ await UpdateTimersForSeriesTimer(epgData, timer, false).ConfigureAwait(false);
}
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false);
@@ -223,7 +239,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken)
{
- var timers = _timerProvider.GetAll().Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase));
+ var timers = _timerProvider
+ .GetAll()
+ .Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
foreach (var timer in timers)
{
CancelTimerInternal(timer.Id);
@@ -332,25 +352,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
_seriesTimerProvider.Add(info);
- await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false);
+ await UpdateTimersForSeriesTimer(epgData, info, false).ConfigureAwait(false);
}
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{
- _seriesTimerProvider.Update(info);
- List<ProgramInfo> epgData;
- if (info.RecordAnyChannel)
- {
- var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false);
- var channelIds = channels.Select(i => i.Id).ToList();
- epgData = GetEpgDataForChannels(channelIds);
- }
- else
+ var instance = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+
+ if (instance != null)
{
- epgData = GetEpgDataForChannel(info.ChannelId);
- }
+ instance.ChannelId = info.ChannelId;
+ instance.Days = info.Days;
+ instance.EndDate = info.EndDate;
+ instance.IsPostPaddingRequired = info.IsPostPaddingRequired;
+ instance.IsPrePaddingRequired = info.IsPrePaddingRequired;
+ instance.PostPaddingSeconds = info.PostPaddingSeconds;
+ instance.PrePaddingSeconds = info.PrePaddingSeconds;
+ instance.Priority = info.Priority;
+ instance.RecordAnyChannel = info.RecordAnyChannel;
+ instance.RecordAnyTime = info.RecordAnyTime;
+ instance.RecordNewOnly = info.RecordNewOnly;
+ instance.StartDate = info.StartDate;
- await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false);
+ _seriesTimerProvider.Update(instance);
+
+ List<ProgramInfo> epgData;
+ if (instance.RecordAnyChannel)
+ {
+ var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false);
+ var channelIds = channels.Select(i => i.Id).ToList();
+ epgData = GetEpgDataForChannels(channelIds);
+ }
+ else
+ {
+ epgData = GetEpgDataForChannel(instance.ChannelId);
+ }
+
+ await UpdateTimersForSeriesTimer(epgData, instance, true).ConfigureAwait(false);
+ }
}
public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
@@ -603,6 +642,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
await RecordStream(timer, recordingEndDate, cancellationTokenSource.Token).ConfigureAwait(false);
}
+ else
+ {
+ _logger.Info("Skipping RecordStream because it's already in progress.");
+ }
}
catch (OperationCanceledException)
{
@@ -721,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.AddOrUpdate(recording);
- _logger.Info("Beginning recording.");
+ _logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
@@ -836,7 +879,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
- private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer)
+ private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
{
var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList();
@@ -849,12 +892,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer);
}
}
+
+ if (deleteInvalidTimers)
+ {
+ var allTimers = GetTimersForSeries(seriesTimer, epgData, new List<RecordingInfo>())
+ .Select(i => i.Id)
+ .ToList();
+
+ var deletes = _timerProvider.GetAll()
+ .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase))
+ .Where(i => !allTimers.Contains(i.Id, StringComparer.OrdinalIgnoreCase) && i.StartDate > DateTime.UtcNow)
+ .ToList();
+
+ foreach (var timer in deletes)
+ {
+ await CancelTimerAsync(timer.Id, CancellationToken.None).ConfigureAwait(false);
+ }
+ }
}
private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms, IReadOnlyList<RecordingInfo> currentRecordings)
{
// Exclude programs that have already ended
- allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow);
+ allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow && i.StartDate > DateTime.UtcNow);
allPrograms = GetProgramsForSeries(seriesTimer, allPrograms);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index f46daa6d50..b29a7562cf 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
where T : class
{
private readonly object _fileDataLock = new object();
- private List<T> _items;
+ private volatile List<T> _items;
private readonly IJsonSerializer _jsonSerializer;
protected readonly ILogger Logger;
private readonly string _dataPath;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 80bb671fa7..5d462f1069 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -5,22 +5,27 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
+using System.Globalization;
using System.Linq;
using System.Threading;
using CommonIO;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Power;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class TimerManager : ItemDataProvider<TimerInfo>
{
private readonly ConcurrentDictionary<string, Timer> _timers = new ConcurrentDictionary<string, Timer>(StringComparer.OrdinalIgnoreCase);
+ private readonly IPowerManagement _powerManagement;
+ private readonly ILogger _logger;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, IPowerManagement powerManagement, ILogger logger1)
: base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
+ _powerManagement = powerManagement;
+ _logger = logger1;
}
public void RestartTimers()
@@ -58,6 +63,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow;
timer.Change(timespan, TimeSpan.Zero);
+ ScheduleWake(item);
}
else
{
@@ -74,6 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
base.Add(item);
AddTimer(item);
+ ScheduleWake(item);
}
private void AddTimer(TimerInfo item)
@@ -91,15 +98,39 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
StartTimer(item, timerLength);
}
+ private void ScheduleWake(TimerInfo info)
+ {
+ var startDate = RecordingHelper.GetStartTime(info).AddMinutes(-5);
+
+ try
+ {
+ _powerManagement.ScheduleWake(startDate);
+ _logger.Info("Scheduled system wake timer at {0} (UTC)", startDate);
+ }
+ catch (NotImplementedException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error scheduling wake timer", ex);
+ }
+ }
+
public void StartTimer(TimerInfo item, TimeSpan length)
{
StopTimer(item);
var timer = new Timer(TimerCallback, item.Id, length, TimeSpan.Zero);
- if (!_timers.TryAdd(item.Id, timer))
+ if (_timers.TryAdd(item.Id, timer))
+ {
+ _logger.Info("Creating recording timer for {0}, {1}. Timer will fire in {2} minutes", item.Id, item.Name, length.TotalMinutes.ToString(CultureInfo.InvariantCulture));
+ }
+ else
{
timer.Dispose();
+ _logger.Warn("Timer already exists for item {0}", item.Id);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index e09e06bd4b..8bf1d27b8b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1954,6 +1954,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+ _logger.Info("New recording scheduled");
}
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)