mirror of
https://github.com/Sonarr/Sonarr
synced 2025-02-25 07:23:16 +00:00
Wanted is much much faster now.
This commit is contained in:
parent
79767aa7bf
commit
20dec3c205
6 changed files with 117 additions and 58 deletions
|
@ -3,19 +3,18 @@ using NzbDrone.Api.Episodes;
|
|||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.Wanted
|
||||
{
|
||||
public class CutoffModule : NzbDroneRestModule<EpisodeResource>
|
||||
{
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IEpisodeCutoffService _episodeCutoffService;
|
||||
private readonly SeriesRepository _seriesRepository;
|
||||
|
||||
public CutoffModule(IEpisodeService episodeService, SeriesRepository seriesRepository)
|
||||
public CutoffModule(IEpisodeCutoffService episodeCutoffService, SeriesRepository seriesRepository)
|
||||
:base("wanted/cutoff")
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
_episodeCutoffService = episodeCutoffService;
|
||||
_seriesRepository = seriesRepository;
|
||||
GetResourcePaged = GetCutoffUnmetEpisodes;
|
||||
}
|
||||
|
@ -39,7 +38,7 @@ namespace NzbDrone.Api.Wanted
|
|||
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();
|
||||
|
||||
|
|
|
@ -512,6 +512,7 @@
|
|||
<Compile Include="Parser\Parser.cs" />
|
||||
<Compile Include="Parser\ParsingService.cs" />
|
||||
<Compile Include="Parser\QualityParser.cs" />
|
||||
<Compile Include="Qualities\QualitiesBelowCutoff.cs" />
|
||||
<Compile Include="Qualities\QualityModelComparer.cs" />
|
||||
<Compile Include="Qualities\QualityProfileItem.cs" />
|
||||
<Compile Include="Rest\JsonNetSerializer.cs" />
|
||||
|
@ -536,6 +537,7 @@
|
|||
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
||||
<Compile Include="ThingiProvider\ProviderFactory.cs" />
|
||||
<Compile Include="Tv\Actor.cs" />
|
||||
<Compile Include="Tv\EpisodeCutoffService.cs" />
|
||||
<Compile Include="Tv\EpisodeService.cs" />
|
||||
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
||||
|
|
17
src/NzbDrone.Core/Qualities/QualitiesBelowCutoff.cs
Normal file
17
src/NzbDrone.Core/Qualities/QualitiesBelowCutoff.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
47
src/NzbDrone.Core/Tv/EpisodeCutoffService.cs
Normal file
47
src/NzbDrone.Core/Tv/EpisodeCutoffService.cs
Normal file
|
@ -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.Messaging.Events;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
|
@ -18,7 +19,7 @@ namespace NzbDrone.Core.Tv
|
|||
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
|
||||
List<Episode> GetEpisodeByFileId(int fileId);
|
||||
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);
|
||||
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate);
|
||||
void SetMonitoredFlat(Episode episode, bool monitored);
|
||||
|
@ -98,7 +99,7 @@ namespace NzbDrone.Core.Tv
|
|||
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 startingSeasonNumber = 1;
|
||||
|
@ -108,29 +109,10 @@ namespace NzbDrone.Core.Tv
|
|||
startingSeasonNumber = 0;
|
||||
}
|
||||
|
||||
var query = 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)
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection());
|
||||
pagingSpec.TotalRecords = EpisodesWhereCutoffUnmetQuery(pagingSpec, currentTime, qualitiesBelowCutoff, startingSeasonNumber).GetRowCount();
|
||||
pagingSpec.Records = EpisodesWhereCutoffUnmetQuery(pagingSpec, currentTime, qualitiesBelowCutoff, startingSeasonNumber).ToList();
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
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;
|
||||
return pagingSpec;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
|
||||
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec);
|
||||
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
||||
void UpdateEpisode(Episode episode);
|
||||
void SetEpisodeMonitored(int episodeId, bool monitored);
|
||||
|
@ -114,34 +113,6 @@ namespace NzbDrone.Core.Tv
|
|||
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)
|
||||
{
|
||||
return _episodeRepository.GetEpisodeByFileId(episodeFileId);
|
||||
|
|
Loading…
Reference in a new issue