Wanted is much much faster now.
This commit is contained in:
parent
79767aa7bf
commit
20dec3c205
|
@ -3,19 +3,18 @@ using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
|
|
||||||
namespace NzbDrone.Api.Wanted
|
namespace NzbDrone.Api.Wanted
|
||||||
{
|
{
|
||||||
public class CutoffModule : NzbDroneRestModule<EpisodeResource>
|
public class CutoffModule : NzbDroneRestModule<EpisodeResource>
|
||||||
{
|
{
|
||||||
private readonly IEpisodeService _episodeService;
|
private readonly IEpisodeCutoffService _episodeCutoffService;
|
||||||
private readonly SeriesRepository _seriesRepository;
|
private readonly SeriesRepository _seriesRepository;
|
||||||
|
|
||||||
public CutoffModule(IEpisodeService episodeService, SeriesRepository seriesRepository)
|
public CutoffModule(IEpisodeCutoffService episodeCutoffService, SeriesRepository seriesRepository)
|
||||||
:base("wanted/cutoff")
|
:base("wanted/cutoff")
|
||||||
{
|
{
|
||||||
_episodeService = episodeService;
|
_episodeCutoffService = episodeCutoffService;
|
||||||
_seriesRepository = seriesRepository;
|
_seriesRepository = seriesRepository;
|
||||||
GetResourcePaged = GetCutoffUnmetEpisodes;
|
GetResourcePaged = GetCutoffUnmetEpisodes;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +38,7 @@ namespace NzbDrone.Api.Wanted
|
||||||
pagingSpec.FilterExpression = v => v.Monitored == true && v.Series.Monitored == true;
|
pagingSpec.FilterExpression = v => v.Monitored == true && v.Series.Monitored == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PagingResource<EpisodeResource> resource = ApplyToPage(_episodeService.EpisodesWhereCutoffUnmet, pagingSpec);
|
PagingResource<EpisodeResource> resource = ApplyToPage(_episodeCutoffService.EpisodesWhereCutoffUnmet, pagingSpec);
|
||||||
|
|
||||||
resource.Records = resource.Records.LoadSubtype(e => e.SeriesId, _seriesRepository).ToList();
|
resource.Records = resource.Records.LoadSubtype(e => e.SeriesId, _seriesRepository).ToList();
|
||||||
|
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<Compile Include="Parser\Parser.cs" />
|
<Compile Include="Parser\Parser.cs" />
|
||||||
<Compile Include="Parser\ParsingService.cs" />
|
<Compile Include="Parser\ParsingService.cs" />
|
||||||
<Compile Include="Parser\QualityParser.cs" />
|
<Compile Include="Parser\QualityParser.cs" />
|
||||||
|
<Compile Include="Qualities\QualitiesBelowCutoff.cs" />
|
||||||
<Compile Include="Qualities\QualityModelComparer.cs" />
|
<Compile Include="Qualities\QualityModelComparer.cs" />
|
||||||
<Compile Include="Qualities\QualityProfileItem.cs" />
|
<Compile Include="Qualities\QualityProfileItem.cs" />
|
||||||
<Compile Include="Rest\JsonNetSerializer.cs" />
|
<Compile Include="Rest\JsonNetSerializer.cs" />
|
||||||
|
@ -536,6 +537,7 @@
|
||||||
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
||||||
<Compile Include="ThingiProvider\ProviderFactory.cs" />
|
<Compile Include="ThingiProvider\ProviderFactory.cs" />
|
||||||
<Compile Include="Tv\Actor.cs" />
|
<Compile Include="Tv\Actor.cs" />
|
||||||
|
<Compile Include="Tv\EpisodeCutoffService.cs" />
|
||||||
<Compile Include="Tv\EpisodeService.cs" />
|
<Compile Include="Tv\EpisodeService.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Qualities
|
||||||
|
{
|
||||||
|
public class QualitiesBelowCutoff
|
||||||
|
{
|
||||||
|
public Int32 ProfileId { get; set; }
|
||||||
|
public IEnumerable<Int32> QualityIds { get; set; }
|
||||||
|
|
||||||
|
public QualitiesBelowCutoff(int profileId, IEnumerable<int> qualityIds)
|
||||||
|
{
|
||||||
|
ProfileId = profileId;
|
||||||
|
QualityIds = qualityIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv
|
||||||
|
{
|
||||||
|
public interface IEpisodeCutoffService
|
||||||
|
{
|
||||||
|
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EpisodeCutoffService : IEpisodeCutoffService
|
||||||
|
{
|
||||||
|
private readonly IEpisodeRepository _episodeRepository;
|
||||||
|
private readonly IQualityProfileService _qualityProfileService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public EpisodeCutoffService(IEpisodeRepository episodeRepository, IQualityProfileService qualityProfileService, Logger logger)
|
||||||
|
{
|
||||||
|
_episodeRepository = episodeRepository;
|
||||||
|
_qualityProfileService = qualityProfileService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec)
|
||||||
|
{
|
||||||
|
var qualitiesBelowCutoff = new List<QualitiesBelowCutoff>();
|
||||||
|
var qualityProfiles = _qualityProfileService.All();
|
||||||
|
|
||||||
|
//Get all items less than the cutoff
|
||||||
|
foreach (var qualityProfile in qualityProfiles)
|
||||||
|
{
|
||||||
|
var cutoffIndex = qualityProfile.Items.FindIndex(v => v.Quality == qualityProfile.Cutoff);
|
||||||
|
var belowCutoff = qualityProfile.Items.Take(cutoffIndex).ToList();
|
||||||
|
|
||||||
|
if (belowCutoff.Any())
|
||||||
|
{
|
||||||
|
qualitiesBelowCutoff.Add(new QualitiesBelowCutoff(qualityProfile.Id, belowCutoff.Select(i => i.Quality.Id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _episodeRepository.EpisodesWhereCutoffUnmet(pagingSpec, qualitiesBelowCutoff, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ using Marr.Data.QGen;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Tv
|
namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
|
@ -18,7 +19,7 @@ namespace NzbDrone.Core.Tv
|
||||||
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
|
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
|
||||||
List<Episode> GetEpisodeByFileId(int fileId);
|
List<Episode> GetEpisodeByFileId(int fileId);
|
||||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
||||||
List<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, bool includeSpecials);
|
||||||
Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
|
Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
|
||||||
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate);
|
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate);
|
||||||
void SetMonitoredFlat(Episode episode, bool monitored);
|
void SetMonitoredFlat(Episode episode, bool monitored);
|
||||||
|
@ -98,7 +99,7 @@ namespace NzbDrone.Core.Tv
|
||||||
return pagingSpec;
|
return pagingSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, bool includeSpecials)
|
||||||
{
|
{
|
||||||
var currentTime = DateTime.UtcNow;
|
var currentTime = DateTime.UtcNow;
|
||||||
var startingSeasonNumber = 1;
|
var startingSeasonNumber = 1;
|
||||||
|
@ -108,29 +109,10 @@ namespace NzbDrone.Core.Tv
|
||||||
startingSeasonNumber = 0;
|
startingSeasonNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var query = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
pagingSpec.TotalRecords = EpisodesWhereCutoffUnmetQuery(pagingSpec, currentTime, qualitiesBelowCutoff, startingSeasonNumber).GetRowCount();
|
||||||
.Join<Episode, EpisodeFile>(JoinType.Left, e => e.EpisodeFile, (e, s) => e.EpisodeFileId == s.Id)
|
pagingSpec.Records = EpisodesWhereCutoffUnmetQuery(pagingSpec, currentTime, qualitiesBelowCutoff, startingSeasonNumber).ToList();
|
||||||
.Where(pagingSpec.FilterExpression)
|
|
||||||
.AndWhere(e => e.EpisodeFileId != 0)
|
|
||||||
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
|
||||||
.AndWhere(e => e.AirDateUtc <= currentTime)
|
|
||||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection());
|
|
||||||
|
|
||||||
return query.ToList();
|
return pagingSpec;
|
||||||
}
|
|
||||||
|
|
||||||
private SortBuilder<Episode> GetMissingEpisodesQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, int startingSeasonNumber)
|
|
||||||
{
|
|
||||||
var query = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
|
||||||
.Where(pagingSpec.FilterExpression)
|
|
||||||
.AndWhere(e => e.EpisodeFileId == 0)
|
|
||||||
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
|
||||||
.AndWhere(e => e.AirDateUtc <= currentTime)
|
|
||||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
|
||||||
.Skip(pagingSpec.PagingOffset())
|
|
||||||
.Take(pagingSpec.PageSize);
|
|
||||||
|
|
||||||
return query;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
|
public Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
|
||||||
|
@ -177,5 +159,46 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId);
|
SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SortBuilder<Episode> GetMissingEpisodesQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, int startingSeasonNumber)
|
||||||
|
{
|
||||||
|
return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||||
|
.Where(pagingSpec.FilterExpression)
|
||||||
|
.AndWhere(e => e.EpisodeFileId == 0)
|
||||||
|
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
||||||
|
.AndWhere(e => e.AirDateUtc <= currentTime)
|
||||||
|
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||||
|
.Skip(pagingSpec.PagingOffset())
|
||||||
|
.Take(pagingSpec.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SortBuilder<Episode> EpisodesWhereCutoffUnmetQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, List<QualitiesBelowCutoff> qualitiesBelowCutoff, int startingSeasonNumber)
|
||||||
|
{
|
||||||
|
return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||||
|
.Join<Episode, EpisodeFile>(JoinType.Left, e => e.EpisodeFile, (e, s) => e.EpisodeFileId == s.Id)
|
||||||
|
.Where(pagingSpec.FilterExpression)
|
||||||
|
.AndWhere(e => e.EpisodeFileId != 0)
|
||||||
|
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
||||||
|
.AndWhere(e => e.AirDateUtc <= currentTime)
|
||||||
|
.AndWhere(BuildQualityCutoffWhereClause(qualitiesBelowCutoff))
|
||||||
|
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||||
|
.Skip(pagingSpec.PagingOffset())
|
||||||
|
.Take(pagingSpec.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildQualityCutoffWhereClause(List<QualitiesBelowCutoff> qualitiesBelowCutoff)
|
||||||
|
{
|
||||||
|
var clauses = new List<String>();
|
||||||
|
|
||||||
|
foreach (var profile in qualitiesBelowCutoff)
|
||||||
|
{
|
||||||
|
foreach (var belowCutoff in profile.QualityIds)
|
||||||
|
{
|
||||||
|
clauses.Add(String.Format("([t1].[QualityProfileId] = {0} AND [t2].[Quality] LIKE '%_quality_:%{1}%')", profile.ProfileId, belowCutoff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.Format("({0})", String.Join(" OR ", clauses));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ namespace NzbDrone.Core.Tv
|
||||||
List<Episode> GetEpisodeBySeries(int seriesId);
|
List<Episode> GetEpisodeBySeries(int seriesId);
|
||||||
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
|
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
|
||||||
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec);
|
|
||||||
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
||||||
void UpdateEpisode(Episode episode);
|
void UpdateEpisode(Episode episode);
|
||||||
void SetEpisodeMonitored(int episodeId, bool monitored);
|
void SetEpisodeMonitored(int episodeId, bool monitored);
|
||||||
|
@ -114,34 +113,6 @@ namespace NzbDrone.Core.Tv
|
||||||
return episodeResult;
|
return episodeResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec)
|
|
||||||
{
|
|
||||||
var allSpec = new PagingSpec<Episode>
|
|
||||||
{
|
|
||||||
SortKey = pagingSpec.SortKey,
|
|
||||||
SortDirection = pagingSpec.SortDirection,
|
|
||||||
FilterExpression = pagingSpec.FilterExpression
|
|
||||||
};
|
|
||||||
|
|
||||||
var allItems = _episodeRepository.EpisodesWhereCutoffUnmet(allSpec, false);
|
|
||||||
|
|
||||||
var qualityProfileComparers = _qualityProfileRepository.All().ToDictionary(v => v.Id, v => new { Profile = v, Comparer = new QualityModelComparer(v) });
|
|
||||||
|
|
||||||
var filtered = allItems.Where(episode =>
|
|
||||||
{
|
|
||||||
var profile = qualityProfileComparers[episode.Series.QualityProfileId];
|
|
||||||
return profile.Comparer.Compare(episode.EpisodeFile.Value.Quality.Quality, profile.Profile.Cutoff) < 0;
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
pagingSpec.Records = filtered
|
|
||||||
.Skip(pagingSpec.PagingOffset())
|
|
||||||
.Take(pagingSpec.PageSize)
|
|
||||||
.ToList();
|
|
||||||
pagingSpec.TotalRecords = filtered.Count;
|
|
||||||
|
|
||||||
return pagingSpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Episode> GetEpisodesByFileId(int episodeFileId)
|
public List<Episode> GetEpisodesByFileId(int episodeFileId)
|
||||||
{
|
{
|
||||||
return _episodeRepository.GetEpisodeByFileId(episodeFileId);
|
return _episodeRepository.GetEpisodeByFileId(episodeFileId);
|
||||||
|
|
Loading…
Reference in New Issue