filter duplicate recordings based on showId

This commit is contained in:
Luke Pulverenti 2016-11-24 11:29:23 -05:00
parent 8bc4d49c89
commit 9606a2a710
10 changed files with 79 additions and 38 deletions

View File

@ -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

View File

@ -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";
} }

View File

@ -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, private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms)
IEnumerable<ProgramInfo> allPrograms)
{ {
if (seriesTimer == null) if (seriesTimer == null)
{ {

View File

@ -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);

View File

@ -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)

View File

@ -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>

View File

@ -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;

View File

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

View File

@ -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))
{ {

View File

@ -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, string appVersion)
bool enableMinification)
{ {
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); resourceStream = await GetAllCss().ConfigureAwait(false);
enableMinification = 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[]
{ {