Forráskód Böngészése

implement keep up to

Luke Pulverenti 8 éve
szülő
commit
64d63c1b4b

+ 3 - 0
MediaBrowser.Controller/LiveTv/TimerInfo.cs

@@ -9,6 +9,7 @@ namespace MediaBrowser.Controller.LiveTv
         public TimerInfo()
         {
             Genres = new List<string>();
+            KeepUntil = KeepUntil.UntilDeleted;
         }
 
         /// <summary>
@@ -109,5 +110,7 @@ namespace MediaBrowser.Controller.LiveTv
         public string ShortOverview { get; set; }
         public string OfficialRating { get; set; }
         public List<string> Genres { get; set; }
+        public string RecordingPath { get; set; }
+        public KeepUntil KeepUntil { get; set; }
     }
 }

+ 1 - 0
MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs

@@ -105,5 +105,6 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
         public bool IsPostPaddingRequired { get; set; }
+        public KeepUntil KeepUntil { get; set; }
     }
 }

+ 0 - 1
MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs

@@ -27,7 +27,6 @@ namespace MediaBrowser.Model.LiveTv
         public bool RecordAnyChannel { get; set; }
 
         public int KeepUpTo { get; set; }
-        public KeepUntil KeepUntil { get; set; }
 
         /// <summary>
         /// Gets or sets a value indicating whether [record new only].

+ 118 - 20
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -442,7 +442,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         private void CancelTimerInternal(string timerId, bool isSeriesCancelled)
         {
-            var timer = _timerProvider.GetAll().FirstOrDefault(r => string.Equals(r.Id, timerId, StringComparison.OrdinalIgnoreCase));
+            var timer = _timerProvider.GetTimer(timerId);
             if (timer != null)
             {
                 if (string.IsNullOrWhiteSpace(timer.SeriesTimerId) || isSeriesCancelled)
@@ -474,10 +474,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             return Task.FromResult(true);
         }
 
+        public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
         public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<string> CreateTimer(TimerInfo timer, CancellationToken cancellationToken)
         {
             var existingTimer = _timerProvider.GetAll()
-                .FirstOrDefault(i => string.Equals(info.ProgramId, i.ProgramId, StringComparison.OrdinalIgnoreCase));
+                .FirstOrDefault(i => string.Equals(timer.ProgramId, i.ProgramId, StringComparison.OrdinalIgnoreCase));
 
             if (existingTimer != null)
             {
@@ -485,6 +495,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                 {
                     existingTimer.Status = RecordingStatus.New;
                     _timerProvider.Update(existingTimer);
+                    return Task.FromResult(existingTimer.Id);
                 }
                 else
                 {
@@ -492,16 +503,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                 }
             }
 
-            return CreateTimer(info, cancellationToken);
-        }
-
-        public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
-        {
-            return CreateSeriesTimer(info, cancellationToken);
-        }
-
-        public Task<string> CreateTimer(TimerInfo timer, CancellationToken cancellationToken)
-        {
             timer.Id = Guid.NewGuid().ToString("N");
 
             ProgramInfo programInfo = null;
@@ -601,9 +602,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         public Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken)
         {
-            var existingTimer = _timerProvider
-                .GetAll()
-                .FirstOrDefault(i => string.Equals(i.Id, updatedTimer.Id, StringComparison.OrdinalIgnoreCase));
+            var existingTimer = _timerProvider.GetTimer(updatedTimer.Id);
 
             if (existingTimer == null)
             {
@@ -1137,6 +1136,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                     _timerProvider.AddOrUpdate(timer, false);
 
                     SaveNfo(timer, recordPath, seriesPath);
+                    EnforceKeepUpTo(timer);
                 };
 
                 var pathWithDuration = tunerHost.ApplyDuration(mediaStreamInfo.Path, duration);
@@ -1148,8 +1148,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                     mediaStreamInfo.RunTimeTicks = duration.Ticks;
                 }
 
-                await
-                    recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken)
+                await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken)
                         .ConfigureAwait(false);
 
                 recordingStatus = RecordingStatus.Completed;
@@ -1195,6 +1194,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             }
             else if (File.Exists(recordPath))
             {
+                timer.RecordingPath = recordPath;
                 timer.Status = RecordingStatus.Completed;
                 _timerProvider.AddOrUpdate(timer, false);
                 OnSuccessfulRecording(timer, recordPath);
@@ -1205,6 +1205,102 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             }
         }
 
