Browse Source

filter duplicate recordings based on showId

Luke Pulverenti 8 years ago
parent
commit
9606a2a710

+ 0 - 2
Emby.Common.Implementations/Net/UdpSocket.cs

@@ -33,8 +33,6 @@ namespace Emby.Common.Implementations.Net
             _LocalPort = localPort;
             _LocalPort = localPort;
 
 
             _Socket.Bind(new IPEndPoint(ip, _LocalPort));
             _Socket.Bind(new IPEndPoint(ip, _LocalPort));
-            if (_LocalPort == 0)
-                _LocalPort = (_Socket.LocalEndPoint as IPEndPoint).Port;
         }
         }
 
 
         #endregion
         #endregion

+ 2 - 1
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -100,7 +100,8 @@ namespace Emby.Server.Implementations.HttpServer
                 responseHeaders = new Dictionary<string, string>();
                 responseHeaders = new Dictionary<string, string>();
             }
             }
 
 
-            if (addCachePrevention)
+            string expires;
+            if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out expires))
             {
             {
                 responseHeaders["Expires"] = "-1";
                 responseHeaders["Expires"] = "-1";
             }
             }

+ 48 - 2
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -645,6 +645,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             existingTimer.SeasonNumber = updatedTimer.SeasonNumber;
             existingTimer.SeasonNumber = updatedTimer.SeasonNumber;
             existingTimer.ShortOverview = updatedTimer.ShortOverview;
             existingTimer.ShortOverview = updatedTimer.ShortOverview;
             existingTimer.StartDate = updatedTimer.StartDate;
             existingTimer.StartDate = updatedTimer.StartDate;
+            existingTimer.ShowId = updatedTimer.ShowId;
         }
         }
 
 
         public Task<ImageStream> GetChannelImageAsync(string channelId, CancellationToken cancellationToken)
         public Task<ImageStream> GetChannelImageAsync(string channelId, CancellationToken cancellationToken)
@@ -1836,6 +1837,39 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             return seriesTimer.SkipEpisodesInLibrary && IsProgramAlreadyInLibrary(timer);
             return seriesTimer.SkipEpisodesInLibrary && IsProgramAlreadyInLibrary(timer);
         }
         }
 
 
+        private void HandleDuplicateShowIds(List<TimerInfo> timers)
+        {
+            foreach (var timer in timers.Skip(1))
+            {
+                // TODO: Get smarter, prefer HD, etc
+
+                timer.Status = RecordingStatus.Cancelled;
+                _timerProvider.Update(timer);
+            }
+        }
+
+        private void SearchForDuplicateShowIds(List<TimerInfo> timers)
+        {
+            var groups = timers.ToLookup(i => i.ShowId ?? string.Empty).ToList();
+
+            foreach (var group in groups)
+            {
+                if (string.IsNullOrWhiteSpace(group.Key))
+                {
+                    continue;
+                }
+
+                var groupTimers = group.ToList();
+
+                if (groupTimers.Count < 2)
+                {
+                    continue;
+                }
+
+                HandleDuplicateShowIds(groupTimers);
+            }
+        }
+
         private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
         private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
         {
         {
             var allTimers = GetTimersForSeries(seriesTimer, epgData)
             var allTimers = GetTimersForSeries(seriesTimer, epgData)
@@ -1843,6 +1877,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 
 
             var registration = await _liveTvManager.GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
             var registration = await _liveTvManager.GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
 
 
+            var enabledTimersForSeries = new List<TimerInfo>();
+
             if (registration.IsValid)
             if (registration.IsValid)
             {
             {
                 foreach (var timer in allTimers)
                 foreach (var timer in allTimers)
@@ -1855,6 +1891,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                         {
                         {
                             timer.Status = RecordingStatus.Cancelled;
                             timer.Status = RecordingStatus.Cancelled;
                         }
                         }
+                        else
+                        {
+                            enabledTimersForSeries.Add(timer);
+                        }
                         _timerProvider.Add(timer);
                         _timerProvider.Add(timer);
                     }
                     }
                     else
                     else
@@ -1870,6 +1910,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                                 existingTimer.Status = RecordingStatus.Cancelled;
                                 existingTimer.Status = RecordingStatus.Cancelled;
                             }
                             }
 
 
