diff --git a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs index 7a87ff338..98af26a4a 100644 --- a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs +++ b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Tv; +using NzbDrone.Core.DecisionEngine; namespace NzbDrone.Api.EpisodeFiles { @@ -20,18 +21,21 @@ namespace NzbDrone.Api.EpisodeFiles private readonly IMediaFileService _mediaFileService; private readonly IRecycleBinProvider _recycleBinProvider; private readonly ISeriesService _seriesService; + private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification; private readonly Logger _logger; public EpisodeModule(ICommandExecutor commandExecutor, IMediaFileService mediaFileService, IRecycleBinProvider recycleBinProvider, ISeriesService seriesService, + IQualityUpgradableSpecification qualityUpgradableSpecification, Logger logger) : base(commandExecutor) { _mediaFileService = mediaFileService; _recycleBinProvider = recycleBinProvider; _seriesService = seriesService; + _qualityUpgradableSpecification = qualityUpgradableSpecification; _logger = logger; GetResourceById = GetEpisodeFile; GetResourceAll = GetEpisodeFiles; @@ -80,11 +84,13 @@ namespace NzbDrone.Api.EpisodeFiles _mediaFileService.Delete(episodeFile); } - private static EpisodeFileResource MapToResource(Core.Tv.Series series, EpisodeFile episodeFile) + private EpisodeFileResource MapToResource(Core.Tv.Series series, EpisodeFile episodeFile) { var resource = episodeFile.InjectTo(); resource.Path = Path.Combine(series.Path, episodeFile.RelativePath); + resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(series.Profile.Value, episodeFile.Quality); + return resource; } diff --git a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileResource.cs b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileResource.cs index 696e367eb..594f4f5b1 100644 --- a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileResource.cs +++ b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileResource.cs @@ -14,5 +14,7 @@ namespace NzbDrone.Api.EpisodeFiles public DateTime DateAdded { get; set; } public String SceneName { get; set; } public QualityModel Quality { get; set; } + + public Boolean QualityCutoffNotMet { get; set; } } } diff --git a/src/NzbDrone.Api/Episodes/EpisodeModule.cs b/src/NzbDrone.Api/Episodes/EpisodeModule.cs index 96ddf161a..3dbb16064 100644 --- a/src/NzbDrone.Api/Episodes/EpisodeModule.cs +++ b/src/NzbDrone.Api/Episodes/EpisodeModule.cs @@ -2,17 +2,23 @@ using NzbDrone.Api.REST; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Tv; +using NzbDrone.Api.Mapping; +using NzbDrone.Core.DecisionEngine; namespace NzbDrone.Api.Episodes { - public class EpisodeModule : EpisodeModuleWithSignalR + public class EpisodeModule : EpisodeModuleWithSignalR { + private readonly ISeriesService _seriesService; private readonly IEpisodeService _episodeService; + private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification; - public EpisodeModule(ICommandExecutor commandExecutor, IEpisodeService episodeService) + public EpisodeModule(ICommandExecutor commandExecutor, ISeriesService seriesService, IEpisodeService episodeService, IQualityUpgradableSpecification qualityUpgradableSpecification) : base(episodeService, commandExecutor) { + _seriesService = seriesService; _episodeService = episodeService; + _qualityUpgradableSpecification = qualityUpgradableSpecification; GetResourceAll = GetEpisodes; UpdateResource = SetMonitored; @@ -27,7 +33,21 @@ namespace NzbDrone.Api.Episodes throw new BadRequestException("seriesId is missing"); } - return ToListResource(() => _episodeService.GetEpisodeBySeries(seriesId.Value)); + var series = _seriesService.GetSeries(seriesId.Value); + + var resources = new List(); + foreach (var episode in _episodeService.GetEpisodeBySeries(seriesId.Value)) + { + var resource = episode.InjectTo(); + if (episode.EpisodeFile.IsLoaded) + { + resource.EpisodeFile.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(series.Profile.Value, episode.EpisodeFile.Value.Quality); + } + + resources.Add(resource); + } + + return resources; } private void SetMonitored(EpisodeResource episodeResource) diff --git a/src/NzbDrone.Api/Episodes/EpisodeModuleWithSignalR.cs b/src/NzbDrone.Api/Episodes/EpisodeModuleWithSignalR.cs index e25d1bd6b..a1ba8b57f 100644 --- a/src/NzbDrone.Api/Episodes/EpisodeModuleWithSignalR.cs +++ b/src/NzbDrone.Api/Episodes/EpisodeModuleWithSignalR.cs @@ -9,7 +9,7 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Api.Episodes { public abstract class EpisodeModuleWithSignalR : NzbDroneRestModuleWithSignalR, - IHandle, + IHandle, IHandle { private readonly IEpisodeService _episodeService; diff --git a/src/NzbDrone.Api/Episodes/EpisodeResource.cs b/src/NzbDrone.Api/Episodes/EpisodeResource.cs index b3a7d1058..50d274143 100644 --- a/src/NzbDrone.Api/Episodes/EpisodeResource.cs +++ b/src/NzbDrone.Api/Episodes/EpisodeResource.cs @@ -1,5 +1,6 @@ using System; using Newtonsoft.Json; +using NzbDrone.Api.EpisodeFiles; using NzbDrone.Api.REST; using NzbDrone.Core.MediaFiles; @@ -15,7 +16,7 @@ namespace NzbDrone.Api.Episodes public String AirDate { get; set; } public DateTime? AirDateUtc { get; set; } public String Overview { get; set; } - public EpisodeFile EpisodeFile { get; set; } + public EpisodeFileResource EpisodeFile { get; set; } public Boolean HasFile { get; set; } public Boolean Monitored { get; set; } diff --git a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs index bd8d56fdf..f2946c59e 100644 --- a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs @@ -164,6 +164,7 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("[Kaylith] Isshuukan Friends Specials - 01 [BD 720p AAC][B7EEE164].mkv", false)] [TestCase("WEEDS.S03E01-06.DUAL.Blu-ray.AC3.-HELLYWOOD.avi", false)] [TestCase("WEEDS.S03E01-06.DUAL.720p.Blu-ray.AC3.-HELLYWOOD.avi", false)] + [TestCase("[Elysium]Lucky.Star.01(BD.720p.AAC.DA)[0BB96AD8].mkv", false)] public void should_parse_bluray720p_quality(string title, bool proper) { ParseAndVerifyQuality(title, Quality.Bluray720p, proper); diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs index 83c5debac..ed019d72e 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs @@ -4,6 +4,7 @@ using MediaInfoLib; using NLog; using NzbDrone.Common; using NzbDrone.Common.Disk; +using System.Globalization; namespace NzbDrone.Core.MediaFiles.MediaInfo { @@ -59,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "Width"), out width); Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "Height"), out height); Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate); - Decimal.TryParse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"), out videoFrameRate); + Decimal.TryParse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out videoFrameRate); //Runtime Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out videoRuntime); diff --git a/src/NzbDrone.Core/Parser/QualityParser.cs b/src/NzbDrone.Core/Parser/QualityParser.cs index 36fa12447..7222e625e 100644 --- a/src/NzbDrone.Core/Parser/QualityParser.cs +++ b/src/NzbDrone.Core/Parser/QualityParser.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Parser private static readonly Regex OtherSourceRegex = new Regex(@"(?HD[-_. ]TV)|(?SD[-_. ]TV)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex AnimeBlurayRegex = new Regex(@"bd(?:720|1080)|(?<=\[|\(|\s)bd(?=\s|\)|\])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex AnimeBlurayRegex = new Regex(@"bd(?:720|1080)|(?<=[-_. (\[])bd(?=[-_. )\]])", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex HighDefPdtvRegex = new Regex(@"hr[-_. ]ws", RegexOptions.Compiled | RegexOptions.IgnoreCase); diff --git a/src/UI/Cells/EpisodeStatusCell.js b/src/UI/Cells/EpisodeStatusCell.js index 494be0195..84272bfc1 100644 --- a/src/UI/Cells/EpisodeStatusCell.js +++ b/src/UI/Cells/EpisodeStatusCell.js @@ -52,7 +52,13 @@ define( title += ' - {0}'.format(size); } - this.$el.html('{1}'.format(title, quality.quality.name)); + if (this.episodeFile.get('qualityCutoffNotMet')) { + this.$el.html('{1}'.format(title, quality.quality.name)); + } + else { + this.$el.html('{1}'.format(title, quality.quality.name)); + } + return; } diff --git a/src/UI/Cells/cells.less b/src/UI/Cells/cells.less index e4517edf5..0f915fc94 100644 --- a/src/UI/Cells/cells.less +++ b/src/UI/Cells/cells.less @@ -86,6 +86,12 @@ td.episode-status-cell, td.quality-cell { font-size: 9px; } + .badge-inverse { + background-color: #eee; + border: 1px solid @badge-bg; + color: @badge-bg; + } + .progress { height : 10px; margin-top : 5px;