+        private async void EnforceKeepUpTo(TimerInfo timer)
+        {
+            if (string.IsNullOrWhiteSpace(timer.SeriesTimerId))
+            {
+                return;
+            }
+
+            var seriesTimerId = timer.SeriesTimerId;
+            var seriesTimer = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, seriesTimerId, StringComparison.OrdinalIgnoreCase));
+
+            if (seriesTimer == null || seriesTimer.KeepUpTo <= 1)
+            {
+                return;
+            }
+
+            if (_disposed)
+            {
+                return;
+            }
+
+            await _recordingDeleteSemaphore.WaitAsync().ConfigureAwait(false);
+
+            try
+            {
+                if (_disposed)
+                {
+                    return;
+                }
+
+                var timersToDelete = _timerProvider.GetAll()
+                    .Where(i => i.Status == RecordingStatus.Completed && !string.IsNullOrWhiteSpace(i.RecordingPath))
+                    .Where(i => string.Equals(i.SeriesTimerId, seriesTimerId, StringComparison.OrdinalIgnoreCase))
+                    .OrderByDescending(i => i.EndDate)
+                    .Where(i => File.Exists(i.RecordingPath))
+                    .Skip(seriesTimer.KeepUpTo - 1)
+                    .ToList();
+
+                await DeleteLibraryItemsForTimers(timersToDelete).ConfigureAwait(false);
+            }
+            finally
+            {
+                _recordingDeleteSemaphore.Release();
+            }
+        }
+
+        private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1,1);
+        private async Task DeleteLibraryItemsForTimers(List<TimerInfo> timers)
+        {
+            foreach (var timer in timers)
+            {
+                if (_disposed)
+                {
+                    return;
+                }
+
+                try
+                {
+                    await DeleteLibraryItemForTimer(timer).ConfigureAwait(false);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error deleting recording", ex);
+                }
+            }
+        }
+
+        private async Task DeleteLibraryItemForTimer(TimerInfo timer)
+        {
+            var libraryItem = _libraryManager.FindByPath(timer.RecordingPath, false);
+
+            if (libraryItem != null)
+            {
+                await _libraryManager.DeleteItem(libraryItem, new DeleteOptions
+                {
+                    DeleteFileLocation = true
+                });
+            }
+            else
+            {
+                try
+                {
+                    File.Delete(timer.RecordingPath);
+                }
+                catch (DirectoryNotFoundException)
+                {
+
+                }
+                catch (FileNotFoundException)
+                {
+                    
+                }
+            }
+
+            _timerProvider.Delete(timer);
+        }
+
         private string EnsureFileUnique(string path, string timerId)
         {
             var originalPath = path;
@@ -1460,9 +1556,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 foreach (var timer in allTimers)
                 {
-                    var existingTimer = _timerProvider
-                        .GetAll()
-                        .FirstOrDefault(i => string.Equals(i.Id, timer.Id, StringComparison.OrdinalIgnoreCase));
+                    var existingTimer = _timerProvider.GetTimer(timer.Id);
 
                     if (existingTimer == null)
                     {
@@ -1484,6 +1578,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                             {
                                 existingTimer.Status = RecordingStatus.Cancelled;
                             }
+
+                            existingTimer.SeriesTimerId = seriesTimer.Id;
                             _timerProvider.Update(existingTimer);
                         }
                     }
@@ -1649,8 +1745,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             return channelIds.SelectMany(GetEpgDataForChannel).ToList();
         }
 
+        private bool _disposed;
         public void Dispose()
         {
+            _disposed = true;
             foreach (var pair in _activeRecordings.ToList())
             {
                 pair.Value.CancellationTokenSource.Cancel();

+ 1 - 0
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs

@@ -25,6 +25,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             timer.PostPaddingSeconds = series.PostPaddingSeconds;
             timer.IsPostPaddingRequired = series.IsPostPaddingRequired;
             timer.IsPrePaddingRequired = series.IsPrePaddingRequired;
+            timer.KeepUntil = series.KeepUntil;
             timer.Priority = series.Priority;
             timer.Name = parent.Name;
             timer.Overview = parent.Overview;

+ 5 - 0
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs

@@ -156,5 +156,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                 EventHelper.FireEventIfNotNull(TimerFired, this, new GenericEventArgs<TimerInfo> { Argument = timer }, Logger);
             }
         }
+
+        public TimerInfo GetTimer(string id)
+        {
+            return GetAll().FirstOrDefault(r => string.Equals(r.Id, id, StringComparison.OrdinalIgnoreCase));
+        }
     }
 }

+ 2 - 0
MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -52,6 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 PostPaddingSeconds = info.PostPaddingSeconds,
                 IsPostPaddingRequired = info.IsPostPaddingRequired,
                 IsPrePaddingRequired = info.IsPrePaddingRequired,
+                KeepUntil = info.KeepUntil,
                 ExternalChannelId = info.ChannelId,
                 ExternalSeriesTimerId = info.SeriesTimerId,
                 ServiceName = service.Name,
@@ -247,6 +248,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 PostPaddingSeconds = dto.PostPaddingSeconds,
                 IsPostPaddingRequired = dto.IsPostPaddingRequired,
                 IsPrePaddingRequired = dto.IsPrePaddingRequired,
+                KeepUntil = dto.KeepUntil,
                 Priority = dto.Priority,
                 SeriesTimerId = dto.ExternalSeriesTimerId,
                 ProgramId = dto.ExternalProgramId,