+                            if (existingTimer.Status != RecordingStatus.Cancelled)
+                            {
+                                enabledTimersForSeries.Add(existingTimer);
+                            }
+
                             existingTimer.SeriesTimerId = seriesTimer.Id;
                             existingTimer.SeriesTimerId = seriesTimer.Id;
                             _timerProvider.Update(existingTimer);
                             _timerProvider.Update(existingTimer);
                         }
                         }
@@ -1877,6 +1922,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                 }
                 }
             }
             }
 
 
+            SearchForDuplicateShowIds(enabledTimersForSeries);
+
             if (deleteInvalidTimers)
             if (deleteInvalidTimers)
             {
             {
                 var allTimerIds = allTimers
                 var allTimerIds = allTimers
@@ -1901,8 +1948,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             }
             }
         }
         }
 
 
-        private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer,
-            IEnumerable<ProgramInfo> allPrograms)
+        private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms)
         {
         {
             if (seriesTimer == null)
             if (seriesTimer == null)
             {
             {

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

@@ -31,6 +31,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             timer.Name = parent.Name;
             timer.Name = parent.Name;
             timer.Overview = parent.Overview;
             timer.Overview = parent.Overview;
             timer.SeriesTimerId = seriesTimer.Id;
             timer.SeriesTimerId = seriesTimer.Id;
+            timer.ShowId = parent.ShowId;
 
 
             CopyProgramInfoToTimerInfo(parent, timer);
             CopyProgramInfoToTimerInfo(parent, timer);
 
 

+ 5 - 2
Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

@@ -124,12 +124,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 
 
         private ProgramInfo GetProgramInfo(XmlTvProgram p, ListingsProviderInfo info)
         private ProgramInfo GetProgramInfo(XmlTvProgram p, ListingsProviderInfo info)
         {
         {
+            var episodeTitle = p.Episode == null ? null : p.Episode.Title;
+
             var programInfo = new ProgramInfo
             var programInfo = new ProgramInfo
             {
             {
                 ChannelId = p.ChannelId,
                 ChannelId = p.ChannelId,
                 EndDate = GetDate(p.EndDate),
                 EndDate = GetDate(p.EndDate),
                 EpisodeNumber = p.Episode == null ? null : p.Episode.Episode,
                 EpisodeNumber = p.Episode == null ? null : p.Episode.Episode,
-                EpisodeTitle = p.Episode == null ? null : p.Episode.Title,
+                EpisodeTitle = episodeTitle,
                 Genres = p.Categories,
                 Genres = p.Categories,
                 Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date,
                 Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date,
                 StartDate = GetDate(p.StartDate),
                 StartDate = GetDate(p.StartDate),
@@ -149,7 +151,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
                 HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
                 OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
                 OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
                 CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null,
                 CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null,
-                SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null
+                SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null,
+                ShowId = ((p.Title ?? string.Empty) + (episodeTitle ?? string.Empty)).GetMD5().ToString("N")
             };
             };
 
 
             if (programInfo.IsMovie)
             if (programInfo.IsMovie)

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

@@ -34,6 +34,8 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The program identifier.</value>
         /// <value>The program identifier.</value>
         public string ProgramId { get; set; }
         public string ProgramId { get; set; }
 
 
+        public string ShowId { get; set; }
+
         /// <summary>
         /// <summary>
         /// Name of the recording.
         /// Name of the recording.
         /// </summary>
         /// </summary>

+ 0 - 2
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -154,7 +154,6 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
         public bool EnableDashboardResponseCaching { get; set; }
         public bool EnableDashboardResponseCaching { get; set; }
-        public bool EnableDashboardResourceMinification { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Allows the dashboard to be served from a custom path.
         /// Allows the dashboard to be served from a custom path.
@@ -230,7 +229,6 @@ namespace MediaBrowser.Model.Configuration
             HttpsPortNumber = DefaultHttpsPort;
             HttpsPortNumber = DefaultHttpsPort;
             EnableHttps = false;
             EnableHttps = false;
             EnableDashboardResponseCaching = true;
             EnableDashboardResponseCaching = true;
-            EnableDashboardResourceMinification = true;
             EnableAnonymousUsageReporting = true;
             EnableAnonymousUsageReporting = true;
 
 
             EnableAutomaticRestart = true;
             EnableAutomaticRestart = true;

+ 2 - 0
MediaBrowser.Model/Querying/ItemFields.cs

@@ -45,6 +45,8 @@
         /// </summary>
         /// </summary>
         Chapters,
         Chapters,
 
 
+        ChildCount,
+
         /// <summary>
         /// <summary>
         /// The critic rating summary
         /// The critic rating summary
         /// </summary>
         /// </summary>

+ 8 - 8
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -113,6 +113,7 @@ namespace MediaBrowser.WebDashboard.Api
         private readonly ILocalizationManager _localization;
         private readonly ILocalizationManager _localization;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IAssemblyInfo _assemblyInfo;
         private readonly IAssemblyInfo _assemblyInfo;
+        private readonly IMemoryStreamFactory _memoryStreamFactory;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardService" /> class.
         /// Initializes a new instance of the <see cref="DashboardService" /> class.
@@ -120,7 +121,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// <param name="appHost">The app host.</param>
         /// <param name="appHost">The app host.</param>
         /// <param name="serverConfigurationManager">The server configuration manager.</param>
         /// <param name="serverConfigurationManager">The server configuration manager.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <param name="fileSystem">The file system.</param>
-        public DashboardService(IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, IAssemblyInfo assemblyInfo, ILogger logger, IHttpResultFactory resultFactory)
+        public DashboardService(IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, IAssemblyInfo assemblyInfo, ILogger logger, IHttpResultFactory resultFactory, IMemoryStreamFactory memoryStreamFactory)
         {
         {
             _appHost = appHost;
             _appHost = appHost;
             _serverConfigurationManager = serverConfigurationManager;
             _serverConfigurationManager = serverConfigurationManager;
@@ -130,6 +131,7 @@ namespace MediaBrowser.WebDashboard.Api
             _assemblyInfo = assemblyInfo;
             _assemblyInfo = assemblyInfo;
             _logger = logger;
             _logger = logger;
             _resultFactory = resultFactory;
             _resultFactory = resultFactory;
+            _memoryStreamFactory = memoryStreamFactory;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -161,7 +163,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             if (plugin != null && stream != null)
             if (plugin != null && stream != null)
             {
             {
-                return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion.ToString(), null, false));
+                return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion.ToString(), null));
             }
             }
 
 
             throw new ResourceNotFoundException();
             throw new ResourceNotFoundException();
@@ -294,7 +296,7 @@ namespace MediaBrowser.WebDashboard.Api
                 cacheDuration = TimeSpan.FromDays(365);
                 cacheDuration = TimeSpan.FromDays(365);
             }
             }
 
 
-            var cacheKey = (_appHost.ApplicationVersion.ToString() + (localizationCulture ?? string.Empty) + path).GetMD5();
+            var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5();
 
 
             return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture)).ConfigureAwait(false);
             return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture)).ConfigureAwait(false);
         }
         }
