2018-12-28 15:30:53 +01:00
using System ;
using System.Collections.Concurrent ;
using System.Globalization ;
using System.Linq ;
2015-07-20 20:32:55 +02:00
using MediaBrowser.Controller.LiveTv ;
using MediaBrowser.Model.Events ;
2018-12-13 14:18:25 +01:00
using Microsoft.Extensions.Logging ;
2015-07-20 20:32:55 +02:00
using MediaBrowser.Model.Serialization ;
2016-10-25 21:02:04 +02:00
using MediaBrowser.Model.IO ;
2016-06-21 00:07:18 +02:00
using MediaBrowser.Model.LiveTv ;
2016-11-04 00:35:19 +01:00
using MediaBrowser.Model.Threading ;
2015-07-20 20:32:55 +02:00
2016-11-04 00:35:19 +01:00
namespace Emby.Server.Implementations.LiveTv.EmbyTV
2015-07-20 20:32:55 +02:00
{
public class TimerManager : ItemDataProvider < TimerInfo >
{
2016-11-04 00:35:19 +01:00
private readonly ConcurrentDictionary < string , ITimer > _timers = new ConcurrentDictionary < string , ITimer > ( StringComparer . OrdinalIgnoreCase ) ;
2016-01-21 18:29:14 +01:00
private readonly ILogger _logger ;
2015-07-20 20:32:55 +02:00
public event EventHandler < GenericEventArgs < TimerInfo > > TimerFired ;
2016-11-04 00:35:19 +01:00
private readonly ITimerFactory _timerFactory ;
2015-07-20 20:32:55 +02:00
2019-01-02 15:57:48 +01:00
public TimerManager ( IFileSystem fileSystem , IJsonSerializer jsonSerializer , ILogger logger , string dataPath , ILogger logger1 , ITimerFactory timerFactory )
2015-09-14 01:07:54 +02:00
: base ( fileSystem , jsonSerializer , logger , dataPath , ( r1 , r2 ) = > string . Equals ( r1 . Id , r2 . Id , StringComparison . OrdinalIgnoreCase ) )
2015-07-20 20:32:55 +02:00
{
2016-01-21 18:29:14 +01:00
_logger = logger1 ;
2016-11-04 00:35:19 +01:00
_timerFactory = timerFactory ;
2015-07-20 20:32:55 +02:00
}
public void RestartTimers ( )
{
StopTimers ( ) ;
2015-07-29 05:42:03 +02:00
foreach ( var item in GetAll ( ) . ToList ( ) )
{
2019-01-02 15:57:48 +01:00
AddOrUpdateSystemTimer ( item ) ;
2015-07-29 05:42:03 +02:00
}
2015-07-20 20:32:55 +02:00
}
public void StopTimers ( )
{
foreach ( var pair in _timers . ToList ( ) )
{
pair . Value . Dispose ( ) ;
}
_timers . Clear ( ) ;
}
public override void Delete ( TimerInfo item )
{
base . Delete ( item ) ;
2015-08-22 20:29:12 +02:00
StopTimer ( item ) ;
2015-07-20 20:32:55 +02:00
}
public override void Update ( TimerInfo item )
{
base . Update ( item ) ;
2019-01-02 15:57:48 +01:00
AddOrUpdateSystemTimer ( item ) ;
2015-07-20 20:32:55 +02:00
}
2016-06-23 07:26:34 +02:00
public void AddOrUpdate ( TimerInfo item , bool resetTimer )
{
if ( resetTimer )
{
AddOrUpdate ( item ) ;
return ;
}
var list = GetAll ( ) . ToList ( ) ;
if ( ! list . Any ( i = > EqualityComparer ( i , item ) ) )
{
base . Add ( item ) ;
}
else
{
base . Update ( item ) ;
}
}
2015-07-20 20:32:55 +02:00
public override void Add ( TimerInfo item )
{
2018-09-12 19:26:21 +02:00
if ( string . IsNullOrEmpty ( item . Id ) )
2015-07-20 20:32:55 +02:00
{
throw new ArgumentException ( "TimerInfo.Id cannot be null or empty." ) ;
}
base . Add ( item ) ;
2019-01-02 15:57:48 +01:00
AddOrUpdateSystemTimer ( item ) ;
2016-09-26 20:59:18 +02:00
}
private bool ShouldStartTimer ( TimerInfo item )
{
if ( item . Status = = RecordingStatus . Completed | |
item . Status = = RecordingStatus . Cancelled )
{
return false ;
}
return true ;
2015-07-20 20:32:55 +02:00
}
2019-01-02 15:57:48 +01:00
private void AddOrUpdateSystemTimer ( TimerInfo item )
2015-07-20 20:32:55 +02:00
{
2016-09-26 20:59:18 +02:00
StopTimer ( item ) ;
if ( ! ShouldStartTimer ( item ) )
2016-06-21 00:07:18 +02:00
{
return ;
}
2015-07-29 05:42:03 +02:00
var startDate = RecordingHelper . GetStartTime ( item ) ;
var now = DateTime . UtcNow ;
if ( startDate < now )
{
2018-12-28 15:21:02 +01:00
TimerFired ? . Invoke ( this , new GenericEventArgs < TimerInfo > { Argument = item } ) ;
2015-07-29 05:42:03 +02:00
return ;
}
2016-09-26 20:59:18 +02:00
var dueTime = startDate - now ;
StartTimer ( item , dueTime ) ;
2015-08-22 20:29:12 +02:00
}
2015-07-20 20:32:55 +02:00
2016-09-26 20:59:18 +02:00
private void StartTimer ( TimerInfo item , TimeSpan dueTime )
2015-08-22 20:29:12 +02:00
{
2016-11-04 00:35:19 +01:00
var timer = _timerFactory . Create ( TimerCallback , item . Id , dueTime , TimeSpan . Zero ) ;
2015-07-20 20:32:55 +02:00
2016-01-28 20:10:56 +01:00
if ( _timers . TryAdd ( item . Id , timer ) )
{
2018-12-20 13:11:26 +01:00
_logger . LogInformation ( "Creating recording timer for {id}, {name}. Timer will fire in {minutes} minutes" , item . Id , item . Name , dueTime . TotalMinutes . ToString ( CultureInfo . InvariantCulture ) ) ;
2016-01-28 20:10:56 +01:00
}
else
2015-07-20 20:32:55 +02:00
{
timer . Dispose ( ) ;
2018-12-20 13:11:26 +01:00
_logger . LogWarning ( "Timer already exists for item {id}" , item . Id ) ;
2015-07-20 20:32:55 +02:00
}
}
2015-08-22 20:29:12 +02:00
private void StopTimer ( TimerInfo item )
{
2016-11-04 00:35:19 +01:00
ITimer timer ;
2015-08-22 20:29:12 +02:00
if ( _timers . TryRemove ( item . Id , out timer ) )
{
timer . Dispose ( ) ;
}
}
2015-07-20 20:32:55 +02:00
private void TimerCallback ( object state )
{
var timerId = ( string ) state ;
var timer = GetAll ( ) . FirstOrDefault ( i = > string . Equals ( i . Id , timerId , StringComparison . OrdinalIgnoreCase ) ) ;
if ( timer ! = null )
{
2018-12-28 15:21:02 +01:00
TimerFired ? . Invoke ( this , new GenericEventArgs < TimerInfo > { Argument = timer } ) ;
2015-07-20 20:32:55 +02:00
}
}
2016-09-27 07:13:56 +02:00
public TimerInfo GetTimer ( string id )
{
return GetAll ( ) . FirstOrDefault ( r = > string . Equals ( r . Id , id , StringComparison . OrdinalIgnoreCase ) ) ;
}
2017-03-26 06:21:32 +02:00
public TimerInfo GetTimerByProgramId ( string programId )
{
return GetAll ( ) . FirstOrDefault ( r = > string . Equals ( r . ProgramId , programId , StringComparison . OrdinalIgnoreCase ) ) ;
}
2015-07-20 20:32:55 +02:00
}
}