@@ -312,15 +314,13 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
         private Task<Stream> GetResourceStream(string path, string localizationCulture)
         private Task<Stream> GetResourceStream(string path, string localizationCulture)
         {
         {
-            var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
-
             return GetPackageCreator()
             return GetPackageCreator()
-                .GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
+                .GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString());
         }
         }
 
 
         private PackageCreator GetPackageCreator()
         private PackageCreator GetPackageCreator()
         {
         {
-            return new PackageCreator(_fileSystem, _localization, _logger, _serverConfigurationManager, _jsonSerializer);
+            return new PackageCreator(_fileSystem, _logger, _serverConfigurationManager, _memoryStreamFactory);
         }
         }
 
 
         private List<string> GetDeployIgnoreExtensions()
         private List<string> GetDeployIgnoreExtensions()
@@ -507,7 +507,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
         private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
         private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
         {
         {
-            using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, false).ConfigureAwait(false))
+            using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion).ConfigureAwait(false))
             {
             {
                 using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
                 using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
                 {
                 {

+ 11 - 21
MediaBrowser.WebDashboard/Api/PackageCreator.cs

@@ -16,32 +16,28 @@ namespace MediaBrowser.WebDashboard.Api
     public class PackageCreator
     public class PackageCreator
     {
     {
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
-        private readonly ILocalizationManager _localization;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
-        private readonly IJsonSerializer _jsonSerializer;
+        private readonly IMemoryStreamFactory _memoryStreamFactory;
 
 
-        public PackageCreator(IFileSystem fileSystem, ILocalizationManager localization, ILogger logger, IServerConfigurationManager config, IJsonSerializer jsonSerializer)
+        public PackageCreator(IFileSystem fileSystem, ILogger logger, IServerConfigurationManager config, IMemoryStreamFactory memoryStreamFactory)
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
-            _localization = localization;
             _logger = logger;
             _logger = logger;
             _config = config;
             _config = config;
-            _jsonSerializer = jsonSerializer;
+            _memoryStreamFactory = memoryStreamFactory;
         }
         }
 
 
         public async Task<Stream> GetResource(string path,
         public async Task<Stream> GetResource(string path,
             string mode,
             string mode,
             string localizationCulture,
             string localizationCulture,
-            string appVersion,
-            bool enableMinification)
+            string appVersion)
         {
         {
             Stream resourceStream;
             Stream resourceStream;
 
 
             if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
             if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
             {
             {
-                resourceStream = await GetAllCss(enableMinification).ConfigureAwait(false);
-                enableMinification = false;
+                resourceStream = await GetAllCss().ConfigureAwait(false);
             }
             }
             else
             else
             {
             {
@@ -56,7 +52,7 @@ namespace MediaBrowser.WebDashboard.Api
                 {
                 {
                     if (IsCoreHtml(path))
                     if (IsCoreHtml(path))
                     {
                     {
-                        resourceStream = await ModifyHtml(path, resourceStream, mode, appVersion, localizationCulture, enableMinification).ConfigureAwait(false);
+                        resourceStream = await ModifyHtml(path, resourceStream, mode, appVersion, localizationCulture).ConfigureAwait(false);
                     }
                     }
                 }
                 }
             }
             }
@@ -140,20 +136,14 @@ namespace MediaBrowser.WebDashboard.Api
         /// <summary>
         /// <summary>
         /// Modifies the HTML by adding common meta tags, css and js.
         /// Modifies the HTML by adding common meta tags, css and js.
         /// </summary>
         /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="sourceStream">The source stream.</param>
-        /// <param name="mode">The mode.</param>
-        /// <param name="appVersion">The application version.</param>
-        /// <param name="localizationCulture">The localization culture.</param>
-        /// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
-        public async Task<Stream> ModifyHtml(string path, Stream sourceStream, string mode, string appVersion, string localizationCulture, bool enableMinification)
+        public async Task<Stream> ModifyHtml(string path, Stream sourceStream, string mode, string appVersion, string localizationCulture)
         {
         {
             using (sourceStream)
             using (sourceStream)
             {
             {
                 string html;
                 string html;
 
 
-                using (var memoryStream = new MemoryStream())
+                using (var memoryStream = _memoryStreamFactory.CreateNew())
                 {
                 {
                     await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
                     await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
 
 
@@ -202,7 +192,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
                 var bytes = Encoding.UTF8.GetBytes(html);
                 var bytes = Encoding.UTF8.GetBytes(html);
 
 
-                return new MemoryStream(bytes);
+                return _memoryStreamFactory.CreateNew(bytes);
             }
             }
         }
         }
 
 
@@ -332,9 +322,9 @@ namespace MediaBrowser.WebDashboard.Api
         /// Gets all CSS.
         /// Gets all CSS.
         /// </summary>
         /// </summary>
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
-        private async Task<Stream> GetAllCss(bool enableMinification)
+        private async Task<Stream> GetAllCss()
         {
         {
-            var memoryStream = new MemoryStream();
+            var memoryStream = _memoryStreamFactory.CreateNew();
 
 
             var files = new[]
             var files = new[]
                                   {
                                   {