Implement Release Parsing, Decision Engine, and Downloading (#35)

* Implement Parsing, Decision Engine, and Downloading
pull/38/head
Qstick 7 years ago committed by GitHub
parent 5556989324
commit 1e4d9480e9

@ -18,6 +18,7 @@ namespace NzbDrone.Api.Albums
public bool Monitored { get; set; } public bool Monitored { get; set; }
public string Path { get; set; } public string Path { get; set; }
public int ProfileId { get; set; } public int ProfileId { get; set; }
public int Duration { get; set; }
public Ratings Ratings { get; set; } public Ratings Ratings { get; set; }
public DateTime? ReleaseDate { get; set; } public DateTime? ReleaseDate { get; set; }
public List<string> Genres { get; set; } public List<string> Genres { get; set; }
@ -46,8 +47,7 @@ namespace NzbDrone.Api.Albums
Title = model.Title, Title = model.Title,
Images = model.Images, Images = model.Images,
Ratings = model.Ratings, Ratings = model.Ratings,
//Genres = model.Genres, Duration = model.Duration,
//ArtworkUrl = model.ArtworkUrl
}; };
} }
@ -68,8 +68,6 @@ namespace NzbDrone.Api.Albums
Title = resource.Title, Title = resource.Title,
Images = resource.Images, Images = resource.Images,
Ratings = resource.Ratings, Ratings = resource.Ratings,
//Genres = resource.Genres,
//ArtworkUrl = resource.ArtworkUrl
}; };
} }

@ -1,8 +1,10 @@
using System; using System;
using Nancy; using Nancy;
using NzbDrone.Api.Episodes; using NzbDrone.Api.Episodes;
using NzbDrone.Api.Albums;
using NzbDrone.Api.Extensions; using NzbDrone.Api.Extensions;
using NzbDrone.Api.Series; using NzbDrone.Api.Series;
using NzbDrone.Api.Music;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@ -32,12 +34,12 @@ namespace NzbDrone.Api.History
{ {
var resource = model.ToResource(); var resource = model.ToResource();
resource.Series = model.Series.ToResource(); resource.Artist = model.Artist.ToResource();
resource.Episode = model.Episode.ToResource(); resource.Album = model.Album.ToResource();
if (model.Series != null) if (model.Artist != null)
{ {
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Series.Profile.Value, model.Quality); resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Artist.Profile.Value, model.Quality);
} }
return resource; return resource;
@ -45,7 +47,7 @@ namespace NzbDrone.Api.History
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource) private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
{ {
var episodeId = Request.Query.EpisodeId; var albumId = Request.Query.AlbumId;
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending); var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
@ -55,10 +57,10 @@ namespace NzbDrone.Api.History
pagingSpec.FilterExpression = v => v.EventType == filterValue; pagingSpec.FilterExpression = v => v.EventType == filterValue;
} }
if (episodeId.HasValue) if (albumId.HasValue)
{ {
int i = (int)episodeId; int i = (int)albumId;
pagingSpec.FilterExpression = h => h.EpisodeId == i; pagingSpec.FilterExpression = h => h.AlbumId == i;
} }
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource); return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Api.Episodes; using NzbDrone.Api.Episodes;
using NzbDrone.Api.Albums;
using NzbDrone.Api.REST; using NzbDrone.Api.REST;
using NzbDrone.Api.Series; using NzbDrone.Api.Series;
using NzbDrone.Api.Music;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
@ -11,8 +13,8 @@ namespace NzbDrone.Api.History
{ {
public class HistoryResource : RestResource public class HistoryResource : RestResource
{ {
public int EpisodeId { get; set; } public int ArtistId { get; set; }
public int SeriesId { get; set; } public int AlbumId { get; set; }
public string SourceTitle { get; set; } public string SourceTitle { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public bool QualityCutoffNotMet { get; set; } public bool QualityCutoffNotMet { get; set; }
@ -23,8 +25,8 @@ namespace NzbDrone.Api.History
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
public EpisodeResource Episode { get; set; } public AlbumResource Album { get; set; }
public SeriesResource Series { get; set; } public ArtistResource Artist { get; set; }
} }
public static class HistoryResourceMapper public static class HistoryResourceMapper
@ -37,8 +39,8 @@ namespace NzbDrone.Api.History
{ {
Id = model.Id, Id = model.Id,
EpisodeId = model.EpisodeId, AlbumId = model.AlbumId,
SeriesId = model.SeriesId, ArtistId = model.ArtistId,
SourceTitle = model.SourceTitle, SourceTitle = model.SourceTitle,
Quality = model.Quality, Quality = model.Quality,
//QualityCutoffNotMet //QualityCutoffNotMet

@ -25,7 +25,7 @@ namespace NzbDrone.Api.Indexers
private readonly IDownloadService _downloadService; private readonly IDownloadService _downloadService;
private readonly Logger _logger; private readonly Logger _logger;
private readonly ICached<RemoteEpisode> _remoteEpisodeCache; private readonly ICached<RemoteAlbum> _remoteAlbumCache;
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
ISearchForNzb nzbSearchService, ISearchForNzb nzbSearchService,
@ -48,14 +48,14 @@ namespace NzbDrone.Api.Indexers
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true); PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
PostValidator.RuleFor(s => s.Guid).NotEmpty(); PostValidator.RuleFor(s => s.Guid).NotEmpty();
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes"); _remoteAlbumCache = cacheManager.GetCache<RemoteAlbum>(GetType(), "remoteAlbums");
} }
private Response DownloadRelease(ReleaseResource release) private Response DownloadRelease(ReleaseResource release)
{ {
var remoteEpisode = _remoteEpisodeCache.Find(release.Guid); var remoteAlbum = _remoteAlbumCache.Find(release.Guid);
if (remoteEpisode == null) if (remoteAlbum == null)
{ {
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired."); _logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
@ -64,7 +64,7 @@ namespace NzbDrone.Api.Indexers
try try
{ {
_downloadService.DownloadReport(remoteEpisode); _downloadService.DownloadReport(remoteAlbum);
} }
catch (ReleaseDownloadException ex) catch (ReleaseDownloadException ex)
{ {
@ -113,7 +113,7 @@ namespace NzbDrone.Api.Indexers
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight) protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
{ {
_remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30)); _remoteAlbumCache.Set(decision.RemoteAlbum.Release.Guid, decision.RemoteAlbum, TimeSpan.FromMinutes(30));
return base.MapDecision(decision, initialWeight); return base.MapDecision(decision, initialWeight);
} }
} }

@ -25,9 +25,9 @@ namespace NzbDrone.Api.Indexers
release.ReleaseWeight = initialWeight; release.ReleaseWeight = initialWeight;
if (decision.RemoteEpisode.Series != null) if (decision.RemoteAlbum.Artist != null)
{ {
release.QualityWeight = decision.RemoteEpisode.Series release.QualityWeight = decision.RemoteAlbum.Artist
.Profile.Value .Profile.Value
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100; .Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
} }

@ -25,18 +25,13 @@ namespace NzbDrone.Api.Indexers
public string ReleaseGroup { get; set; } public string ReleaseGroup { get; set; }
public string ReleaseHash { get; set; } public string ReleaseHash { get; set; }
public string Title { get; set; } public string Title { get; set; }
public bool FullSeason { get; set; }
public int SeasonNumber { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public string AirDate { get; set; } public string ReleaseDate { get; set; }
public string SeriesTitle { get; set; } public string ArtistName { get; set; }
public int[] EpisodeNumbers { get; set; } public string AlbumTitle { get; set; }
public int[] AbsoluteEpisodeNumbers { get; set; }
public bool Approved { get; set; } public bool Approved { get; set; }
public bool TemporarilyRejected { get; set; } public bool TemporarilyRejected { get; set; }
public bool Rejected { get; set; } public bool Rejected { get; set; }
public int TvdbId { get; set; }
public int TvRageId { get; set; }
public IEnumerable<string> Rejections { get; set; } public IEnumerable<string> Rejections { get; set; }
public DateTime PublishDate { get; set; } public DateTime PublishDate { get; set; }
public string CommentUrl { get; set; } public string CommentUrl { get; set; }
@ -82,16 +77,16 @@ namespace NzbDrone.Api.Indexers
{ {
public static ReleaseResource ToResource(this DownloadDecision model) public static ReleaseResource ToResource(this DownloadDecision model)
{ {
var releaseInfo = model.RemoteEpisode.Release; var releaseInfo = model.RemoteAlbum.Release;
var parsedEpisodeInfo = model.RemoteEpisode.ParsedEpisodeInfo; var parsedAlbumInfo = model.RemoteAlbum.ParsedAlbumInfo;
var remoteEpisode = model.RemoteEpisode; var remoteAlbum = model.RemoteAlbum;
var torrentInfo = (model.RemoteEpisode.Release as TorrentInfo) ?? new TorrentInfo(); var torrentInfo = (model.RemoteAlbum.Release as TorrentInfo) ?? new TorrentInfo();
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?) // TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
return new ReleaseResource return new ReleaseResource
{ {
Guid = releaseInfo.Guid, Guid = releaseInfo.Guid,
Quality = parsedEpisodeInfo.Quality, Quality = parsedAlbumInfo.Quality,
//QualityWeight //QualityWeight
Age = releaseInfo.Age, Age = releaseInfo.Age,
AgeHours = releaseInfo.AgeHours, AgeHours = releaseInfo.AgeHours,
@ -99,27 +94,22 @@ namespace NzbDrone.Api.Indexers
Size = releaseInfo.Size, Size = releaseInfo.Size,
IndexerId = releaseInfo.IndexerId, IndexerId = releaseInfo.IndexerId,
Indexer = releaseInfo.Indexer, Indexer = releaseInfo.Indexer,
ReleaseGroup = parsedEpisodeInfo.ReleaseGroup, ReleaseGroup = parsedAlbumInfo.ReleaseGroup,
ReleaseHash = parsedEpisodeInfo.ReleaseHash, ReleaseHash = parsedAlbumInfo.ReleaseHash,
Title = releaseInfo.Title, Title = releaseInfo.Title,
FullSeason = parsedEpisodeInfo.FullSeason, Language = parsedAlbumInfo.Language,
SeasonNumber = parsedEpisodeInfo.SeasonNumber, ReleaseDate = parsedAlbumInfo.ReleaseDate,
Language = parsedEpisodeInfo.Language, ArtistName = parsedAlbumInfo.ArtistName,
AirDate = parsedEpisodeInfo.AirDate, AlbumTitle = parsedAlbumInfo.AlbumTitle,
SeriesTitle = parsedEpisodeInfo.SeriesTitle,
EpisodeNumbers = parsedEpisodeInfo.EpisodeNumbers,
AbsoluteEpisodeNumbers = parsedEpisodeInfo.AbsoluteEpisodeNumbers,
Approved = model.Approved, Approved = model.Approved,
TemporarilyRejected = model.TemporarilyRejected, TemporarilyRejected = model.TemporarilyRejected,
Rejected = model.Rejected, Rejected = model.Rejected,
TvdbId = releaseInfo.TvdbId,
TvRageId = releaseInfo.TvRageId,
Rejections = model.Rejections.Select(r => r.Reason).ToList(), Rejections = model.Rejections.Select(r => r.Reason).ToList(),
PublishDate = releaseInfo.PublishDate, PublishDate = releaseInfo.PublishDate,
CommentUrl = releaseInfo.CommentUrl, CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl, DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl, InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = remoteEpisode.DownloadAllowed, DownloadAllowed = remoteAlbum.DownloadAllowed,
//ReleaseWeight //ReleaseWeight
MagnetUrl = torrentInfo.MagnetUrl, MagnetUrl = torrentInfo.MagnetUrl,
@ -127,11 +117,6 @@ namespace NzbDrone.Api.Indexers
Seeders = torrentInfo.Seeders, Seeders = torrentInfo.Seeders,
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null, Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
Protocol = releaseInfo.DownloadProtocol, Protocol = releaseInfo.DownloadProtocol,
IsDaily = parsedEpisodeInfo.IsDaily,
IsAbsoluteNumbering = parsedEpisodeInfo.IsAbsoluteNumbering,
IsPossibleSpecialEpisode = parsedEpisodeInfo.IsPossibleSpecialEpisode,
Special = parsedEpisodeInfo.Special,
}; };
} }
@ -164,8 +149,6 @@ namespace NzbDrone.Api.Indexers
model.IndexerId = resource.IndexerId; model.IndexerId = resource.IndexerId;
model.Indexer = resource.Indexer; model.Indexer = resource.Indexer;
model.DownloadProtocol = resource.DownloadProtocol; model.DownloadProtocol = resource.DownloadProtocol;
model.TvdbId = resource.TvdbId;
model.TvRageId = resource.TvRageId;
model.PublishDate = resource.PublishDate; model.PublishDate = resource.PublishDate;
return model; return model;

@ -53,6 +53,7 @@ namespace NzbDrone.Api.Music
//public string Certification { get; set; } //public string Certification { get; set; }
public List<string> Genres { get; set; } public List<string> Genres { get; set; }
public string CleanName { get; set; } public string CleanName { get; set; }
public string SortName { get; set; }
public HashSet<int> Tags { get; set; } public HashSet<int> Tags { get; set; }
public DateTime Added { get; set; } public DateTime Added { get; set; }
public AddArtistOptions AddOptions { get; set; } public AddArtistOptions AddOptions { get; set; }
@ -75,8 +76,9 @@ namespace NzbDrone.Api.Music
AllMusicId = model.AMId, AllMusicId = model.AMId,
Name = model.Name, Name = model.Name,
CleanName = model.CleanName, CleanName = model.CleanName,
//AlternateTitles //AlternateTitles
//SortTitle = resource.SortTitle, SortName = model.SortName,
//TotalTrackCount //TotalTrackCount
//TrackCount //TrackCount
@ -130,7 +132,7 @@ namespace NzbDrone.Api.Music
Name = resource.Name, Name = resource.Name,
CleanName = resource.CleanName, CleanName = resource.CleanName,
//AlternateTitles //AlternateTitles
//SortTitle = resource.SortTitle, SortName = resource.SortName,
MBId = resource.MBId, MBId = resource.MBId,
TADBId = resource.TADBId, TADBId = resource.TADBId,
DiscogsId = resource.DiscogsId, DiscogsId = resource.DiscogsId,

@ -1,5 +1,5 @@
using NzbDrone.Api.Episodes; using NzbDrone.Api.Albums;
using NzbDrone.Api.Series; using NzbDrone.Api.Music;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Parse namespace NzbDrone.Api.Parse
@ -18,23 +18,23 @@ namespace NzbDrone.Api.Parse
private ParseResource Parse() private ParseResource Parse()
{ {
var title = Request.Query.Title.Value as string; var title = Request.Query.Title.Value as string;
var parsedEpisodeInfo = Parser.ParseTitle(title); var parsedAlbumInfo = Parser.ParseAlbumTitle(title);
if (parsedEpisodeInfo == null) if (parsedAlbumInfo == null)
{ {
return null; return null;
} }
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); var remoteAlbum = _parsingService.Map(parsedAlbumInfo);
if (remoteEpisode != null) if (remoteAlbum != null)
{ {
return new ParseResource return new ParseResource
{ {
Title = title, Title = title,
ParsedEpisodeInfo = remoteEpisode.ParsedEpisodeInfo, ParsedAlbumInfo = remoteAlbum.ParsedAlbumInfo,
Series = remoteEpisode.Series.ToResource(), Artist = remoteAlbum.Artist.ToResource(),
Episodes = remoteEpisode.Episodes.ToResource() Albums = remoteAlbum.Albums.ToResource()
}; };
} }
else else
@ -42,7 +42,7 @@ namespace NzbDrone.Api.Parse
return new ParseResource return new ParseResource
{ {
Title = title, Title = title,
ParsedEpisodeInfo = parsedEpisodeInfo ParsedAlbumInfo = parsedAlbumInfo
}; };
} }
} }

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.REST; using NzbDrone.Api.REST;
using NzbDrone.Api.Series; using NzbDrone.Api.Music;
using NzbDrone.Api.Albums;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Api.Parse namespace NzbDrone.Api.Parse
@ -9,8 +9,8 @@ namespace NzbDrone.Api.Parse
public class ParseResource : RestResource public class ParseResource : RestResource
{ {
public string Title { get; set; } public string Title { get; set; }
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } public ParsedAlbumInfo ParsedAlbumInfo { get; set; }
public SeriesResource Series { get; set; } public ArtistResource Artist { get; set; }
public List<EpisodeResource> Episodes { get; set; } public List<AlbumResource> Albums { get; set; }
} }
} }

@ -105,7 +105,7 @@ namespace NzbDrone.Api.Queue
throw new NotFoundException(); throw new NotFoundException();
} }
_downloadService.DownloadReport(pendingRelease.RemoteEpisode); _downloadService.DownloadReport(pendingRelease.RemoteAlbum);
return resource.AsResponse(); return resource.AsResponse();
} }

@ -4,6 +4,8 @@ using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series; using NzbDrone.Api.Series;
using NzbDrone.Api.Episodes; using NzbDrone.Api.Episodes;
using NzbDrone.Api.Music;
using NzbDrone.Api.Albums;
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using System.Linq; using System.Linq;
@ -12,8 +14,8 @@ namespace NzbDrone.Api.Queue
{ {
public class QueueResource : RestResource public class QueueResource : RestResource
{ {
public SeriesResource Series { get; set; } public ArtistResource Artist { get; set; }
public EpisodeResource Episode { get; set; } public AlbumResource Album { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public decimal Size { get; set; } public decimal Size { get; set; }
public string Title { get; set; } public string Title { get; set; }
@ -37,8 +39,8 @@ namespace NzbDrone.Api.Queue
{ {
Id = model.Id, Id = model.Id,
Series = model.Series.ToResource(), Artist = model.Artist.ToResource(),
Episode = model.Episode.ToResource(), Album = model.Album.ToResource(),
Quality = model.Quality, Quality = model.Quality,
Size = model.Size, Size = model.Size,
Title = model.Title, Title = model.Title,

@ -17,18 +17,11 @@ namespace NzbDrone.Api.Tracks
public bool Explicit { get; set; } public bool Explicit { get; set; }
public int TrackNumber { get; set; } public int TrackNumber { get; set; }
public string Title { get; set; } public string Title { get; set; }
//public string AirDate { get; set; } public int Duration { get; set; }
//public DateTime? AirDateUtc { get; set; }
//public string Overview { get; set; }
public TrackFileResource TrackFile { get; set; } public TrackFileResource TrackFile { get; set; }
public bool HasFile { get; set; } public bool HasFile { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }
//public int? AbsoluteEpisodeNumber { get; set; }
//public int? SceneAbsoluteEpisodeNumber { get; set; }
//public int? SceneEpisodeNumber { get; set; }
//public int? SceneSeasonNumber { get; set; }
//public bool UnverifiedSceneNumbering { get; set; }
//public string SeriesTitle { get; set; } //public string SeriesTitle { get; set; }
public ArtistResource Artist { get; set; } public ArtistResource Artist { get; set; }
public Ratings Ratings { get; set; } public Ratings Ratings { get; set; }
@ -54,19 +47,12 @@ namespace NzbDrone.Api.Tracks
Explicit = model.Explicit, Explicit = model.Explicit,
TrackNumber = model.TrackNumber, TrackNumber = model.TrackNumber,
Title = model.Title, Title = model.Title,
//AirDate = model.AirDate, Duration = model.Duration,
//AirDateUtc = model.AirDateUtc,
//Overview = model.Overview,
//EpisodeFile //EpisodeFile
HasFile = model.HasFile, HasFile = model.HasFile,
Monitored = model.Monitored, Monitored = model.Monitored,
Ratings = model.Ratings, Ratings = model.Ratings,
//AbsoluteEpisodeNumber = model.AbsoluteEpisodeNumber,
//SceneAbsoluteEpisodeNumber = model.SceneAbsoluteEpisodeNumber,
//SceneEpisodeNumber = model.SceneEpisodeNumber,
//SceneSeasonNumber = model.SceneSeasonNumber,
//UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
//SeriesTitle = model.SeriesTitle, //SeriesTitle = model.SeriesTitle,
//Series = model.Series.MapToResource(), //Series = model.Series.MapToResource(),
}; };

@ -8,7 +8,7 @@ using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
@ -16,40 +16,40 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class AcceptableSizeSpecificationFixture : CoreTest<AcceptableSizeSpecification> public class AcceptableSizeSpecificationFixture : CoreTest<AcceptableSizeSpecification>
{ {
private RemoteEpisode parseResultMultiSet; private RemoteAlbum parseResultMultiSet;
private RemoteEpisode parseResultMulti; private RemoteAlbum parseResultMulti;
private RemoteEpisode parseResultSingle; private RemoteAlbum parseResultSingle;
private Series series; private Artist artist;
private QualityDefinition qualityType; private QualityDefinition qualityType;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
series = Builder<Series>.CreateNew() artist = Builder<Artist>.CreateNew()
.Build(); .Build();
parseResultMultiSet = new RemoteEpisode parseResultMultiSet = new RemoteAlbum
{ {
Series = series, Artist = artist,
Release = new ReleaseInfo(), Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
Episodes = new List<Episode> { new Episode(), new Episode(), new Episode(), new Episode(), new Episode(), new Episode() } Albums = new List<Album> { new Album(), new Album(), new Album(), new Album(), new Album(), new Album() }
}; };
parseResultMulti = new RemoteEpisode parseResultMulti = new RemoteAlbum
{ {
Series = series, Artist = artist,
Release = new ReleaseInfo(), Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
Episodes = new List<Episode> { new Episode(), new Episode() } Albums = new List<Album> { new Album(), new Album() }
}; };
parseResultSingle = new RemoteEpisode parseResultSingle = new RemoteAlbum
{ {
Series = series, Artist = artist,
Release = new ReleaseInfo(), Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
Episodes = new List<Episode> { new Episode() { Id = 2 } } Albums = new List<Album> { new Album { Id = 2 } }
}; };
@ -59,83 +59,68 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
qualityType = Builder<QualityDefinition>.CreateNew() qualityType = Builder<QualityDefinition>.CreateNew()
.With(q => q.MinSize = 2) .With(q => q.MinSize = 2)
.With(q => q.MaxSize = 10) .With(q => q.MaxSize = 6)
.With(q => q.Quality = Quality.MP3_192) .With(q => q.Quality = Quality.MP3_192)
.Build(); .Build();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.MP3_192)).Returns(qualityType); Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.MP3_192)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup( Mocker.GetMock<IAlbumService>().Setup(
s => s.GetEpisodesBySeason(It.IsAny<int>(), It.IsAny<int>())) s => s.GetAlbumsByArtist(It.IsAny<int>()))
.Returns(new List<Episode>() { .Returns(new List<Album>() {
new Episode(), new Episode(), new Episode(), new Episode(), new Episode(), new Album(), new Album(), new Album(), new Album(), new Album(),
new Episode(), new Episode(), new Episode(), new Episode() { Id = 2 }, new Episode() }); new Album(), new Album(), new Album(), new Album { Id = 2 }, new Album() });
} }
private void GivenLastEpisode() private void GivenLastAlbum()
{ {
Mocker.GetMock<IEpisodeService>().Setup( Mocker.GetMock<IAlbumService>().Setup(
s => s.GetEpisodesBySeason(It.IsAny<int>(), It.IsAny<int>())) s => s.GetAlbumsByArtist(It.IsAny<int>()))
.Returns(new List<Episode>() { .Returns(new List<Album> {
new Episode(), new Episode(), new Episode(), new Episode(), new Episode(), new Album(), new Album(), new Album(), new Album(), new Album(),
new Episode(), new Episode(), new Episode(), new Episode(), new Episode() { Id = 2 } }); new Album(), new Album(), new Album(), new Album(), new Album { Id = 2 } });
} }
[TestCase(30, 50, false)] [TestCase(1800000, 50, false)]
[TestCase(30, 250, true)] [TestCase(1800000, 150, true)]
[TestCase(30, 500, false)] [TestCase(1800000, 300, false)]
[TestCase(60, 100, false)] [TestCase(3600000, 100, false)]
[TestCase(60, 500, true)] [TestCase(3600000, 300, true)]
[TestCase(60, 1000, false)] [TestCase(3600000, 600, false)]
public void single_episode(int runtime, int sizeInMegaBytes, bool expectedResult) public void single_album(int runtime, int sizeInMegaBytes, bool expectedResult)
{ {
series.Runtime = runtime; parseResultSingle.Albums.Select(c => { c.Duration = runtime; return c; }).ToList();
parseResultSingle.Series = series; parseResultSingle.Artist = artist;
parseResultSingle.Release.Size = sizeInMegaBytes.Megabytes(); parseResultSingle.Release.Size = sizeInMegaBytes.Megabytes();
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().Be(expectedResult); Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().Be(expectedResult);
} }
[TestCase(30, 500, true)] [TestCase(1800000, 50 * 2, false)]
[TestCase(30, 1000, false)] [TestCase(1800000, 150 * 2, true)]
[TestCase(60, 1000, true)] [TestCase(1800000, 300 * 2, false)]
[TestCase(60, 2000, false)] [TestCase(3600000, 100 * 2, false)]
public void single_episode_first_or_last(int runtime, int sizeInMegaBytes, bool expectedResult) [TestCase(3600000, 300 * 2, true)]
[TestCase(3600000, 600 * 2, false)]
public void multi_album(int runtime, int sizeInMegaBytes, bool expectedResult)
{ {
GivenLastEpisode(); parseResultMulti.Albums.Select(c => { c.Duration = runtime; return c; }).ToList();
parseResultMulti.Artist = artist;
series.Runtime = runtime;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = sizeInMegaBytes.Megabytes();
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().Be(expectedResult);
}
[TestCase(30, 50 * 2, false)]
[TestCase(30, 250 * 2, true)]
[TestCase(30, 500 * 2, false)]
[TestCase(60, 100 * 2, false)]
[TestCase(60, 500 * 2, true)]
[TestCase(60, 1000 * 2, false)]
public void multi_episode(int runtime, int sizeInMegaBytes, bool expectedResult)
{
series.Runtime = runtime;
parseResultMulti.Series = series;
parseResultMulti.Release.Size = sizeInMegaBytes.Megabytes(); parseResultMulti.Release.Size = sizeInMegaBytes.Megabytes();
Subject.IsSatisfiedBy(parseResultMulti, null).Accepted.Should().Be(expectedResult); Subject.IsSatisfiedBy(parseResultMulti, null).Accepted.Should().Be(expectedResult);
} }
[TestCase(30, 50 * 6, false)] [TestCase(1800000, 50 * 6, false)]
[TestCase(30, 250 * 6, true)] [TestCase(1800000, 150 * 6, true)]
[TestCase(30, 500 * 6, false)] [TestCase(1800000, 300 * 6, false)]
[TestCase(60, 100 * 6, false)] [TestCase(3600000, 100 * 6, false)]
[TestCase(60, 500 * 6, true)] [TestCase(3600000, 300 * 6, true)]
[TestCase(60, 1000 * 6, false)] [TestCase(3600000, 600 * 6, false)]
public void multiset_episode(int runtime, int sizeInMegaBytes, bool expectedResult) public void multiset_album(int runtime, int sizeInMegaBytes, bool expectedResult)
{ {
series.Runtime = runtime; parseResultMultiSet.Albums.Select(c => { c.Duration = runtime; return c; }).ToList();
parseResultMultiSet.Series = series; parseResultMultiSet.Artist = artist;
parseResultMultiSet.Release.Size = sizeInMegaBytes.Megabytes(); parseResultMultiSet.Release.Size = sizeInMegaBytes.Megabytes();
Subject.IsSatisfiedBy(parseResultMultiSet, null).Accepted.Should().Be(expectedResult); Subject.IsSatisfiedBy(parseResultMultiSet, null).Accepted.Should().Be(expectedResult);
@ -144,10 +129,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_size_is_zero() public void should_return_true_if_size_is_zero()
{ {
GivenLastEpisode(); GivenLastAlbum();
parseResultSingle.Albums.Select(c => { c.Duration = 1800000; return c; }).ToList();
series.Runtime = 30; parseResultSingle.Artist = artist;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = 0; parseResultSingle.Release.Size = 0;
qualityType.MinSize = 10; qualityType.MinSize = 10;
qualityType.MaxSize = 20; qualityType.MaxSize = 20;
@ -158,10 +142,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_unlimited_30_minute() public void should_return_true_if_unlimited_30_minute()
{ {
GivenLastEpisode(); GivenLastAlbum();
parseResultSingle.Albums.Select(c => { c.Duration = 1800000; return c; }).ToList();
series.Runtime = 30; parseResultSingle.Artist = artist;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = 18457280000; parseResultSingle.Release.Size = 18457280000;
qualityType.MaxSize = null; qualityType.MaxSize = null;
@ -171,50 +154,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_unlimited_60_minute() public void should_return_true_if_unlimited_60_minute()
{ {
GivenLastEpisode(); GivenLastAlbum();
parseResultSingle.Albums.Select(c => { c.Duration = 3600000; return c; }).ToList();
series.Runtime = 60; parseResultSingle.Artist = artist;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = 36857280000; parseResultSingle.Release.Size = 36857280000;
qualityType.MaxSize = null; qualityType.MaxSize = null;
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().BeTrue();
} }
[Test]
public void should_treat_daily_series_as_single_episode()
{
GivenLastEpisode();
series.Runtime = 60;
parseResultSingle.Series = series;
parseResultSingle.Series.SeriesType = SeriesTypes.Daily;
parseResultSingle.Release.Size = 300.Megabytes();
qualityType.MaxSize = 10;
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_RAWHD()
{
parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.FLAC);
series.Runtime = 45;
parseResultSingle.Series = series;
parseResultSingle.Series.SeriesType = SeriesTypes.Daily;
parseResultSingle.Release.Size = 8000.Megabytes();
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_for_special()
{
parseResultSingle.ParsedEpisodeInfo.Special = true;
Subject.IsSatisfiedBy(parseResultSingle, null).Accepted.Should().BeTrue();
}
} }
} }

@ -1,110 +0,0 @@
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Marr.Data;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class AnimeVersionUpgradeSpecificationFixture : CoreTest<AnimeVersionUpgradeSpecification>
{
private AnimeVersionUpgradeSpecification _subject;
private RemoteEpisode _remoteEpisode;
private EpisodeFile _episodeFile;
[SetUp]
public void Setup()
{
Mocker.Resolve<QualityUpgradableSpecification>();
_subject = Mocker.Resolve<AnimeVersionUpgradeSpecification>();
_episodeFile = new EpisodeFile
{
Quality = new QualityModel(Quality.MP3_256, new Revision()),
ReleaseGroup = "DRONE2"
};
_remoteEpisode = new RemoteEpisode();
_remoteEpisode.Series = new Series { SeriesType = SeriesTypes.Anime };
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo
{
Quality = new QualityModel(Quality.MP3_256, new Revision(2)),
ReleaseGroup = "DRONE"
};
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.All()
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(_episodeFile))
.Build()
.ToList();
}
private void GivenStandardSeries()
{
_remoteEpisode.Series.SeriesType = SeriesTypes.Standard;
}
private void GivenNoVersionUpgrade()
{
_remoteEpisode.ParsedEpisodeInfo.Quality.Revision = new Revision();
}
[Test]
public void should_be_true_when_no_existing_file()
{
_remoteEpisode.Episodes.First().EpisodeFileId = 0;
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_true_if_series_is_not_anime()
{
GivenStandardSeries();
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_true_if_is_not_a_version_upgrade_for_existing_file()
{
GivenNoVersionUpgrade();
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_true_when_release_group_matches()
{
_episodeFile.ReleaseGroup = _remoteEpisode.ParsedEpisodeInfo.ReleaseGroup;
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_false_when_existing_file_doesnt_have_a_release_group()
{
_episodeFile.ReleaseGroup = string.Empty;
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
[Test]
public void should_should_be_false_when_release_doesnt_have_a_release_group()
{
_remoteEpisode.ParsedEpisodeInfo.ReleaseGroup = string.Empty;
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
[Test]
public void should_be_false_when_release_group_does_not_match()
{
_subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
}
}

@ -11,28 +11,28 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class CutoffSpecificationFixture : CoreTest<QualityUpgradableSpecification> public class CutoffSpecificationFixture : CoreTest<QualityUpgradableSpecification>
{ {
[Test] [Test]
public void should_return_true_if_current_episode_is_less_than_cutoff() public void should_return_true_if_current_album_is_less_than_cutoff()
{ {
Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }, Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() },
new QualityModel(Quality.MP3_192, new Revision(version: 2))).Should().BeTrue(); new QualityModel(Quality.MP3_192, new Revision(version: 2))).Should().BeTrue();
} }
[Test] [Test]
public void should_return_false_if_current_episode_is_equal_to_cutoff() public void should_return_false_if_current_album_is_equal_to_cutoff()
{ {
Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() }, Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() },
new QualityModel(Quality.MP3_256, new Revision(version: 2))).Should().BeFalse(); new QualityModel(Quality.MP3_256, new Revision(version: 2))).Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_current_episode_is_greater_than_cutoff() public void should_return_false_if_current_album_is_greater_than_cutoff()
{ {
Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() }, Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() },
new QualityModel(Quality.MP3_512, new Revision(version: 2))).Should().BeFalse(); new QualityModel(Quality.MP3_512, new Revision(version: 2))).Should().BeFalse();
} }
[Test] [Test]
public void should_return_true_when_new_episode_is_proper_but_existing_is_not() public void should_return_true_when_new_album_is_proper_but_existing_is_not()
{ {
Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() }, Subject.CutoffNotMet(new Profile { Cutoff = Quality.MP3_256, Items = Qualities.QualityFixture.GetDefaultQualities() },
new QualityModel(Quality.MP3_256, new Revision(version: 1)), new QualityModel(Quality.MP3_256, new Revision(version: 1)),

@ -8,7 +8,7 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using FizzWare.NBuilder; using FizzWare.NBuilder;
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class DownloadDecisionMakerFixture : CoreTest<DownloadDecisionMaker> public class DownloadDecisionMakerFixture : CoreTest<DownloadDecisionMaker>
{ {
private List<ReleaseInfo> _reports; private List<ReleaseInfo> _reports;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
private Mock<IDecisionEngineSpecification> _pass1; private Mock<IDecisionEngineSpecification> _pass1;
private Mock<IDecisionEngineSpecification> _pass2; private Mock<IDecisionEngineSpecification> _pass2;
@ -39,23 +39,23 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_fail2 = new Mock<IDecisionEngineSpecification>(); _fail2 = new Mock<IDecisionEngineSpecification>();
_fail3 = new Mock<IDecisionEngineSpecification>(); _fail3 = new Mock<IDecisionEngineSpecification>();
_pass1.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Accept); _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Accept);
_pass2.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Accept); _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Accept);
_pass3.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Accept); _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Accept);
_fail1.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Reject("fail1")); _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Reject("fail1"));
_fail2.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Reject("fail2")); _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Reject("fail2"));
_fail3.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(Decision.Reject("fail3")); _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null)).Returns(Decision.Reject("fail3"));
_reports = new List<ReleaseInfo> { new ReleaseInfo { Title = "The.Office.S03E115.DVDRip.XviD-OSiTV" } }; _reports = new List<ReleaseInfo> { new ReleaseInfo { Title = "Coldplay-A Head Full Of Dreams-CD-FLAC-2015-PERFECT" } };
_remoteEpisode = new RemoteEpisode { _remoteAlbum = new RemoteAlbum {
Series = new Series(), Artist = new Artist(),
Episodes = new List<Episode> { new Episode() } Albums = new List<Album> { new Album() }
}; };
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>())) .Setup(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()))
.Returns(_remoteEpisode); .Returns(_remoteAlbum);
} }
private void GivenSpecifications(params Mock<IDecisionEngineSpecification>[] mocks) private void GivenSpecifications(params Mock<IDecisionEngineSpecification>[] mocks)
@ -70,12 +70,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.GetRssDecision(_reports).ToList(); Subject.GetRssDecision(_reports).ToList();
_fail1.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _fail1.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
_fail2.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _fail2.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
_fail3.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _fail3.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
_pass1.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _pass1.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
_pass2.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _pass2.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
_pass3.Verify(c => c.IsSatisfiedBy(_remoteEpisode, null), Times.Once()); _pass3.Verify(c => c.IsSatisfiedBy(_remoteAlbum, null), Times.Once());
} }
[Test] [Test]
@ -118,51 +118,51 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
} }
[Test] [Test]
public void should_not_attempt_to_map_episode_if_not_parsable() public void should_not_attempt_to_map_album_if_not_parsable()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_reports[0].Title = "Not parsable"; _reports[0].Title = "Not parsable";
var results = Subject.GetRssDecision(_reports).ToList(); var results = Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never()); Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
results.Should().BeEmpty(); results.Should().BeEmpty();
} }
[Test] [Test]
public void should_not_attempt_to_map_episode_series_title_is_blank() public void should_not_attempt_to_map_album_artist_title_is_blank()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_reports[0].Title = "1937 - Snow White and the Seven Dwarves"; _reports[0].Title = "2013 - Night Visions";
var results = Subject.GetRssDecision(_reports).ToList(); var results = Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never()); Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
results.Should().BeEmpty(); results.Should().BeEmpty();
} }
[Test] [Test]
public void should_not_attempt_to_make_decision_if_series_is_unknown() public void should_not_attempt_to_make_decision_if_artist_is_unknown()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Series = null; _remoteAlbum.Artist = null;
Subject.GetRssDecision(_reports); Subject.GetRssDecision(_reports);
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never()); _pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteAlbum>(), null), Times.Never());
} }
[Test] [Test]
@ -170,29 +170,29 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenSpecifications(_pass1); GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>())) Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()))
.Throws<TestException>(); .Throws<TestException>();
_reports = new List<ReleaseInfo> _reports = new List<ReleaseInfo>
{ {
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"}, new ReleaseInfo{Title = "Coldplay-A Head Full Of Dreams-CD-FLAC-2015-PERFECT"},
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"}, new ReleaseInfo{Title = "Coldplay-A Head Full Of Dreams-CD-FLAC-2015-PERFECT"},
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"} new ReleaseInfo{Title = "Coldplay-A Head Full Of Dreams-CD-FLAC-2015-PERFECT"}
}; };
Subject.GetRssDecision(_reports); Subject.GetRssDecision(_reports);
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Exactly(_reports.Count)); Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()), Times.Exactly(_reports.Count));
ExceptionVerification.ExpectedErrors(3); ExceptionVerification.ExpectedErrors(3);
} }
[Test] [Test]
public void should_return_unknown_series_rejection_if_series_is_unknown() public void should_return_unknown_artist_rejection_if_artist_is_unknown()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Series = null; _remoteAlbum.Artist = null;
var result = Subject.GetRssDecision(_reports); var result = Subject.GetRssDecision(_reports);
@ -200,40 +200,38 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
} }
[Test] [Test]
public void should_only_include_reports_for_requested_episodes() public void should_only_include_reports_for_requested_albums()
{ {
var series = Builder<Series>.CreateNew().Build(); var artist = Builder<Artist>.CreateNew().Build();
var episodes = Builder<Episode>.CreateListOfSize(2) var albums = Builder<Album>.CreateListOfSize(2)
.All() .All()
.With(v => v.SeriesId, series.Id) .With(v => v.ArtistId, artist.Id)
.With(v => v.Series, series) .With(v => v.Artist, artist)
.With(v => v.SeasonNumber, 1)
.With(v => v.SceneSeasonNumber, 2)
.BuildList(); .BuildList();
var criteria = new SeasonSearchCriteria { Episodes = episodes.Take(1).ToList(), SeasonNumber = 1 }; var criteria = new ArtistSearchCriteria { Albums = albums.Take(1).ToList()};
var reports = episodes.Select(v => var reports = albums.Select(v =>
new ReleaseInfo() new ReleaseInfo()
{ {
Title = string.Format("{0}.S{1:00}E{2:00}.720p.WEB-DL-DRONE", series.Title, v.SceneSeasonNumber, v.SceneEpisodeNumber) Title = string.Format("{0}-{1}[FLAC][2017][DRONE]", artist.Name, v.Title)
}).ToList(); }).ToList();
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(v => v.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>())) .Setup(v => v.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()))
.Returns<ParsedEpisodeInfo, int, int, SearchCriteriaBase>((p,tvdbid,tvrageid,c) => .Returns<ParsedAlbumInfo, SearchCriteriaBase>((p,c) =>
new RemoteEpisode new RemoteAlbum
{ {
DownloadAllowed = true, DownloadAllowed = true,
ParsedEpisodeInfo = p, ParsedAlbumInfo = p,
Series = series, Artist = artist,
Episodes = episodes.Where(v => v.SceneEpisodeNumber == p.EpisodeNumbers.First()).ToList() Albums = albums.Where(v => v.Title == p.AlbumTitle).ToList()
}); });
Mocker.SetConstant<IEnumerable<IDecisionEngineSpecification>>(new List<IDecisionEngineSpecification> Mocker.SetConstant<IEnumerable<IDecisionEngineSpecification>>(new List<IDecisionEngineSpecification>
{ {
Mocker.Resolve<NzbDrone.Core.DecisionEngine.Specifications.Search.EpisodeRequestedSpecification>() Mocker.Resolve<NzbDrone.Core.DecisionEngine.Specifications.Search.AlbumRequestedSpecification>()
}); });
var decisions = Subject.GetSearchDecision(reports, criteria); var decisions = Subject.GetSearchDecision(reports, criteria);
@ -244,31 +242,31 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
} }
[Test] [Test]
public void should_not_allow_download_if_series_is_unknown() public void should_not_allow_download_if_artist_is_unknown()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Series = null; _remoteAlbum.Artist = null;
var result = Subject.GetRssDecision(_reports); var result = Subject.GetRssDecision(_reports);
result.Should().HaveCount(1); result.Should().HaveCount(1);
result.First().RemoteEpisode.DownloadAllowed.Should().BeFalse(); result.First().RemoteAlbum.DownloadAllowed.Should().BeFalse();
} }
[Test] [Test]
public void should_not_allow_download_if_no_episodes_found() public void should_not_allow_download_if_no_albums_found()
{ {
GivenSpecifications(_pass1, _pass2, _pass3); GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Episodes = new List<Episode>(); _remoteAlbum.Albums = new List<Album>();
var result = Subject.GetRssDecision(_reports); var result = Subject.GetRssDecision(_reports);
result.Should().HaveCount(1); result.Should().HaveCount(1);
result.First().RemoteEpisode.DownloadAllowed.Should().BeFalse(); result.First().RemoteAlbum.DownloadAllowed.Should().BeFalse();
} }
[Test] [Test]
@ -276,7 +274,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenSpecifications(_pass1); GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>())) Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedAlbumInfo>(), It.IsAny<SearchCriteriaBase>()))
.Throws<TestException>(); .Throws<TestException>();
_reports = new List<ReleaseInfo> _reports = new List<ReleaseInfo>

@ -11,9 +11,8 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
@ -23,13 +22,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
private HistorySpecification _upgradeHistory; private HistorySpecification _upgradeHistory;
private RemoteEpisode _parseResultMulti; private RemoteAlbum _parseResultMulti;
private RemoteEpisode _parseResultSingle; private RemoteAlbum _parseResultSingle;
private QualityModel _upgradableQuality; private QualityModel _upgradableQuality;
private QualityModel _notupgradableQuality; private QualityModel _notupgradableQuality;
private Series _fakeSeries; private Artist _fakeArtist;
private const int FIRST_EPISODE_ID = 1; private const int FIRST_ALBUM_ID = 1;
private const int SECOND_EPISODE_ID = 2; private const int SECOND_ALBUM_ID = 2;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -37,29 +36,29 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<QualityUpgradableSpecification>(); Mocker.Resolve<QualityUpgradableSpecification>();
_upgradeHistory = Mocker.Resolve<HistorySpecification>(); _upgradeHistory = Mocker.Resolve<HistorySpecification>();
var singleEpisodeList = new List<Episode> { new Episode { Id = FIRST_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 3 } }; var singleAlbumList = new List<Album> { new Album { Id = FIRST_ALBUM_ID} };
var doubleEpisodeList = new List<Episode> { var doubleAlbumList = new List<Album> {
new Episode {Id = FIRST_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 3 }, new Album {Id = FIRST_ALBUM_ID },
new Episode {Id = SECOND_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 4 }, new Album {Id = SECOND_ALBUM_ID },
new Episode {Id = 3, SeasonNumber = 12, EpisodeNumber = 5 } new Album {Id = 3 }
}; };
_fakeSeries = Builder<Series>.CreateNew() _fakeArtist = Builder<Artist>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(c => c.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
_parseResultMulti = new RemoteEpisode _parseResultMulti = new RemoteAlbum
{ {
Series = _fakeSeries, Artist = _fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
Episodes = doubleEpisodeList Albums = doubleAlbumList
}; };
_parseResultSingle = new RemoteEpisode _parseResultSingle = new RemoteAlbum
{ {
Series = _fakeSeries, Artist = _fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
Episodes = singleEpisodeList Albums = singleAlbumList
}; };
_upgradableQuality = new QualityModel(Quality.MP3_192, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.MP3_192, new Revision(version: 1));
@ -70,9 +69,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(true); .Returns(true);
} }
private void GivenMostRecentForEpisode(int episodeId, string downloadId, QualityModel quality, DateTime date, HistoryEventType eventType) private void GivenMostRecentForAlbum(int albumId, string downloadId, QualityModel quality, DateTime date, HistoryEventType eventType)
{ {
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(episodeId)) Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForAlbum(albumId))
.Returns(new History.History { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType }); .Returns(new History.History { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType });
} }
@ -92,14 +91,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_latest_history_item_is_null() public void should_return_true_if_latest_history_item_is_null()
{ {
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(It.IsAny<int>())).Returns((History.History)null); Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForAlbum(It.IsAny<int>())).Returns((History.History)null);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_if_latest_history_item_is_not_grabbed() public void should_return_true_if_latest_history_item_is_not_grabbed()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.DownloadFailed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.DownloadFailed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
@ -113,57 +112,57 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_latest_history_item_is_older_than_twelve_hours() public void should_return_true_if_latest_history_item_is_older_than_twelve_hours()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-13), HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-12).AddMilliseconds(-1), HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_upgradable_if_only_episode_is_upgradable() public void should_be_upgradable_if_only_album_is_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_upgradable_if_both_episodes_are_upgradable() public void should_be_upgradable_if_both_albums_are_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_not_be_upgradable_if_both_episodes_are_not_upgradable() public void should_not_be_upgradable_if_both_albums_are_not_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_first_episodes_is_upgradable() public void should_be_not_upgradable_if_only_first_albums_is_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() public void should_be_not_upgradable_if_only_second_albums_is_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing() public void should_not_be_upgradable_if_album_is_of_same_quality_as_existing()
{ {
_fakeSeries.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeArtist.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
_upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
@ -171,11 +170,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_not_be_upgradable_if_cutoff_already_met() public void should_not_be_upgradable_if_cutoff_already_met()
{ {
_fakeSeries.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeArtist.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
_upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
@ -183,7 +182,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_false_if_latest_history_item_is_only_one_hour_old() public void should_return_false_if_latest_history_item_is_only_one_hour_old()
{ {
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
@ -191,7 +190,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_false_if_latest_history_has_a_download_id_and_cdh_is_disabled() public void should_return_false_if_latest_history_has_a_download_id_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); GivenCdhDisabled();
GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
@ -199,20 +198,20 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_false_if_cutoff_already_met_and_cdh_is_disabled() public void should_return_false_if_cutoff_already_met_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); GivenCdhDisabled();
_fakeSeries.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeArtist.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
_upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.MP3_512, new Revision(version: 1));
GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_only_episode_is_not_upgradable_and_cdh_is_disabled() public void should_return_false_if_only_album_is_not_upgradable_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); GivenCdhDisabled();
GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
} }

@ -6,7 +6,7 @@ using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
@ -14,18 +14,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class LanguageSpecificationFixture : CoreTest public class LanguageSpecificationFixture : CoreTest
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode _remoteAlbum = new RemoteAlbum
{ {
ParsedEpisodeInfo = new ParsedEpisodeInfo ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Language = Language.English Language = Language.English
}, },
Series = new Series Artist = new Artist
{ {
Profile = new LazyLoaded<Profile>(new Profile Profile = new LazyLoaded<Profile>(new Profile
{ {
@ -37,12 +37,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithEnglishRelease() private void WithEnglishRelease()
{ {
_remoteEpisode.ParsedEpisodeInfo.Language = Language.English; _remoteAlbum.ParsedAlbumInfo.Language = Language.English;
} }
private void WithGermanRelease() private void WithGermanRelease()
{ {
_remoteEpisode.ParsedEpisodeInfo.Language = Language.German; _remoteAlbum.ParsedAlbumInfo.Language = Language.German;
} }
[Test] [Test]
@ -50,7 +50,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
WithEnglishRelease(); WithEnglishRelease();
Mocker.Resolve<LanguageSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Mocker.Resolve<LanguageSpecification>().IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
WithGermanRelease(); WithGermanRelease();
Mocker.Resolve<LanguageSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Mocker.Resolve<LanguageSpecification>().IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -13,12 +13,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class MinimumAgeSpecificationFixture : CoreTest<MinimumAgeSpecification> public class MinimumAgeSpecificationFixture : CoreTest<MinimumAgeSpecification>
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode _remoteAlbum = new RemoteAlbum
{ {
Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Usenet } Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Usenet }
}; };
@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithAge(int minutes) private void WithAge(int minutes)
{ {
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddMinutes(-minutes); _remoteAlbum.Release.PublishDate = DateTime.UtcNow.AddMinutes(-minutes);
} }
[Test] [Test]
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithMinimumAge(0); WithMinimumAge(0);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithMinimumAge(30); WithMinimumAge(30);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithMinimumAge(30); WithMinimumAge(30);
WithAge(10); WithAge(10);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -0,0 +1,141 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Music;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class MonitoredAlbumSpecificationFixture : CoreTest<MonitoredAlbumSpecification>
{
private MonitoredAlbumSpecification _monitoredAlbumSpecification;
private RemoteAlbum _parseResultMulti;
private RemoteAlbum _parseResultSingle;
private Artist _fakeArtist;
private Album _firstAlbum;
private Album _secondAlbum;
[SetUp]
public void Setup()
{
_monitoredAlbumSpecification = Mocker.Resolve<MonitoredAlbumSpecification>();
_fakeArtist = Builder<Artist>.CreateNew()
.With(c => c.Monitored = true)
.Build();
_firstAlbum = new Album { Monitored = true };
_secondAlbum = new Album { Monitored = true };
var singleAlbumList = new List<Album> { _firstAlbum };
var doubleAlbumList = new List<Album> { _firstAlbum, _secondAlbum };
_parseResultMulti = new RemoteAlbum
{
Artist = _fakeArtist,
Albums = doubleAlbumList
};
_parseResultSingle = new RemoteAlbum
{
Artist = _fakeArtist,
Albums = singleAlbumList
};
}
private void WithFirstAlbumUnmonitored()
{
_firstAlbum.Monitored = false;
}
private void WithSecondAlbumUnmonitored()
{
_secondAlbum.Monitored = false;
}
[Test]
public void setup_should_return_monitored_album_should_return_true()
{
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
}
[Test]
public void not_monitored_series_should_be_skipped()
{
_fakeArtist.Monitored = false;
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_album_not_monitored_should_return_false()
{
WithFirstAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
}
[Test]
public void both_albums_not_monitored_should_return_false()
{
WithFirstAlbumUnmonitored();
WithSecondAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_first_album_not_monitored_should_return_false()
{
WithFirstAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_second_album_not_monitored_should_return_false()
{
WithSecondAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_for_single_album_search()
{
_fakeArtist.Monitored = false;
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria()).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_album_is_monitored_for_season_search()
{
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, new SeasonSearchCriteria()).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_if_album_is_not_monitored_for_season_search()
{
WithFirstAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, new SeasonSearchCriteria()).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_if_album_is_not_monitored_and_monitoredEpisodesOnly_flag_is_false()
{
WithFirstAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = false }).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_if_album_is_not_monitored_and_monitoredEpisodesOnly_flag_is_true()
{
WithFirstAlbumUnmonitored();
_monitoredAlbumSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria{ MonitoredEpisodesOnly = true}).Accepted.Should().BeFalse();
}
}
}

@ -1,141 +0,0 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class MonitoredEpisodeSpecificationFixture : CoreTest<MonitoredEpisodeSpecification>
{
private MonitoredEpisodeSpecification _monitoredEpisodeSpecification;
private RemoteEpisode _parseResultMulti;
private RemoteEpisode _parseResultSingle;
private Series _fakeSeries;
private Episode _firstEpisode;
private Episode _secondEpisode;
[SetUp]
public void Setup()
{
_monitoredEpisodeSpecification = Mocker.Resolve<MonitoredEpisodeSpecification>();
_fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Monitored = true)
.Build();
_firstEpisode = new Episode { Monitored = true };
_secondEpisode = new Episode { Monitored = true };
var singleEpisodeList = new List<Episode> { _firstEpisode };
var doubleEpisodeList = new List<Episode> { _firstEpisode, _secondEpisode };
_parseResultMulti = new RemoteEpisode
{
Series = _fakeSeries,
Episodes = doubleEpisodeList
};
_parseResultSingle = new RemoteEpisode
{
Series = _fakeSeries,
Episodes = singleEpisodeList
};
}
private void WithFirstEpisodeUnmonitored()
{
_firstEpisode.Monitored = false;
}
private void WithSecondEpisodeUnmonitored()
{
_secondEpisode.Monitored = false;
}
[Test]
public void setup_should_return_monitored_episode_should_return_true()
{
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
}
[Test]
public void not_monitored_series_should_be_skipped()
{
_fakeSeries.Monitored = false;
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_episode_not_monitored_should_return_false()
{
WithFirstEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
}
[Test]
public void both_episodes_not_monitored_should_return_false()
{
WithFirstEpisodeUnmonitored();
WithSecondEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_first_episode_not_monitored_should_return_false()
{
WithFirstEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void only_second_episode_not_monitored_should_return_false()
{
WithSecondEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_for_single_episode_search()
{
_fakeSeries.Monitored = false;
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria()).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_episode_is_monitored_for_season_search()
{
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SeasonSearchCriteria()).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_if_episode_is_not_monitored_for_season_search()
{
WithFirstEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SeasonSearchCriteria()).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_if_episode_is_not_monitored_and_monitoredEpisodesOnly_flag_is_false()
{
WithFirstEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = false }).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_if_episode_is_not_monitored_and_monitoredEpisodesOnly_flag_is_true()
{
WithFirstEpisodeUnmonitored();
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria{ MonitoredEpisodesOnly = true}).Accepted.Should().BeFalse();
}
}
}

@ -4,7 +4,7 @@ using System.Linq;
using Moq; using Moq;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -26,33 +26,32 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenPreferredDownloadProtocol(DownloadProtocol.Usenet); GivenPreferredDownloadProtocol(DownloadProtocol.Usenet);
} }
private Episode GivenEpisode(int id) private Album GivenAlbum(int id)
{ {
return Builder<Episode>.CreateNew() return Builder<Album>.CreateNew()
.With(e => e.Id = id) .With(e => e.Id = id)
.With(e => e.EpisodeNumber = id)
.Build(); .Build();
} }
private RemoteEpisode GivenRemoteEpisode(List<Episode> episodes, QualityModel quality, int age = 0, long size = 0, DownloadProtocol downloadProtocol = DownloadProtocol.Usenet) private RemoteAlbum GivenRemoteAlbum(List<Album> albums, QualityModel quality, int age = 0, long size = 0, DownloadProtocol downloadProtocol = DownloadProtocol.Usenet)
{ {
var remoteEpisode = new RemoteEpisode(); var remoteAlbum = new RemoteAlbum();
remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo(); remoteAlbum.ParsedAlbumInfo = new ParsedAlbumInfo();
remoteEpisode.ParsedEpisodeInfo.Quality = quality; remoteAlbum.ParsedAlbumInfo.Quality = quality;
remoteEpisode.Episodes = new List<Episode>(); remoteAlbum.Albums = new List<Album>();
remoteEpisode.Episodes.AddRange(episodes); remoteAlbum.Albums.AddRange(albums);
remoteEpisode.Release = new ReleaseInfo(); remoteAlbum.Release = new ReleaseInfo();
remoteEpisode.Release.PublishDate = DateTime.Now.AddDays(-age); remoteAlbum.Release.PublishDate = DateTime.Now.AddDays(-age);
remoteEpisode.Release.Size = size; remoteAlbum.Release.Size = size;
remoteEpisode.Release.DownloadProtocol = downloadProtocol; remoteAlbum.Release.DownloadProtocol = downloadProtocol;
remoteEpisode.Series = Builder<Series>.CreateNew() remoteAlbum.Artist = Builder<Artist>.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
return remoteEpisode; return remoteAlbum;
} }
private void GivenPreferredDownloadProtocol(DownloadProtocol downloadProtocol) private void GivenPreferredDownloadProtocol(DownloadProtocol downloadProtocol)
@ -68,103 +67,75 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_put_propers_before_non_propers() public void should_put_propers_before_non_propers()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256, new Revision(version: 1))); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256, new Revision(version: 1)));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256, new Revision(version: 2))); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256, new Revision(version: 2)));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version.Should().Be(2); qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.Quality.Revision.Version.Should().Be(2);
} }
[Test] [Test]
public void should_put_higher_quality_before_lower() public void should_put_higher_quality_before_lower()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_192)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_192));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Quality.Should().Be(Quality.MP3_256); qualifiedReports.First().RemoteAlbum.ParsedAlbumInfo.Quality.Quality.Should().Be(Quality.MP3_256);
}
[Test]
public void should_order_by_lowest_number_of_episodes()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(2) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
}
[Test]
public void should_order_by_lowest_number_of_episodes_with_multiple_episodes()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(2), GivenEpisode(3) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.MP3_256));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
} }
[Test] [Test]
public void should_order_by_age_then_largest_rounded_to_200mb() public void should_order_by_age_then_largest_rounded_to_200mb()
{ {
var remoteEpisodeSd = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_192), size: 100.Megabytes(), age: 1); var remoteAlbumSd = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_192), size: 100.Megabytes(), age: 1);
var remoteEpisodeHdSmallOld = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), size: 1200.Megabytes(), age: 1000); var remoteAlbumHdSmallOld = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), size: 1200.Megabytes(), age: 1000);
var remoteEpisodeSmallYoung = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), size: 1250.Megabytes(), age: 10); var remoteAlbumSmallYoung = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), size: 1250.Megabytes(), age: 10);
var remoteEpisodeHdLargeYoung = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), size: 3000.Megabytes(), age: 1); var remoteAlbumHdLargeYoung = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), size: 3000.Megabytes(), age: 1);
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisodeSd)); decisions.Add(new DownloadDecision(remoteAlbumSd));
decisions.Add(new DownloadDecision(remoteEpisodeHdSmallOld)); decisions.Add(new DownloadDecision(remoteAlbumHdSmallOld));
decisions.Add(new DownloadDecision(remoteEpisodeSmallYoung)); decisions.Add(new DownloadDecision(remoteAlbumSmallYoung));
decisions.Add(new DownloadDecision(remoteEpisodeHdLargeYoung)); decisions.Add(new DownloadDecision(remoteAlbumHdLargeYoung));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdLargeYoung); qualifiedReports.First().RemoteAlbum.Should().Be(remoteAlbumHdLargeYoung);
} }
[Test] [Test]
public void should_order_by_youngest() public void should_order_by_youngest()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), age: 10); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), age: 10);
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), age: 5); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), age: 5);
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisode2); qualifiedReports.First().RemoteAlbum.Should().Be(remoteAlbum2);
} }
[Test] [Test]
public void should_not_throw_if_no_episodes_are_found() public void should_not_throw_if_no_episodes_are_found()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), size: 500.Megabytes()); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), size: 500.Megabytes());
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), size: 500.Megabytes()); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), size: 500.Megabytes());
remoteEpisode1.Episodes = new List<Episode>(); remoteAlbum1.Albums = new List<Album>();
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
Subject.PrioritizeDecisions(decisions); Subject.PrioritizeDecisions(decisions);
} }
@ -174,15 +145,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenPreferredDownloadProtocol(DownloadProtocol.Usenet); GivenPreferredDownloadProtocol(DownloadProtocol.Usenet);
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Torrent); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Torrent);
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Usenet); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Usenet);
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Release.DownloadProtocol.Should().Be(DownloadProtocol.Usenet); qualifiedReports.First().RemoteAlbum.Release.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
} }
[Test] [Test]
@ -190,69 +161,36 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenPreferredDownloadProtocol(DownloadProtocol.Torrent); GivenPreferredDownloadProtocol(DownloadProtocol.Torrent);
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Torrent); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Torrent);
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Usenet); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256), downloadProtocol: DownloadProtocol.Usenet);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Release.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
}
[Test]
public void should_prefer_season_pack_above_single_episode()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256));
remoteEpisode1.ParsedEpisodeInfo.FullSeason = true;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.FullSeason.Should().BeTrue();
}
[Test]
public void should_prefer_multiepisode_over_single_episode_for_anime()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256));
remoteEpisode1.Series.SeriesType = SeriesTypes.Anime;
remoteEpisode2.Series.SeriesType = SeriesTypes.Anime;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.Count.Should().Be(remoteEpisode1.Episodes.Count); qualifiedReports.First().RemoteAlbum.Release.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
} }
[Test] [Test]
public void should_prefer_single_episode_over_multi_episode_for_non_anime() public void should_prefer_single_album_over_multi_album()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1), GivenAlbum(2) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.Count.Should().Be(remoteEpisode2.Episodes.Count); qualifiedReports.First().RemoteAlbum.Albums.Count.Should().Be(remoteAlbum2.Albums.Count);
} }
[Test] [Test]
public void should_prefer_releases_with_more_seeders() public void should_prefer_releases_with_more_seeders()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var torrentInfo1 = new TorrentInfo(); var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now; torrentInfo1.PublishDate = DateTime.Now;
@ -263,22 +201,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var torrentInfo2 = torrentInfo1.JsonClone(); var torrentInfo2 = torrentInfo1.JsonClone();
torrentInfo2.Seeders = 100; torrentInfo2.Seeders = 100;
remoteEpisode1.Release = torrentInfo1; remoteAlbum1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2; remoteAlbum2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo) qualifiedReports.First().RemoteEpisode.Release).Seeders.Should().Be(torrentInfo2.Seeders); ((TorrentInfo) qualifiedReports.First().RemoteAlbum.Release).Seeders.Should().Be(torrentInfo2.Seeders);
} }
[Test] [Test]
public void should_prefer_releases_with_more_peers_given_equal_number_of_seeds() public void should_prefer_releases_with_more_peers_given_equal_number_of_seeds()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var torrentInfo1 = new TorrentInfo(); var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now; torrentInfo1.PublishDate = DateTime.Now;
@ -291,22 +229,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var torrentInfo2 = torrentInfo1.JsonClone(); var torrentInfo2 = torrentInfo1.JsonClone();
torrentInfo2.Peers = 100; torrentInfo2.Peers = 100;
remoteEpisode1.Release = torrentInfo1; remoteAlbum1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2; remoteAlbum2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo)qualifiedReports.First().RemoteEpisode.Release).Peers.Should().Be(torrentInfo2.Peers); ((TorrentInfo)qualifiedReports.First().RemoteAlbum.Release).Peers.Should().Be(torrentInfo2.Peers);
} }
[Test] [Test]
public void should_prefer_releases_with_more_peers_no_seeds() public void should_prefer_releases_with_more_peers_no_seeds()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var torrentInfo1 = new TorrentInfo(); var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now; torrentInfo1.PublishDate = DateTime.Now;
@ -320,22 +258,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
torrentInfo2.Seeders = 0; torrentInfo2.Seeders = 0;
torrentInfo2.Peers = 100; torrentInfo2.Peers = 100;
remoteEpisode1.Release = torrentInfo1; remoteAlbum1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2; remoteAlbum2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo)qualifiedReports.First().RemoteEpisode.Release).Peers.Should().Be(torrentInfo2.Peers); ((TorrentInfo)qualifiedReports.First().RemoteAlbum.Release).Peers.Should().Be(torrentInfo2.Peers);
} }
[Test] [Test]
public void should_prefer_first_release_if_peers_and_size_are_too_similar() public void should_prefer_first_release_if_peers_and_size_are_too_similar()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var torrentInfo1 = new TorrentInfo(); var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now; torrentInfo1.PublishDate = DateTime.Now;
@ -349,42 +287,42 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
torrentInfo2.Peers = 10; torrentInfo2.Peers = 10;
torrentInfo1.Size = 250.Megabytes(); torrentInfo1.Size = 250.Megabytes();
remoteEpisode1.Release = torrentInfo1; remoteAlbum1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2; remoteAlbum2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo) qualifiedReports.First().RemoteEpisode.Release).Should().Be(torrentInfo1); ((TorrentInfo) qualifiedReports.First().RemoteAlbum.Release).Should().Be(torrentInfo1);
} }
[Test] [Test]
public void should_prefer_first_release_if_age_and_size_are_too_similar() public void should_prefer_first_release_if_age_and_size_are_too_similar()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_256)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_256));
remoteEpisode1.Release.PublishDate = DateTime.UtcNow.AddDays(-100); remoteAlbum1.Release.PublishDate = DateTime.UtcNow.AddDays(-100);
remoteEpisode1.Release.Size = 200.Megabytes(); remoteAlbum1.Release.Size = 200.Megabytes();
remoteEpisode2.Release.PublishDate = DateTime.UtcNow.AddDays(-150); remoteAlbum2.Release.PublishDate = DateTime.UtcNow.AddDays(-150);
remoteEpisode2.Release.Size = 250.Megabytes(); remoteAlbum2.Release.Size = 250.Megabytes();
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Release.Should().Be(remoteEpisode1.Release); qualifiedReports.First().RemoteAlbum.Release.Should().Be(remoteAlbum1.Release);
} }
[Test] [Test]
public void should_prefer_quality_over_the_number_of_peers() public void should_prefer_quality_over_the_number_of_peers()
{ {
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_512)); var remoteAlbum1 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_512));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.MP3_192)); var remoteAlbum2 = GivenRemoteAlbum(new List<Album> { GivenAlbum(1) }, new QualityModel(Quality.MP3_192));
var torrentInfo1 = new TorrentInfo(); var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now; torrentInfo1.PublishDate = DateTime.Now;
@ -398,15 +336,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
torrentInfo2.Peers = 10; torrentInfo2.Peers = 10;
torrentInfo1.Size = 250.Megabytes(); torrentInfo1.Size = 250.Megabytes();
remoteEpisode1.Release = torrentInfo1; remoteAlbum1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2; remoteAlbum2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo)qualifiedReports.First().RemoteEpisode.Release).Should().Be(torrentInfo1); ((TorrentInfo)qualifiedReports.First().RemoteAlbum.Release).Should().Be(torrentInfo1);
} }
} }
} }

@ -7,22 +7,22 @@ using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
[TestFixture] [TestFixture]
public class ProtocolSpecificationFixture : CoreTest<ProtocolSpecification> public class ProtocolSpecificationFixture : CoreTest<ProtocolSpecification>
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
private DelayProfile _delayProfile; private DelayProfile _delayProfile;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode(); _remoteAlbum = new RemoteAlbum();
_remoteEpisode.Release = new ReleaseInfo(); _remoteAlbum.Release = new ReleaseInfo();
_remoteEpisode.Series = new Series(); _remoteAlbum.Artist = new Artist();
_delayProfile = new DelayProfile(); _delayProfile = new DelayProfile();
@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void GivenProtocol(DownloadProtocol downloadProtocol) private void GivenProtocol(DownloadProtocol downloadProtocol)
{ {
_remoteEpisode.Release.DownloadProtocol = downloadProtocol; _remoteAlbum.Release.DownloadProtocol = downloadProtocol;
} }
[Test] [Test]
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenProtocol(DownloadProtocol.Usenet); GivenProtocol(DownloadProtocol.Usenet);
_delayProfile.EnableUsenet = true; _delayProfile.EnableUsenet = true;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().Be(true); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().Be(true);
} }
[Test] [Test]
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenProtocol(DownloadProtocol.Torrent); GivenProtocol(DownloadProtocol.Torrent);
_delayProfile.EnableTorrent = true; _delayProfile.EnableTorrent = true;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().Be(true); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().Be(true);
} }
[Test] [Test]
@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenProtocol(DownloadProtocol.Usenet); GivenProtocol(DownloadProtocol.Usenet);
_delayProfile.EnableUsenet = false; _delayProfile.EnableUsenet = false;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().Be(false); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().Be(false);
} }
[Test] [Test]
@ -69,7 +69,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenProtocol(DownloadProtocol.Torrent); GivenProtocol(DownloadProtocol.Torrent);
_delayProfile.EnableTorrent = false; _delayProfile.EnableTorrent = false;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().Be(false); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().Be(false);
} }
} }
} }

@ -6,7 +6,7 @@ using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class QualityAllowedByProfileSpecificationFixture : CoreTest<QualityAllowedByProfileSpecification> public class QualityAllowedByProfileSpecificationFixture : CoreTest<QualityAllowedByProfileSpecification>
{ {
private RemoteEpisode remoteEpisode; private RemoteAlbum remoteAlbum;
public static object[] AllowedTestCases = public static object[] AllowedTestCases =
{ {
@ -26,41 +26,41 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public static object[] DeniedTestCases = public static object[] DeniedTestCases =
{ {
new object[] { Quality.MP3_192 }, new object[] { Quality.MP3_VBR },
new object[] { Quality.MP3_320 }, new object[] { Quality.FLAC },
new object[] { Quality.MP3_320 } new object[] { Quality.Unknown }
}; };
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
var fakeSeries = Builder<Series>.CreateNew() var fakeArtist = Builder<Artist>.CreateNew()
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.MP3_512 }) .With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.MP3_512 })
.Build(); .Build();
remoteEpisode = new RemoteEpisode remoteAlbum = new RemoteAlbum
{ {
Series = fakeSeries, Artist = fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) },
}; };
} }
[Test, TestCaseSource(nameof(AllowedTestCases))] [Test, TestCaseSource(nameof(AllowedTestCases))]
public void should_allow_if_quality_is_defined_in_profile(Quality qualityType) public void should_allow_if_quality_is_defined_in_profile(Quality qualityType)
{ {
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; remoteAlbum.ParsedAlbumInfo.Quality.Quality = qualityType;
remoteEpisode.Series.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_192, Quality.MP3_256, Quality.MP3_512); remoteAlbum.Artist.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_192, Quality.MP3_256, Quality.MP3_512);
Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test, TestCaseSource(nameof(DeniedTestCases))] [Test, TestCaseSource(nameof(DeniedTestCases))]
public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType) public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType)
{ {
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; remoteAlbum.ParsedAlbumInfo.Quality.Quality = qualityType;
remoteEpisode.Series.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_192, Quality.MP3_256, Quality.MP3_512); remoteAlbum.Artist.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_192, Quality.MP3_256, Quality.MP3_512);
Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -9,7 +9,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Queue; using NzbDrone.Core.Queue;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
@ -17,41 +17,39 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[TestFixture] [TestFixture]
public class QueueSpecificationFixture : CoreTest<QueueSpecification> public class QueueSpecificationFixture : CoreTest<QueueSpecification>
{ {
private Series _series; private Artist _artist;
private Episode _episode; private Album _album;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
private Series _otherSeries; private Artist _otherArtist;
private Episode _otherEpisode; private Album _otherAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.Resolve<QualityUpgradableSpecification>(); Mocker.Resolve<QualityUpgradableSpecification>();
_series = Builder<Series>.CreateNew() _artist = Builder<Artist>.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.With(e => e.SeriesId = _series.Id) .With(e => e.ArtistId = _artist.Id)
.Build(); .Build();
_otherSeries = Builder<Series>.CreateNew() _otherArtist = Builder<Artist>.CreateNew()
.With(s => s.Id = 2) .With(s => s.Id = 2)
.Build(); .Build();
_otherEpisode = Builder<Episode>.CreateNew() _otherAlbum = Builder<Album>.CreateNew()
.With(e => e.SeriesId = _otherSeries.Id) .With(e => e.ArtistId = _otherArtist.Id)
.With(e => e.Id = 2) .With(e => e.Id = 2)
.With(e => e.SeasonNumber = 2)
.With(e => e.EpisodeNumber = 2)
.Build(); .Build();
_remoteEpisode = Builder<RemoteEpisode>.CreateNew() _remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192) }) .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_192) })
.Build(); .Build();
} }
@ -62,11 +60,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(new List<Queue.Queue>()); .Returns(new List<Queue.Queue>());
} }
private void GivenQueue(IEnumerable<RemoteEpisode> remoteEpisodes) private void GivenQueue(IEnumerable<RemoteAlbum> remoteAlbums)
{ {
var queue = remoteEpisodes.Select(remoteEpisode => new Queue.Queue var queue = remoteAlbums.Select(remoteAlbum => new Queue.Queue
{ {
RemoteEpisode = remoteEpisode RemoteAlbum = remoteAlbum
}); });
Mocker.GetMock<IQueueService>() Mocker.GetMock<IQueueService>()
@ -78,181 +76,181 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_true_when_queue_is_empty() public void should_return_true_when_queue_is_empty()
{ {
GivenEmptyQueue(); GivenEmptyQueue();
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_when_series_doesnt_match() public void should_return_true_when_series_doesnt_match()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _otherSeries) .With(r => r.Artist = _otherArtist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_when_quality_in_queue_is_lower() public void should_return_true_when_quality_in_queue_is_lower()
{ {
_series.Profile.Value.Cutoff = Quality.MP3_512; _artist.Profile.Value.Cutoff = Quality.MP3_512;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_192) Quality = new QualityModel(Quality.MP3_192)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_when_episode_doesnt_match() public void should_return_true_when_album_doesnt_match()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _otherEpisode }) .With(r => r.Albums = new List<Album> { _otherAlbum })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_192) Quality = new QualityModel(Quality.MP3_192)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_false_when_qualities_are_the_same() public void should_return_false_when_qualities_are_the_same()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_192) Quality = new QualityModel(Quality.MP3_192)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_when_quality_in_queue_is_better() public void should_return_false_when_quality_in_queue_is_better()
{ {
_series.Profile.Value.Cutoff = Quality.MP3_512; _artist.Profile.Value.Cutoff = Quality.MP3_512;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_256) Quality = new QualityModel(Quality.MP3_256)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_matching_multi_episode_is_in_queue() public void should_return_false_if_matching_multi_album_is_in_queue()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode, _otherEpisode }) .With(r => r.Albums = new List<Album> { _album, _otherAlbum })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_256) Quality = new QualityModel(Quality.MP3_256)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_multi_episode_has_one_episode_in_queue() public void should_return_false_if_multi_album_has_one_album_in_queue()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_256) Quality = new QualityModel(Quality.MP3_256)
}) })
.Build(); .Build();
_remoteEpisode.Episodes.Add(_otherEpisode); _remoteAlbum.Albums.Add(_otherAlbum);
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_multi_part_episode_is_already_in_queue() public void should_return_false_if_multi_part_album_is_already_in_queue()
{ {
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode, _otherEpisode }) .With(r => r.Albums = new List<Album> { _album, _otherAlbum })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_256) Quality = new QualityModel(Quality.MP3_256)
}) })
.Build(); .Build();
_remoteEpisode.Episodes.Add(_otherEpisode); _remoteAlbum.Albums.Add(_otherAlbum);
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_multi_part_episode_has_two_episodes_in_queue() public void should_return_false_if_multi_part_album_has_two_episodes_in_queue()
{ {
var remoteEpisodes = Builder<RemoteEpisode>.CreateListOfSize(2) var remoteAlbums = Builder<RemoteAlbum>.CreateListOfSize(2)
.All() .All()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = Quality =
new QualityModel( new QualityModel(
Quality.MP3_256) Quality.MP3_256)
}) })
.TheFirst(1) .TheFirst(1)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.TheNext(1) .TheNext(1)
.With(r => r.Episodes = new List<Episode> { _otherEpisode }) .With(r => r.Albums = new List<Album> { _otherAlbum })
.Build(); .Build();
_remoteEpisode.Episodes.Add(_otherEpisode); _remoteAlbum.Albums.Add(_otherAlbum);
GivenQueue(remoteEpisodes); GivenQueue(remoteAlbums);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_quality_in_queue_meets_cutoff() public void should_return_false_if_quality_in_queue_meets_cutoff()
{ {
_series.Profile.Value.Cutoff = _remoteEpisode.ParsedEpisodeInfo.Quality.Quality; _artist.Profile.Value.Cutoff = _remoteAlbum.ParsedAlbumInfo.Quality.Quality;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Artist = _artist)
.With(r => r.Episodes = new List<Episode> { _episode }) .With(r => r.Albums = new List<Album> { _album })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo .With(r => r.ParsedAlbumInfo = new ParsedAlbumInfo
{ {
Quality = new QualityModel(Quality.MP3_256) Quality = new QualityModel(Quality.MP3_256)
}) })
.Build(); .Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode }); GivenQueue(new List<RemoteAlbum> { remoteAlbum });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -2,7 +2,6 @@
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
@ -12,12 +11,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class RawDiskSpecificationFixture : CoreTest<RawDiskSpecification> public class RawDiskSpecificationFixture : CoreTest<RawDiskSpecification>
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode _remoteAlbum = new RemoteAlbum
{ {
Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Torrent } Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Torrent }
}; };
@ -25,48 +24,41 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithContainer(string container) private void WithContainer(string container)
{ {
_remoteEpisode.Release.Container = container; _remoteAlbum.Release.Container = container;
} }
[Test] [Test]
public void should_return_true_if_no_container_specified() public void should_return_true_if_no_container_specified()
{ {
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_if_mkv() public void should_return_true_if_flac()
{ {
WithContainer("MKV"); WithContainer("FLAC");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_false_if_vob() public void should_return_false_if_vob()
{ {
WithContainer("VOB"); WithContainer("VOB");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_iso() public void should_return_false_if_iso()
{ {
WithContainer("ISO"); WithContainer("ISO");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
}
[Test]
public void should_return_false_if_m2ts()
{
WithContainer("M2TS");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_compare_case_insensitive() public void should_compare_case_insensitive()
{ {
WithContainer("vob"); WithContainer("vob");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }

@ -6,21 +6,21 @@ using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Restrictions; using NzbDrone.Core.Restrictions;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
[TestFixture] [TestFixture]
public class ReleaseRestrictionsSpecificationFixture : CoreTest<ReleaseRestrictionsSpecification> public class ReleaseRestrictionsSpecificationFixture : CoreTest<ReleaseRestrictionsSpecification>
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode _remoteAlbum = new RemoteAlbum
{ {
Series = new Series Artist = new Artist
{ {
Tags = new HashSet<int>() Tags = new HashSet<int>()
}, },
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>())) .Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
.Returns(new List<Restriction>()); .Returns(new List<Restriction>());
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions("WEBRip", null); GivenRestictions("WEBRip", null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions("doesnt,exist", null); GivenRestictions("doesnt,exist", null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions(null, "ignored"); GivenRestictions(null, "ignored");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions(null, "edited"); GivenRestictions(null, "edited");
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[TestCase("EdiTED")] [TestCase("EdiTED")]
@ -95,7 +95,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions(required, null); GivenRestictions(required, null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[TestCase("EdiTED")] [TestCase("EdiTED")]
@ -106,22 +106,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenRestictions(null, ignored); GivenRestictions(null, ignored);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_false_when_release_contains_one_restricted_word_and_one_required_word() public void should_be_false_when_release_contains_one_restricted_word_and_one_required_word()
{ {
_remoteEpisode.Release.Title = "[ www.Speed.cd ] -Whose.Line.is.it.Anyway.US.S10E24.720p.HDTV.x264-BAJSKORV"; _remoteAlbum.Release.Title = "[ www.Speed.cd ] - Katy Perry - Witness (2017) MP3 [320 kbps] ";
Mocker.GetMock<IRestrictionService>() Mocker.GetMock<IRestrictionService>()
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>())) .Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
.Returns(new List<Restriction> .Returns(new List<Restriction>
{ {
new Restriction { Required = "x264", Ignored = "www.Speed.cd" } new Restriction { Required = "320", Ignored = "www.Speed.cd" }
}); });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -13,12 +13,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class RetentionSpecificationFixture : CoreTest<RetentionSpecification> public class RetentionSpecificationFixture : CoreTest<RetentionSpecification>
{ {
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = new RemoteEpisode _remoteAlbum = new RemoteAlbum
{ {
Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Usenet } Release = new ReleaseInfo() { DownloadProtocol = DownloadProtocol.Usenet }
}; };
@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithAge(int days) private void WithAge(int days)
{ {
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddDays(-days); _remoteAlbum.Release.PublishDate = DateTime.UtcNow.AddDays(-days);
} }
[Test] [Test]
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithRetention(0); WithRetention(0);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithRetention(1000); WithRetention(1000);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithRetention(100); WithRetention(100);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithRetention(10); WithRetention(10);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
@ -76,18 +76,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
WithRetention(0); WithRetention(0);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_when_release_is_not_usenet() public void should_return_true_when_release_is_not_usenet()
{ {
_remoteEpisode.Release.DownloadProtocol = DownloadProtocol.Torrent; _remoteAlbum.Release.DownloadProtocol = DownloadProtocol.Torrent;
WithRetention(10); WithRetention(10);
WithAge(100); WithAge(100);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
} }
} }

@ -17,7 +17,7 @@ using NzbDrone.Core.Profiles;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{ {
@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{ {
private Profile _profile; private Profile _profile;
private DelayProfile _delayProfile; private DelayProfile _delayProfile;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -38,12 +38,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
.With(d => d.PreferredProtocol = DownloadProtocol.Usenet) .With(d => d.PreferredProtocol = DownloadProtocol.Usenet)
.Build(); .Build();
var series = Builder<Series>.CreateNew() var artist = Builder<Artist>.CreateNew()
.With(s => s.Profile = _profile) .With(s => s.Profile = _profile)
.Build(); .Build();
_remoteEpisode = Builder<RemoteEpisode>.CreateNew() _remoteAlbum = Builder<RemoteAlbum>.CreateNew()
.With(r => r.Series = series) .With(r => r.Artist = artist)
.Build(); .Build();
_profile.Items = new List<ProfileQualityItem>(); _profile.Items = new List<ProfileQualityItem>();
@ -53,30 +53,30 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_profile.Cutoff = Quality.MP3_320; _profile.Cutoff = Quality.MP3_320;
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo(); _remoteAlbum.ParsedAlbumInfo = new ParsedAlbumInfo();
_remoteEpisode.Release = new ReleaseInfo(); _remoteAlbum.Release = new ReleaseInfo();
_remoteEpisode.Release.DownloadProtocol = DownloadProtocol.Usenet; _remoteAlbum.Release.DownloadProtocol = DownloadProtocol.Usenet;
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1).Build().ToList(); _remoteAlbum.Albums = Builder<Album>.CreateListOfSize(1).Build().ToList();
_remoteEpisode.Episodes.First().EpisodeFileId = 0;
Mocker.GetMock<IMediaFileService>()
.Setup(s => s.GetFilesByAlbum(It.IsAny<int>(), It.IsAny<int>()))
.Returns(new List<TrackFile> {});
Mocker.GetMock<IDelayProfileService>() Mocker.GetMock<IDelayProfileService>()
.Setup(s => s.BestForTags(It.IsAny<HashSet<int>>())) .Setup(s => s.BestForTags(It.IsAny<HashSet<int>>()))
.Returns(_delayProfile); .Returns(_delayProfile);
Mocker.GetMock<IPendingReleaseService>() Mocker.GetMock<IPendingReleaseService>()
.Setup(s => s.GetPendingRemoteEpisodes(It.IsAny<int>())) .Setup(s => s.GetPendingRemoteAlbums(It.IsAny<int>()))
.Returns(new List<RemoteEpisode>()); .Returns(new List<RemoteAlbum>());
} }
private void GivenExistingFile(QualityModel quality) private void GivenExistingFile(QualityModel quality)
{ {
_remoteEpisode.Episodes.First().EpisodeFileId = 1; Mocker.GetMock<IMediaFileService>()
.Setup(s => s.GetFilesByAlbum(It.IsAny<int>(), It.IsAny<int>()))
_remoteEpisode.Episodes.First().EpisodeFile = new LazyLoaded<EpisodeFile>(new EpisodeFile .Returns(new List<TrackFile> { new TrackFile { Quality = quality } });
{
Quality = quality
});
} }
private void GivenUpgradeForExistingFile() private void GivenUpgradeForExistingFile()
@ -89,18 +89,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_be_true_when_user_invoked_search() public void should_be_true_when_user_invoked_search()
{ {
Subject.IsSatisfiedBy(new RemoteEpisode(), new SingleEpisodeSearchCriteria { UserInvokedSearch = true }).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(new RemoteAlbum(), new AlbumSearchCriteria { UserInvokedSearch = true }).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_false_when_system_invoked_search_and_release_is_younger_than_delay() public void should_be_false_when_system_invoked_search_and_release_is_younger_than_delay()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_192); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_192);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteAlbum.Release.PublishDate = DateTime.UtcNow;
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, new SingleEpisodeSearchCriteria()).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, new AlbumSearchCriteria()).Accepted.Should().BeFalse();
} }
[Test] [Test]
@ -108,44 +108,44 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{ {
_delayProfile.UsenetDelay = 0; _delayProfile.UsenetDelay = 0;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_quality_is_last_allowed_in_profile() public void should_be_true_when_quality_is_last_allowed_in_profile()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_320); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_release_is_older_than_delay() public void should_be_true_when_release_is_older_than_delay()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow.AddHours(-10); _remoteAlbum.Release.PublishDate = DateTime.UtcNow.AddHours(-10);
_delayProfile.UsenetDelay = 60; _delayProfile.UsenetDelay = 60;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_false_when_release_is_younger_than_delay() public void should_be_false_when_release_is_younger_than_delay()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_192); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_192);
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteAlbum.Release.PublishDate = DateTime.UtcNow;
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_true_when_release_is_a_proper_for_existing_episode() public void should_be_true_when_release_is_a_proper_for_existing_album()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteAlbum.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.MP3_256)); GivenExistingFile(new QualityModel(Quality.MP3_256));
GivenUpgradeForExistingFile(); GivenUpgradeForExistingFile();
@ -156,14 +156,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_true_when_release_is_a_real_for_existing_episode() public void should_be_true_when_release_is_a_real_for_existing_album()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(real: 1)); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(real: 1));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteAlbum.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.MP3_256)); GivenExistingFile(new QualityModel(Quality.MP3_256));
GivenUpgradeForExistingFile(); GivenUpgradeForExistingFile();
@ -174,20 +174,20 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_false_when_release_is_proper_for_existing_episode_of_different_quality() public void should_be_false_when_release_is_proper_for_existing_album_of_different_quality()
{ {
_remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)); _remoteAlbum.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2));
_remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteAlbum.Release.PublishDate = DateTime.UtcNow;
GivenExistingFile(new QualityModel(Quality.MP3_192)); GivenExistingFile(new QualityModel(Quality.MP3_192));
_delayProfile.UsenetDelay = 720; _delayProfile.UsenetDelay = 720;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -3,6 +3,7 @@ using System.Collections.Generic;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using Moq;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine.Specifications.RssSync; using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@ -10,7 +11,7 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -21,38 +22,43 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
public class ProperSpecificationFixture : CoreTest<ProperSpecification> public class ProperSpecificationFixture : CoreTest<ProperSpecification>
{ {
private RemoteEpisode _parseResultMulti; private RemoteAlbum _parseResultMulti;
private RemoteEpisode _parseResultSingle; private RemoteAlbum _parseResultSingle;
private EpisodeFile _firstFile; private TrackFile _firstFile;
private EpisodeFile _secondFile; private TrackFile _secondFile;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.Resolve<QualityUpgradableSpecification>(); Mocker.Resolve<QualityUpgradableSpecification>();
_firstFile = new EpisodeFile { Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1)), DateAdded = DateTime.Now }; _firstFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)), DateAdded = DateTime.Now };
_secondFile = new EpisodeFile { Quality = new QualityModel(Quality.MP3_512, new Revision(version: 1)), DateAdded = DateTime.Now }; _secondFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)), DateAdded = DateTime.Now };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } }; var singleEpisodeList = new List<Album> { new Album {}, new Album {} };
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } }; var doubleEpisodeList = new List<Album> { new Album {}, new Album {}, new Album {} };
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.MP3_512 }) var fakeArtist = Builder<Artist>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.FLAC })
.Build(); .Build();
_parseResultMulti = new RemoteEpisode Mocker.GetMock<IMediaFileService>()
.Setup(c => c.GetFilesByAlbum(It.IsAny<int>(), It.IsAny<int>()))
.Returns(new List<TrackFile> { _firstFile, _secondFile });
_parseResultMulti = new RemoteAlbum
{ {
Series = fakeSeries, Artist = fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
Episodes = doubleEpisodeList Albums = doubleEpisodeList
}; };
_parseResultSingle = new RemoteEpisode _parseResultSingle = new RemoteAlbum
{ {
Series = fakeSeries, Artist = fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
Episodes = singleEpisodeList Albums = singleEpisodeList
}; };
} }
@ -69,36 +75,36 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
} }
[Test] [Test]
public void should_return_false_when_episodeFile_was_added_more_than_7_days_ago() public void should_return_false_when_trackFile_was_added_more_than_7_days_ago()
{ {
_firstFile.Quality.Quality = Quality.MP3_192; _firstFile.Quality.Quality = Quality.MP3_256;
_firstFile.DateAdded = DateTime.Today.AddDays(-30); _firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_when_first_episodeFile_was_added_more_than_7_days_ago() public void should_return_false_when_first_trackFile_was_added_more_than_7_days_ago()
{ {
_firstFile.Quality.Quality = Quality.MP3_192; _firstFile.Quality.Quality = Quality.MP3_256;
_secondFile.Quality.Quality = Quality.MP3_192; _secondFile.Quality.Quality = Quality.MP3_256;
_firstFile.DateAdded = DateTime.Today.AddDays(-30); _firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_when_second_episodeFile_was_added_more_than_7_days_ago() public void should_return_false_when_second_trackFile_was_added_more_than_7_days_ago()
{ {
_firstFile.Quality.Quality = Quality.MP3_192; _firstFile.Quality.Quality = Quality.MP3_256;
_secondFile.Quality.Quality = Quality.MP3_192; _secondFile.Quality.Quality = Quality.MP3_256;
_secondFile.DateAdded = DateTime.Today.AddDays(-30); _secondFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_proper_is_for_better_quality() public void should_return_true_when_trackFile_was_added_more_than_7_days_ago_but_proper_is_for_better_quality()
{ {
WithFirstFileUpgradable(); WithFirstFileUpgradable();
@ -107,7 +113,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
} }
[Test] [Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_is_for_search() public void should_return_true_when_trackFile_was_added_more_than_7_days_ago_but_is_for_search()
{ {
WithFirstFileUpgradable(); WithFirstFileUpgradable();
@ -118,18 +124,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_false_when_proper_but_auto_download_propers_is_false() public void should_return_false_when_proper_but_auto_download_propers_is_false()
{ {
_firstFile.Quality.Quality = Quality.MP3_192; _firstFile.Quality.Quality = Quality.MP3_256;
_firstFile.DateAdded = DateTime.Today; _firstFile.DateAdded = DateTime.Today;
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_true_when_episodeFile_was_added_today() public void should_return_true_when_trackFile_was_added_today()
{ {
GivenAutoDownloadPropers(); GivenAutoDownloadPropers();
_firstFile.Quality.Quality = Quality.MP3_192; _firstFile.Quality.Quality = Quality.MP3_256;
_firstFile.DateAdded = DateTime.Today; _firstFile.DateAdded = DateTime.Today;
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();

@ -0,0 +1,46 @@
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications.Search;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Music;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.DecisionEngineTests.Search
{
[TestFixture]
public class ArtistSpecificationFixture : TestBase<ArtistSpecification>
{
private Artist _artist1;
private Artist _artist2;
private RemoteAlbum _remoteAlbum = new RemoteAlbum();
private SearchCriteriaBase _searchCriteria = new AlbumSearchCriteria();
[SetUp]
public void Setup()
{
_artist1 = Builder<Artist>.CreateNew().With(s => s.Id = 1).Build();
_artist2 = Builder<Artist>.CreateNew().With(s => s.Id = 2).Build();
_remoteAlbum.Artist = _artist1;
}
[Test]
public void should_return_false_if_artist_doesnt_match()
{
_searchCriteria.Artist = _artist2;
Subject.IsSatisfiedBy(_remoteAlbum, _searchCriteria).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_when_artist_ids_match()
{
_searchCriteria.Artist = _artist1;
Subject.IsSatisfiedBy(_remoteAlbum, _searchCriteria).Accepted.Should().BeTrue();
}
}
}

@ -1,45 +0,0 @@
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications.Search;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.DecisionEngineTests.Search
{
[TestFixture]
public class SeriesSpecificationFixture : TestBase<SeriesSpecification>
{
private Series _series1;
private Series _series2;
private RemoteEpisode _remoteEpisode = new RemoteEpisode();
private SearchCriteriaBase _searchCriteria = new SingleEpisodeSearchCriteria();
[SetUp]
public void Setup()
{
_series1 = Builder<Series>.CreateNew().With(s => s.Id = 1).Build();
_series2 = Builder<Series>.CreateNew().With(s => s.Id = 2).Build();
_remoteEpisode.Series = _series1;
}
[Test]
public void should_return_false_if_series_doesnt_match()
{
_searchCriteria.Series = _series2;
Subject.IsSatisfiedBy(_remoteEpisode, _searchCriteria).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_when_series_ids_match()
{
_searchCriteria.Series = _series1;
Subject.IsSatisfiedBy(_remoteEpisode, _searchCriteria).Accepted.Should().BeTrue();
}
}
}

@ -3,14 +3,14 @@ using System.Collections.Generic;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using Moq;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
@ -19,42 +19,44 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class UpgradeDiskSpecificationFixture : CoreTest<UpgradeDiskSpecification> public class UpgradeDiskSpecificationFixture : CoreTest<UpgradeDiskSpecification>
{ {
private UpgradeDiskSpecification _upgradeDisk; private RemoteAlbum _parseResultMulti;
private RemoteAlbum _parseResultSingle;
private RemoteEpisode _parseResultMulti; private TrackFile _firstFile;
private RemoteEpisode _parseResultSingle; private TrackFile _secondFile;
private EpisodeFile _firstFile;
private EpisodeFile _secondFile;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.Resolve<QualityUpgradableSpecification>(); Mocker.Resolve<QualityUpgradableSpecification>();
_upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>();
_firstFile = new EpisodeFile { Quality = new QualityModel(Quality.MP3_512, new Revision(version: 2)), DateAdded = DateTime.Now }; _firstFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 2)), DateAdded = DateTime.Now };
_secondFile = new EpisodeFile { Quality = new QualityModel(Quality.MP3_512, new Revision(version: 2)), DateAdded = DateTime.Now }; _secondFile = new TrackFile { Quality = new QualityModel(Quality.FLAC, new Revision(version: 2)), DateAdded = DateTime.Now };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } }; var singleEpisodeList = new List<Album> { new Album {}};
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } }; var doubleEpisodeList = new List<Album> { new Album {}, new Album {}, new Album {} };
var fakeSeries = Builder<Series>.CreateNew() var fakeArtist = Builder<Artist>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(c => c.Profile = new Profile { Cutoff = Quality.MP3_512, Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
_parseResultMulti = new RemoteEpisode Mocker.GetMock<IMediaFileService>()
.Setup(c => c.GetFilesByAlbum(It.IsAny<int>(), It.IsAny<int>()))
.Returns(new List<TrackFile> { _firstFile, _secondFile });
_parseResultMulti = new RemoteAlbum
{ {
Series = fakeSeries, Artist = fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
Episodes = doubleEpisodeList Albums = doubleEpisodeList
}; };
_parseResultSingle = new RemoteEpisode _parseResultSingle = new RemoteAlbum
{ {
Series = fakeSeries, Artist = fakeArtist,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.MP3_192, new Revision(version: 2)) }, ParsedAlbumInfo = new ParsedAlbumInfo { Quality = new QualityModel(Quality.MP3_256, new Revision(version: 2)) },
Episodes = singleEpisodeList Albums = singleEpisodeList
}; };
} }
private void WithFirstFileUpgradable() private void WithFirstFileUpgradable()
@ -68,61 +70,42 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
} }
[Test] [Test]
public void should_return_true_if_episode_has_no_existing_file() public void should_return_true_if_album_has_no_existing_file()
{ {
_parseResultSingle.Episodes.ForEach(c => c.EpisodeFileId = 0); Mocker.GetMock<IMediaFileService>()
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); .Setup(c => c.GetFilesByAlbum(It.IsAny<int>(), It.IsAny<int>()))
} .Returns(new List<TrackFile> { });
[Test] Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
public void should_return_true_if_single_episode_doesnt_exist_on_disk()
{
_parseResultSingle.Episodes = new List<Episode>();
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_upgradable_if_only_episode_is_upgradable() public void should_return_true_if_single_album_doesnt_exist_on_disk()
{ {
WithFirstFileUpgradable(); _parseResultSingle.Albums = new List<Album>();
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
}
[Test] Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
public void should_be_upgradable_if_both_episodes_are_upgradable()
{
WithFirstFileUpgradable();
WithSecondFileUpgradable();
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_not_upgradable_if_both_episodes_are_not_upgradable()
{
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_first_episodes_is_upgradable() public void should_be_upgradable_if_album_is_upgradable()
{ {
WithFirstFileUpgradable(); WithFirstFileUpgradable();
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() public void should_not_be_upgradable_if_qualities_are_the_same()
{ {
WithSecondFileUpgradable(); _firstFile.Quality = new QualityModel(Quality.MP3_512);
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_512);
Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_not_be_upgradable_if_qualities_are_the_same() public void should_not_be_upgradable_if_all_tracks_are_not_upgradable()
{ {
_firstFile.Quality = new QualityModel(Quality.MP3_512); Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_512);
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
} }
} }

@ -11,7 +11,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
@ -27,89 +27,88 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
.Returns<List<DownloadDecision>>(v => v); .Returns<List<DownloadDecision>>(v => v);
} }
private Episode GetEpisode(int id) private Album GetAlbum(int id)
{ {
return Builder<Episode>.CreateNew() return Builder<Album>.CreateNew()
.With(e => e.Id = id) .With(e => e.Id = id)
.With(e => e.EpisodeNumber = id)
.Build(); .Build();
} }
private RemoteEpisode GetRemoteEpisode(List<Episode> episodes, QualityModel quality) private RemoteAlbum GetRemoteAlbum(List<Album> albums, QualityModel quality)
{ {
var remoteEpisode = new RemoteEpisode(); var remoteAlbum = new RemoteAlbum();
remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo(); remoteAlbum.ParsedAlbumInfo = new ParsedAlbumInfo();
remoteEpisode.ParsedEpisodeInfo.Quality = quality; remoteAlbum.ParsedAlbumInfo.Quality = quality;
remoteEpisode.Episodes = new List<Episode>(); remoteAlbum.Albums = new List<Album>();
remoteEpisode.Episodes.AddRange(episodes); remoteAlbum.Albums.AddRange(albums);
remoteEpisode.Release = new ReleaseInfo(); remoteAlbum.Release = new ReleaseInfo();
remoteEpisode.Release.PublishDate = DateTime.UtcNow; remoteAlbum.Release.PublishDate = DateTime.UtcNow;
remoteEpisode.Series = Builder<Series>.CreateNew() remoteAlbum.Artist = Builder<Artist>.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
return remoteEpisode; return remoteAlbum;
} }
[Test] [Test]
public void should_download_report_if_epsiode_was_not_already_downloaded() public void should_download_report_if_album_was_not_already_downloaded()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteEpisode = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteEpisode));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteEpisode>()), Times.Once()); Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteAlbum>()), Times.Once());
} }
[Test] [Test]
public void should_only_download_episode_once() public void should_only_download_album_once()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteEpisode>()), Times.Once()); Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteAlbum>()), Times.Once());
} }
[Test] [Test]
public void should_not_download_if_any_episode_was_already_downloaded() public void should_not_download_if_any_album_was_already_downloaded()
{ {
var remoteEpisode1 = GetRemoteEpisode( var remoteAlbum1 = GetRemoteAlbum(
new List<Episode> { GetEpisode(1) }, new List<Album> { GetAlbum(1) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var remoteEpisode2 = GetRemoteEpisode( var remoteAlbum2 = GetRemoteAlbum(
new List<Episode> { GetEpisode(1), GetEpisode(2) }, new List<Album> { GetAlbum(1), GetAlbum(2) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteEpisode>()), Times.Once()); Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteAlbum>()), Times.Once());
} }
[Test] [Test]
public void should_return_downloaded_reports() public void should_return_downloaded_reports()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(1); Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(1);
} }
@ -117,19 +116,19 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test] [Test]
public void should_return_all_downloaded_reports() public void should_return_all_downloaded_reports()
{ {
var remoteEpisode1 = GetRemoteEpisode( var remoteAlbum1 = GetRemoteAlbum(
new List<Episode> { GetEpisode(1) }, new List<Album> { GetAlbum(1) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var remoteEpisode2 = GetRemoteEpisode( var remoteAlbum2 = GetRemoteAlbum(
new List<Episode> { GetEpisode(2) }, new List<Album> { GetAlbum(2) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(2); Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(2);
} }
@ -137,25 +136,25 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test] [Test]
public void should_only_return_downloaded_reports() public void should_only_return_downloaded_reports()
{ {
var remoteEpisode1 = GetRemoteEpisode( var remoteAlbum1 = GetRemoteAlbum(
new List<Episode> { GetEpisode(1) }, new List<Album> { GetAlbum(1) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var remoteEpisode2 = GetRemoteEpisode( var remoteAlbum2 = GetRemoteAlbum(
new List<Episode> { GetEpisode(2) }, new List<Album> { GetAlbum(2) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var remoteEpisode3 = GetRemoteEpisode( var remoteAlbum3 = GetRemoteAlbum(
new List<Episode> { GetEpisode(2) }, new List<Album> { GetAlbum(2) },
new QualityModel(Quality.MP3_192) new QualityModel(Quality.MP3_192)
); );
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteAlbum1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteAlbum2));
decisions.Add(new DownloadDecision(remoteEpisode3)); decisions.Add(new DownloadDecision(remoteAlbum3));
Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(2); Subject.ProcessDecisions(decisions).Grabbed.Should().HaveCount(2);
} }
@ -163,13 +162,13 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test] [Test]
public void should_not_add_to_downloaded_list_when_download_fails() public void should_not_add_to_downloaded_list_when_download_fails()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteEpisode>())).Throws(new Exception()); Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteAlbum>())).Throws(new Exception());
Subject.ProcessDecisions(decisions).Grabbed.Should().BeEmpty(); Subject.ProcessDecisions(decisions).Grabbed.Should().BeEmpty();
ExceptionVerification.ExpectedWarns(1); ExceptionVerification.ExpectedWarns(1);
} }
@ -178,8 +177,8 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
public void should_return_an_empty_list_when_none_are_appproved() public void should_return_an_empty_list_when_none_are_appproved()
{ {
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(null, new Rejection("Failure!"))); decisions.Add(new DownloadDecision(new RemoteAlbum(), new Rejection("Failure!")));
decisions.Add(new DownloadDecision(null, new Rejection("Failure!"))); decisions.Add(new DownloadDecision(new RemoteAlbum(), new Rejection("Failure!")));
Subject.GetQualifiedReports(decisions).Should().BeEmpty(); Subject.GetQualifiedReports(decisions).Should().BeEmpty();
} }
@ -187,26 +186,26 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test] [Test]
public void should_not_grab_if_pending() public void should_not_grab_if_pending()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary))); decisions.Add(new DownloadDecision(remoteAlbum, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteEpisode>()), Times.Never()); Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteAlbum>()), Times.Never());
} }
[Test] [Test]
public void should_not_add_to_pending_if_episode_was_grabbed() public void should_not_add_to_pending_if_album_was_grabbed()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode)); decisions.Add(new DownloadDecision(remoteAlbum));
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary))); decisions.Add(new DownloadDecision(remoteAlbum, new Rejection("Failure!", RejectionType.Temporary)));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IPendingReleaseService>().Verify(v => v.Add(It.IsAny<DownloadDecision>()), Times.Never()); Mocker.GetMock<IPendingReleaseService>().Verify(v => v.Add(It.IsAny<DownloadDecision>()), Times.Never());
@ -215,12 +214,12 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test] [Test]
public void should_add_to_pending_even_if_already_added_to_pending() public void should_add_to_pending_even_if_already_added_to_pending()
{ {
var episodes = new List<Episode> { GetEpisode(1) }; var albums = new List<Album> { GetAlbum(1) };
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.MP3_192)); var remoteAlbum = GetRemoteAlbum(albums, new QualityModel(Quality.MP3_192));
var decisions = new List<DownloadDecision>(); var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary))); decisions.Add(new DownloadDecision(remoteAlbum, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary))); decisions.Add(new DownloadDecision(remoteAlbum, new Rejection("Failure!", RejectionType.Temporary)));
Subject.ProcessDecisions(decisions); Subject.ProcessDecisions(decisions);
Mocker.GetMock<IPendingReleaseService>().Verify(v => v.Add(It.IsAny<DownloadDecision>()), Times.Exactly(2)); Mocker.GetMock<IPendingReleaseService>().Verify(v => v.Add(It.IsAny<DownloadDecision>()), Times.Exactly(2));

@ -1,4 +1,4 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
@ -16,7 +16,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[TestFixture] [TestFixture]
public class ScanWatchFolderFixture : CoreTest<ScanWatchFolder> public class ScanWatchFolderFixture : CoreTest<ScanWatchFolder>
{ {
protected readonly string _title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"; protected readonly string _title = "Radiohead - Scotch Mist [2008-FLAC-Lossless]";
protected string _completedDownloadFolder = @"c:\blackhole\completed".AsOsAgnostic(); protected string _completedDownloadFolder = @"c:\blackhole\completed".AsOsAgnostic();
protected void GivenCompletedItem() protected void GivenCompletedItem()
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.mkv") }); .Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>())) .Setup(c => c.GetFileSize(It.IsAny<string>()))

@ -1,4 +1,4 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -67,26 +67,26 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.mkv") }); .Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>())) .Setup(c => c.GetFileSize(It.IsAny<string>()))
.Returns(1000000); .Returns(1000000);
} }
protected override RemoteEpisode CreateRemoteEpisode() protected override RemoteAlbum CreateRemoteAlbum()
{ {
var remoteEpisode = base.CreateRemoteEpisode(); var remoteAlbum = base.CreateRemoteAlbum();
var torrentInfo = new TorrentInfo(); var torrentInfo = new TorrentInfo();
torrentInfo.Title = remoteEpisode.Release.Title; torrentInfo.Title = remoteAlbum.Release.Title;
torrentInfo.DownloadUrl = remoteEpisode.Release.DownloadUrl; torrentInfo.DownloadUrl = remoteAlbum.Release.DownloadUrl;
torrentInfo.DownloadProtocol = remoteEpisode.Release.DownloadProtocol; torrentInfo.DownloadProtocol = remoteAlbum.Release.DownloadProtocol;
torrentInfo.MagnetUrl = "magnet:?xt=urn:btih:755248817d32b00cc853e633ecdc48e4c21bff15&dn=Series.S05E10.PROPER.HDTV.x264-DEFiNE%5Brartv%5D&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710"; torrentInfo.MagnetUrl = "magnet:?xt=urn:btih:755248817d32b00cc853e633ecdc48e4c21bff15&dn=Artist.Album.FLAC.loseless-DEFiNE%5Brartv%5D&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710";
remoteEpisode.Release = torrentInfo; remoteAlbum.Release = torrentInfo;
return remoteEpisode; return remoteAlbum;
} }
[Test] [Test]
@ -125,9 +125,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_download_file_if_it_doesnt_exist() public void Download_should_download_file_if_it_doesnt_exist()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
Subject.Download(remoteEpisode); Subject.Download(remoteAlbum);
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once());
@ -139,10 +139,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
{ {
Subject.Definition.Settings.As<TorrentBlackholeSettings>().SaveMagnetFiles = true; Subject.Definition.Settings.As<TorrentBlackholeSettings>().SaveMagnetFiles = true;
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = null; remoteAlbum.Release.DownloadUrl = null;
Subject.Download(remoteEpisode); Subject.Download(remoteAlbum);
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Never()); Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Never());
@ -153,10 +153,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_not_save_magnet_if_disabled() public void Download_should_not_save_magnet_if_disabled()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = null; remoteAlbum.Release.DownloadUrl = null;
Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteEpisode)); Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteAlbum));
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Never()); Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Never());
@ -169,9 +169,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
{ {
Subject.Definition.Settings.As<TorrentBlackholeSettings>().SaveMagnetFiles = true; Subject.Definition.Settings.As<TorrentBlackholeSettings>().SaveMagnetFiles = true;
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
Subject.Download(remoteEpisode); Subject.Download(remoteAlbum);
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once());
@ -182,13 +182,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_replace_illegal_characters_in_title() public void Download_should_replace_illegal_characters_in_title()
{ {
var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]"; var illegalTitle = "Radiohead - Scotch Mist [2008/FLAC/Lossless]";
var expectedFilename = Path.Combine(_blackholeFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV]" + Path.GetExtension(_filePath)); var expectedFilename = Path.Combine(_blackholeFolder, "Radiohead - Scotch Mist [2008+FLAC+Lossless]" + Path.GetExtension(_filePath));
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
remoteEpisode.Release.Title = illegalTitle; remoteAlbum.Release.Title = illegalTitle;
Subject.Download(remoteEpisode); Subject.Download(remoteAlbum);
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.FullUri == _downloadUrl)), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(expectedFilename), Times.Once()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(expectedFilename), Times.Once());
@ -198,10 +198,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_throw_if_magnet_and_torrent_url_does_not_exist() public void Download_should_throw_if_magnet_and_torrent_url_does_not_exist()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = null; remoteAlbum.Release.DownloadUrl = null;
Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteEpisode)); Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteAlbum));
} }
[Test] [Test]
@ -273,9 +273,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void should_return_null_hash() public void should_return_null_hash()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteAlbum = CreateRemoteAlbum();
Subject.Download(remoteEpisode).Should().BeNull(); Subject.Download(remoteAlbum).Should().BeNull();
} }
} }
} }

@ -1,4 +1,4 @@

using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.mkv") }); .Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>())) .Setup(c => c.GetFileSize(It.IsAny<string>()))
@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_download_file_if_it_doesnt_exist() public void Download_should_download_file_if_it_doesnt_exist()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Subject.Download(remoteEpisode); Subject.Download(remoteEpisode);
@ -116,10 +116,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void Download_should_replace_illegal_characters_in_title() public void Download_should_replace_illegal_characters_in_title()
{ {
var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]"; var illegalTitle = "Radiohead - Scotch Mist [2008/FLAC/Lossless]";
var expectedFilename = Path.Combine(_blackholeFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV]" + Path.GetExtension(_filePath)); var expectedFilename = Path.Combine(_blackholeFolder, "Radiohead - Scotch Mist [2008+FLAC+Lossless]" + Path.GetExtension(_filePath));
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.Title = illegalTitle; remoteEpisode.Release.Title = illegalTitle;
Subject.Download(remoteEpisode); Subject.Download(remoteEpisode);

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
@ -196,7 +196,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -208,7 +208,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = magnetUrl; remoteEpisode.Release.DownloadUrl = magnetUrl;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -9,6 +9,7 @@ using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Music;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
@ -30,8 +31,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
.Returns(30); .Returns(30);
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), (SearchCriteriaBase)null)) .Setup(s => s.Map(It.IsAny<ParsedAlbumInfo>(), (SearchCriteriaBase)null))
.Returns(() => CreateRemoteEpisode()); .Returns(() => CreateRemoteAlbum());
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>())) .Setup(s => s.Get(It.IsAny<HttpRequest>()))
@ -42,22 +43,21 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
.Returns<string, OsPath>((h, r) => r); .Returns<string, OsPath>((h, r) => r);
} }
protected virtual RemoteEpisode CreateRemoteEpisode() protected virtual RemoteAlbum CreateRemoteAlbum()
{ {
var remoteEpisode = new RemoteEpisode(); var remoteAlbum = new RemoteAlbum();
remoteEpisode.Release = new ReleaseInfo(); remoteAlbum.Release = new ReleaseInfo();
remoteEpisode.Release.Title = _title; remoteAlbum.Release.Title = _title;
remoteEpisode.Release.DownloadUrl = _downloadUrl; remoteAlbum.Release.DownloadUrl = _downloadUrl;
remoteEpisode.Release.DownloadProtocol = Subject.Protocol; remoteAlbum.Release.DownloadProtocol = Subject.Protocol;
remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo(); remoteAlbum.ParsedAlbumInfo = new ParsedAlbumInfo();
remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
remoteEpisode.Episodes = new List<Episode>(); remoteAlbum.Albums = new List<Album>();
remoteEpisode.Series = new Series(); remoteAlbum.Artist = new Artist();
return remoteEpisode; return remoteAlbum;
} }
protected void VerifyIdentifiable(DownloadClientItem downloadClientItem) protected void VerifyIdentifiable(DownloadClientItem downloadClientItem)

@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
protected string _serialNumber = "SERIALNUMBER"; protected string _serialNumber = "SERIALNUMBER";
protected string _category ="lidarr"; protected string _category ="lidarr";
protected string _tvDirectory = @"video/Series"; protected string _musicDirectory = @"music/Artist";
protected string _defaultDestination = "somepath"; protected string _defaultDestination = "somepath";
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata"); protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
@ -301,7 +301,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
protected void GivenTvDirectory() protected void GivenTvDirectory()
{ {
_settings.TvDirectory = _tvDirectory; _settings.TvDirectory = _musicDirectory;
} }
protected virtual void GivenTasks(List<DownloadStationTask> torrents) protected virtual void GivenTasks(List<DownloadStationTask> torrents)
@ -339,13 +339,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
.Callback(PrepareClientToReturnQueuedItem); .Callback(PrepareClientToReturnQueuedItem);
} }
protected override RemoteEpisode CreateRemoteEpisode() protected override RemoteAlbum CreateRemoteAlbum()
{ {
var episode = base.CreateRemoteEpisode(); var album = base.CreateRemoteAlbum();
episode.Release.DownloadUrl = DownloadURL; album.Release.DownloadUrl = DownloadURL;
return episode; return album;
} }
protected int GivenAllKindOfTasks() protected int GivenAllKindOfTasks()
@ -366,14 +366,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenTvDirectory(); GivenTvDirectory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _musicDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
[Test] [Test]
@ -383,7 +383,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenTvCategory(); GivenTvCategory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -399,7 +399,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenSerialNumber(); GivenSerialNumber();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -474,7 +474,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
[Test] [Test]
public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number() public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Mocker.GetMock<ISerialNumberProvider>() Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings)) .Setup(s => s.GetSerialNumber(_settings))

@ -29,18 +29,18 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
protected string _serialNumber = "SERIALNUMBER"; protected string _serialNumber = "SERIALNUMBER";
protected string _category = "lidarr"; protected string _category = "lidarr";
protected string _tvDirectory = @"video/Series"; protected string _musicDirectory = @"music/Artist";
protected string _defaultDestination = "somepath"; protected string _defaultDestination = "somepath";
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata"); protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
protected RemoteEpisode _remoteEpisode; protected RemoteAlbum _remoteAlbum;
protected Dictionary<string, object> _downloadStationConfigItems; protected Dictionary<string, object> _downloadStationConfigItems;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_remoteEpisode = CreateRemoteEpisode(); _remoteAlbum = CreateRemoteAlbum();
_settings = new DownloadStationSettings() _settings = new DownloadStationSettings()
{ {
@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
{ "destination","shared/folder" }, { "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" } { "uri", FileNameBuilder.CleanFileName(_remoteAlbum.Release.Title) + ".nzb" }
}, },
Transfer = new Dictionary<string, string> Transfer = new Dictionary<string, string>
{ {
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
{ "destination","shared/folder" }, { "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" } { "uri", FileNameBuilder.CleanFileName(_remoteAlbum.Release.Title) + ".nzb" }
}, },
Transfer = new Dictionary<string, string> Transfer = new Dictionary<string, string>
{ {
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
{ "destination","shared/folder" }, { "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" } { "uri", FileNameBuilder.CleanFileName(_remoteAlbum.Release.Title) + ".nzb" }
}, },
Transfer = new Dictionary<string, string> Transfer = new Dictionary<string, string>
{ {
@ -135,7 +135,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
{ "destination","shared/folder" }, { "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" } { "uri", FileNameBuilder.CleanFileName(_remoteAlbum.Release.Title) + ".nzb" }
}, },
Transfer = new Dictionary<string, string> Transfer = new Dictionary<string, string>
{ {
@ -158,7 +158,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
{ "destination","shared/folder" }, { "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" } { "uri", FileNameBuilder.CleanFileName(_remoteAlbum.Release.Title) + ".nzb" }
}, },
Transfer = new Dictionary<string, string> Transfer = new Dictionary<string, string>
{ {
@ -203,7 +203,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
protected void GivenTvDirectory() protected void GivenTvDirectory()
{ {
_settings.TvDirectory = _tvDirectory; _settings.TvDirectory = _musicDirectory;
} }
protected virtual void GivenTasks(List<DownloadStationTask> nzbs) protected virtual void GivenTasks(List<DownloadStationTask> nzbs)
@ -254,14 +254,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenTvDirectory(); GivenTvDirectory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _musicDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
[Test] [Test]
@ -271,7 +271,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenTvCategory(); GivenTvCategory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -287,7 +287,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenSerialNumber(); GivenSerialNumber();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -362,7 +362,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
[Test] [Test]
public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number() public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Mocker.GetMock<ISerialNumberProvider>() Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings)) .Setup(s => s.GetSerialNumber(_settings))

@ -197,7 +197,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.HadoukenTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -276,7 +276,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.HadoukenTests
[Test] [Test]
public void Download_from_magnet_link_should_return_hash_uppercase() public void Download_from_magnet_link_should_return_hash_uppercase()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = "magnet:?xt=urn:btih:a45129e59d8750f9da982f53552b1e4f0457ee9f"; remoteEpisode.Release.DownloadUrl = "magnet:?xt=urn:btih:a45129e59d8750f9da982f53552b1e4f0457ee9f";
@ -291,7 +291,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.HadoukenTests
[Test] [Test]
public void Download_from_torrent_file_should_return_hash_uppercase() public void Download_from_torrent_file_should_return_hash_uppercase()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Mocker.GetMock<IHadoukenProxy>() Mocker.GetMock<IHadoukenProxy>()
.Setup(v => v.AddTorrentFile(It.IsAny<HadoukenSettings>(), It.IsAny<byte[]>())) .Setup(v => v.AddTorrentFile(It.IsAny<HadoukenSettings>(), It.IsAny<byte[]>()))

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
Host = "127.0.0.1", Host = "127.0.0.1",
Port = 2222, Port = 2222,
ApiKey = "1234-ABCD", ApiKey = "1234-ABCD",
TvCategory = "tv", TvCategory = "Music",
RecentTvPriority = (int)NzbgetPriority.High RecentTvPriority = (int)NzbgetPriority.High
}; };
@ -41,16 +41,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
Id = RandomNumber, Id = RandomNumber,
DownloadedSize = 1000, DownloadedSize = 1000,
TotalDownloadSize = 10, TotalDownloadSize = 10,
GroupName = "tv", GroupName = "Music",
UiTitle = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE" UiTitle = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN"
}; };
_failed = new NzbVortexQueueItem _failed = new NzbVortexQueueItem
{ {
DownloadedSize = 1000, DownloadedSize = 1000,
TotalDownloadSize = 1000, TotalDownloadSize = 1000,
GroupName = "tv", GroupName = "Music",
UiTitle = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", UiTitle = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
DestinationPath = "somedirectory", DestinationPath = "somedirectory",
State = NzbVortexStateType.UncompressFailed, State = NzbVortexStateType.UncompressFailed,
}; };
@ -59,9 +59,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
{ {
DownloadedSize = 1000, DownloadedSize = 1000,
TotalDownloadSize = 1000, TotalDownloadSize = 1000,
GroupName = "tv", GroupName = "Music",
UiTitle = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", UiTitle = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
DestinationPath = "/remote/mount/tv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", DestinationPath = "/remote/mount/music/Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
State = NzbVortexStateType.Done State = NzbVortexStateType.Done
}; };
} }
@ -189,7 +189,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -201,7 +201,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
{ {
GivenFailedDownload(); GivenFailedDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Assert.Throws<DownloadClientException>(() => Subject.Download(remoteEpisode)); Assert.Throws<DownloadClientException>(() => Subject.Download(remoteEpisode));
} }
@ -223,13 +223,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
{ {
Mocker.GetMock<IRemotePathMappingService>() Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>())) .Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic())); .Returns(new OsPath(@"O:\mymount\Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN".AsOsAgnostic()));
GivenQueue(_completed); GivenQueue(_completed);
var result = Subject.GetItems().Single(); var result = Subject.GetItems().Single();
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic()); result.OutputPath.Should().Be(@"O:\mymount\Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN".AsOsAgnostic());
} }
[Test] [Test]
@ -241,14 +241,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
Mocker.GetMock<INzbVortexProxy>() Mocker.GetMock<INzbVortexProxy>()
.Setup(s => s.GetFiles(It.IsAny<int>(), It.IsAny<NzbVortexSettings>())) .Setup(s => s.GetFiles(It.IsAny<int>(), It.IsAny<NzbVortexSettings>()))
.Returns(new List<NzbVortexFile> { new NzbVortexFile { FileName = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.mkv" } }); .Returns(new List<NzbVortexFile> { new NzbVortexFile { FileName = "Fall Out Boy - Make America Psyco Again - Track 1.flac" } });
_completed.State = NzbVortexStateType.Done; _completed.State = NzbVortexStateType.Done;
GivenQueue(_completed); GivenQueue(_completed);
var result = Subject.GetItems().Single(); var result = Subject.GetItems().Single();
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.mkv".AsOsAgnostic()); result.OutputPath.Should().Be(@"O:\mymount\Fall Out Boy - Make America Psyco Again - Track 1.flac".AsOsAgnostic());
} }
[Test] [Test]
@ -262,8 +262,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
.Setup(s => s.GetFiles(It.IsAny<int>(), It.IsAny<NzbVortexSettings>())) .Setup(s => s.GetFiles(It.IsAny<int>(), It.IsAny<NzbVortexSettings>()))
.Returns(new List<NzbVortexFile> .Returns(new List<NzbVortexFile>
{ {
new NzbVortexFile { FileName = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.mkv" }, new NzbVortexFile { FileName = "Fall Out Boy - Make America Psyco Again - Track 1.flac" },
new NzbVortexFile { FileName = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.nfo" } new NzbVortexFile { FileName = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN.nfo" }
}); });
_completed.State = NzbVortexStateType.Done; _completed.State = NzbVortexStateType.Done;

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
Port = 2222, Port = 2222,
Username = "admin", Username = "admin",
Password = "pass", Password = "pass",
TvCategory = "tv", TvCategory = "music",
RecentTvPriority = (int)NzbgetPriority.High RecentTvPriority = (int)NzbgetPriority.High
}; };
@ -38,16 +38,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
RemainingSizeLo = 10, RemainingSizeLo = 10,
Category = "tv", Category = "music",
NzbName = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", NzbName = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } } Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }
}; };
_failed = new NzbgetHistoryItem _failed = new NzbgetHistoryItem
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
Category = "tv", Category = "music",
Name = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", Name = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
DestDir = "somedirectory", DestDir = "somedirectory",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }, Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
ParStatus = "Some Error", ParStatus = "Some Error",
@ -61,9 +61,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_completed = new NzbgetHistoryItem _completed = new NzbgetHistoryItem
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
Category = "tv", Category = "music",
Name = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", Name = "Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
DestDir = "/remote/mount/tv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", DestDir = "/remote/mount/music/Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }, Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
ParStatus = "SUCCESS", ParStatus = "SUCCESS",
UnpackStatus = "NONE", UnpackStatus = "NONE",
@ -81,8 +81,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
}); });
var configItems = new Dictionary<string, string>(); var configItems = new Dictionary<string, string>();
configItems.Add("Category1.Name", "tv"); configItems.Add("Category1.Name", "music");
configItems.Add("Category1.DestDir", @"/remote/mount/tv"); configItems.Add("Category1.DestDir", @"/remote/mount/music");
Mocker.GetMock<INzbgetProxy>() Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>())) .Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))
@ -303,7 +303,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -315,7 +315,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{ {
GivenFailedDownload(); GivenFailedDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
Assert.Throws<DownloadClientException>(() => Subject.Download(remoteEpisode)); Assert.Throws<DownloadClientException>(() => Subject.Download(remoteEpisode));
} }
@ -340,7 +340,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
result.IsLocalhost.Should().BeTrue(); result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull(); result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(@"/remote/mount/tv"); result.OutputRootFolders.First().Should().Be(@"/remote/mount/music");
} }
[Test] [Test]
@ -362,14 +362,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{ {
Mocker.GetMock<IRemotePathMappingService>() Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>())) .Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic())); .Returns(new OsPath(@"O:\mymount\Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN".AsOsAgnostic()));
GivenQueue(null); GivenQueue(null);
GivenHistory(_completed); GivenHistory(_completed);
var result = Subject.GetItems().Single(); var result = Subject.GetItems().Single();
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic()); result.OutputPath.Should().Be(@"O:\mymount\Fall Out Boy-Make America Psycho Again-CD-FLAC-2015-FORSAKEN".AsOsAgnostic());
} }
[TestCase("11.0", false)] [TestCase("11.0", false)]

@ -1,4 +1,4 @@
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using Moq; using Moq;
@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
private string _pneumaticFolder; private string _pneumaticFolder;
private string _sabDrop; private string _sabDrop;
private string _nzbPath; private string _nzbPath;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteEpisode;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -33,13 +33,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop); Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop);
_remoteEpisode = new RemoteEpisode(); _remoteEpisode = new RemoteAlbum();
_remoteEpisode.Release = new ReleaseInfo(); _remoteEpisode.Release = new ReleaseInfo();
_remoteEpisode.Release.Title = _title; _remoteEpisode.Release.Title = _title;
_remoteEpisode.Release.DownloadUrl = _nzbUrl; _remoteEpisode.Release.DownloadUrl = _nzbUrl;
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo(); _remoteEpisode.ParsedAlbumInfo = new ParsedAlbumInfo();
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
Subject.Definition = new DownloadClientDefinition(); Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new PneumaticSettings Subject.Definition.Settings = new PneumaticSettings
@ -74,7 +73,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
public void should_throw_if_full_season_download() public void should_throw_if_full_season_download()
{ {
_remoteEpisode.Release.Title = "30 Rock - Season 1"; _remoteEpisode.Release.Title = "30 Rock - Season 1";
_remoteEpisode.ParsedEpisodeInfo.FullSeason = true;
Assert.Throws<NotSupportedException>(() => Subject.Download(_remoteEpisode)); Assert.Throws<NotSupportedException>(() => Subject.Download(_remoteEpisode));
} }

@ -245,7 +245,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -257,7 +257,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = magnetUrl; remoteEpisode.Release.DownloadUrl = magnetUrl;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -290,7 +290,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenRedirectToMagnet(); GivenRedirectToMagnet();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -303,7 +303,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenRedirectToTorrent(); GivenRedirectToTorrent();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
@ -116,7 +116,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using FizzWare.NBuilder; using FizzWare.NBuilder;
@ -8,7 +8,7 @@ using NUnit.Framework;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Sabnzbd; using NzbDrone.Core.Download.Clients.Sabnzbd;
using NzbDrone.Core.Download.Clients.Sabnzbd.Responses; using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@ -281,7 +281,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.Title = title; remoteEpisode.Release.Title = title;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -295,7 +295,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -336,10 +336,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>())) .Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()))
.Returns(new SabnzbdAddResponse()); .Returns(new SabnzbdAddResponse());
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1) remoteEpisode.Albums = Builder<Album>.CreateListOfSize(1)
.All() .All()
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT)) .With(e => e.ReleaseDate = DateTime.Today)
.Build() .Build()
.ToList(); .ToList();

@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
GivenTvDirectory(); GivenTvDirectory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
GivenTvCategory(); GivenTvCategory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -102,7 +102,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
_transmissionConfigItems["download-dir"] += "/"; _transmissionConfigItems["download-dir"] += "/";
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -132,7 +132,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = magnetUrl; remoteEpisode.Release.DownloadUrl = magnetUrl;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -30,8 +30,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Port = 2222, Port = 2222,
Username = "admin", Username = "admin",
Password = "pass", Password = "pass",
TvCategory = "tv" TvCategory = "lidarr"
}; };
_queued = new UTorrentTorrent _queued = new UTorrentTorrent
{ {
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 1000, Remaining = 1000,
Progress = 0, Progress = 0,
Label = "tv", Label = "lidarr",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 100, Remaining = 100,
Progress = 0.9, Progress = 0.9,
Label = "tv", Label = "lidarr",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 100, Remaining = 100,
Progress = 0.9, Progress = 0.9,
Label = "tv", Label = "lidarr",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 0, Remaining = 0,
Progress = 1.0, Progress = 1.0,
Label = "tv", Label = "lidarr",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -229,7 +229,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -253,7 +253,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = magnetUrl; remoteEpisode.Release.DownloadUrl = magnetUrl;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -328,7 +328,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
result.IsLocalhost.Should().BeTrue(); result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull(); result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\tv".AsOsAgnostic()); result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\lidarr".AsOsAgnostic());
} }
[Test] [Test]
@ -351,7 +351,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
GivenRedirectToMagnet(); GivenRedirectToMagnet();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -364,7 +364,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
GivenRedirectToTorrent(); GivenRedirectToTorrent();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
GivenTvDirectory(); GivenTvDirectory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
GivenTvCategory(); GivenTvCategory();
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
_transmissionConfigItems["download-dir"] += "/"; _transmissionConfigItems["download-dir"] += "/";
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);
@ -134,7 +134,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
{ {
GivenSuccessfulDownload(); GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteAlbum();
remoteEpisode.Release.DownloadUrl = magnetUrl; remoteEpisode.Release.DownloadUrl = magnetUrl;
var id = Subject.Download(remoteEpisode); var id = Subject.Download(remoteEpisode);

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -12,7 +12,7 @@ using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download namespace NzbDrone.Core.Test.Download
@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.Download
[TestFixture] [TestFixture]
public class DownloadServiceFixture : CoreTest<DownloadService> public class DownloadServiceFixture : CoreTest<DownloadService>
{ {
private RemoteEpisode _parseResult; private RemoteAlbum _parseResult;
private List<IDownloadClient> _downloadClients; private List<IDownloadClient> _downloadClients;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -35,10 +35,10 @@ namespace NzbDrone.Core.Test.Download
.Setup(v => v.GetDownloadClient(It.IsAny<DownloadProtocol>())) .Setup(v => v.GetDownloadClient(It.IsAny<DownloadProtocol>()))
.Returns<DownloadProtocol>(v => _downloadClients.FirstOrDefault(d => d.Protocol == v)); .Returns<DownloadProtocol>(v => _downloadClients.FirstOrDefault(d => d.Protocol == v));
var episodes = Builder<Episode>.CreateListOfSize(2) var episodes = Builder<Album>.CreateListOfSize(2)
.TheFirst(1).With(s => s.Id = 12) .TheFirst(1).With(s => s.Id = 12)
.TheNext(1).With(s => s.Id = 99) .TheNext(1).With(s => s.Id = 99)
.All().With(s => s.SeriesId = 5) .All().With(s => s.ArtistId = 5)
.Build().ToList(); .Build().ToList();
var releaseInfo = Builder<ReleaseInfo>.CreateNew() var releaseInfo = Builder<ReleaseInfo>.CreateNew()
@ -46,10 +46,10 @@ namespace NzbDrone.Core.Test.Download
.With(v => v.DownloadUrl = "http://test.site/download1.ext") .With(v => v.DownloadUrl = "http://test.site/download1.ext")
.Build(); .Build();
_parseResult = Builder<RemoteEpisode>.CreateNew() _parseResult = Builder<RemoteAlbum>.CreateNew()
.With(c => c.Series = Builder<Series>.CreateNew().Build()) .With(c => c.Artist = Builder<Artist>.CreateNew().Build())
.With(c => c.Release = releaseInfo) .With(c => c.Release = releaseInfo)
.With(c => c.Episodes = episodes) .With(c => c.Albums = episodes)
.Build(); .Build();
} }
@ -81,42 +81,42 @@ namespace NzbDrone.Core.Test.Download
public void Download_report_should_publish_on_grab_event() public void Download_report_should_publish_on_grab_event()
{ {
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())); mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()));
Subject.DownloadReport(_parseResult); Subject.DownloadReport(_parseResult);
VerifyEventPublished<EpisodeGrabbedEvent>(); VerifyEventPublished<AlbumGrabbedEvent>();
} }
[Test] [Test]
public void Download_report_should_grab_using_client() public void Download_report_should_grab_using_client()
{ {
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())); mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()));
Subject.DownloadReport(_parseResult); Subject.DownloadReport(_parseResult);
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once()); mock.Verify(s => s.Download(It.IsAny<RemoteAlbum>()), Times.Once());
} }
[Test] [Test]
public void Download_report_should_not_publish_on_failed_grab_event() public void Download_report_should_not_publish_on_failed_grab_event()
{ {
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())) mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()))
.Throws(new WebException()); .Throws(new WebException());
Assert.Throws<WebException>(() => Subject.DownloadReport(_parseResult)); Assert.Throws<WebException>(() => Subject.DownloadReport(_parseResult));
VerifyEventNotPublished<EpisodeGrabbedEvent>(); VerifyEventNotPublished<AlbumGrabbedEvent>();
} }
[Test] [Test]
public void Download_report_should_trigger_indexer_backoff_on_indexer_error() public void Download_report_should_trigger_indexer_backoff_on_indexer_error()
{ {
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())) mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()))
.Callback<RemoteEpisode>(v => { .Callback<RemoteAlbum>(v => {
throw new ReleaseDownloadException(v.Release, "Error", new WebException()); throw new ReleaseDownloadException(v.Release, "Error", new WebException());
}); });
@ -134,8 +134,8 @@ namespace NzbDrone.Core.Test.Download
response.Headers["Retry-After"] = "300"; response.Headers["Retry-After"] = "300";
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())) mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()))
.Callback<RemoteEpisode>(v => { .Callback<RemoteAlbum>(v => {
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response)); throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
}); });
@ -153,8 +153,8 @@ namespace NzbDrone.Core.Test.Download
response.Headers["Retry-After"] = DateTime.UtcNow.AddSeconds(300).ToString("r"); response.Headers["Retry-After"] = DateTime.UtcNow.AddSeconds(300).ToString("r");
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())) mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()))
.Callback<RemoteEpisode>(v => .Callback<RemoteAlbum>(v =>
{ {
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response)); throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
}); });
@ -170,7 +170,7 @@ namespace NzbDrone.Core.Test.Download
public void Download_report_should_not_trigger_indexer_backoff_on_downloadclient_error() public void Download_report_should_not_trigger_indexer_backoff_on_downloadclient_error()
{ {
var mock = WithUsenetClient(); var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>())) mock.Setup(s => s.Download(It.IsAny<RemoteAlbum>()))
.Throws(new DownloadClientException("Some Error")); .Throws(new DownloadClientException("Some Error"));
Assert.Throws<DownloadClientException>(() => Subject.DownloadReport(_parseResult)); Assert.Throws<DownloadClientException>(() => Subject.DownloadReport(_parseResult));
@ -184,7 +184,7 @@ namespace NzbDrone.Core.Test.Download
{ {
Subject.DownloadReport(_parseResult); Subject.DownloadReport(_parseResult);
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never()); Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Never());
VerifyEventNotPublished<EpisodeGrabbedEvent>(); VerifyEventNotPublished<EpisodeGrabbedEvent>();
ExceptionVerification.ExpectedWarns(1); ExceptionVerification.ExpectedWarns(1);
@ -198,8 +198,8 @@ namespace NzbDrone.Core.Test.Download
Subject.DownloadReport(_parseResult); Subject.DownloadReport(_parseResult);
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never()); mockTorrent.Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Never());
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Once()); mockUsenet.Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Once());
} }
[Test] [Test]
@ -212,8 +212,8 @@ namespace NzbDrone.Core.Test.Download
Subject.DownloadReport(_parseResult); Subject.DownloadReport(_parseResult);
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Once()); mockTorrent.Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Once());
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never()); mockUsenet.Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Never());
} }
} }
} }

@ -12,7 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
@ -20,20 +20,20 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
public class AddFixture : CoreTest<PendingReleaseService> public class AddFixture : CoreTest<PendingReleaseService>
{ {
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Artist _artist;
private Episode _episode; private Album _album;
private Profile _profile; private Profile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedAlbumInfo _parsedAlbumInfo;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_series = Builder<Series>.CreateNew() _artist = Builder<Artist>.CreateNew()
.Build(); .Build();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new Profile
@ -48,32 +48,32 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _artist.Profile = new LazyLoaded<Profile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();
_parsedEpisodeInfo = Builder<ParsedEpisodeInfo>.CreateNew().Build(); _parsedAlbumInfo = Builder<ParsedAlbumInfo>.CreateNew().Build();
_parsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256); _parsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256);
_remoteEpisode = new RemoteEpisode(); _remoteAlbum = new RemoteAlbum();
_remoteEpisode.Episodes = new List<Episode>{ _episode }; _remoteAlbum.Albums = new List<Album>{ _album };
_remoteEpisode.Series = _series; _remoteAlbum.Artist = _artist;
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo; _remoteAlbum.ParsedAlbumInfo = _parsedAlbumInfo;
_remoteEpisode.Release = _release; _remoteAlbum.Release = _release;
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary)); _temporarilyRejected = new DownloadDecision(_remoteAlbum, new Rejection("Temp Rejected", RejectionType.Temporary));
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
.Setup(s => s.All()) .Setup(s => s.All())
.Returns(new List<PendingRelease>()); .Returns(new List<PendingRelease>());
Mocker.GetMock<ISeriesService>() Mocker.GetMock<IArtistService>()
.Setup(s => s.GetSeries(It.IsAny<int>())) .Setup(s => s.GetArtist(It.IsAny<int>()))
.Returns(_series); .Returns(_artist);
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null)) .Setup(s => s.GetAlbums(It.IsAny<ParsedAlbumInfo>(), _artist, null))
.Returns(new List<Episode> {_episode}); .Returns(new List<Album> {_album});
Mocker.GetMock<IPrioritizeDownloadDecision>() Mocker.GetMock<IPrioritizeDownloadDecision>()
.Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>())) .Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>()))
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
var heldReleases = Builder<PendingRelease>.CreateListOfSize(1) var heldReleases = Builder<PendingRelease>.CreateListOfSize(1)
.All() .All()
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.With(h => h.Title = title) .With(h => h.Title = title)
.With(h => h.Release = release) .With(h => h.Release = release)
.Build(); .Build();

@ -12,7 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
@ -20,20 +20,20 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
public class RemoveGrabbedFixture : CoreTest<PendingReleaseService> public class RemoveGrabbedFixture : CoreTest<PendingReleaseService>
{ {
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Artist _artist;
private Episode _episode; private Album _album;
private Profile _profile; private Profile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedAlbumInfo _parsedAlbumInfo;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_series = Builder<Series>.CreateNew() _artist = Builder<Artist>.CreateNew()
.Build(); .Build();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new Profile
@ -48,32 +48,32 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _artist.Profile = new LazyLoaded<Profile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();
_parsedEpisodeInfo = Builder<ParsedEpisodeInfo>.CreateNew().Build(); _parsedAlbumInfo = Builder<ParsedAlbumInfo>.CreateNew().Build();
_parsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_256); _parsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256);
_remoteEpisode = new RemoteEpisode(); _remoteAlbum = new RemoteAlbum();
_remoteEpisode.Episodes = new List<Episode>{ _episode }; _remoteAlbum.Albums = new List<Album>{ _album };
_remoteEpisode.Series = _series; _remoteAlbum.Artist = _artist;
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo; _remoteAlbum.ParsedAlbumInfo = _parsedAlbumInfo;
_remoteEpisode.Release = _release; _remoteAlbum.Release = _release;
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary)); _temporarilyRejected = new DownloadDecision(_remoteAlbum, new Rejection("Temp Rejected", RejectionType.Temporary));
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
.Setup(s => s.All()) .Setup(s => s.All())
.Returns(new List<PendingRelease>()); .Returns(new List<PendingRelease>());
Mocker.GetMock<ISeriesService>() Mocker.GetMock<IArtistService>()
.Setup(s => s.GetSeries(It.IsAny<int>())) .Setup(s => s.GetArtist(It.IsAny<int>()))
.Returns(_series); .Returns(_artist);
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null)) .Setup(s => s.GetAlbums(It.IsAny<ParsedAlbumInfo>(), _artist, null))
.Returns(new List<Episode> {_episode}); .Returns(new List<Album> {_album});
Mocker.GetMock<IPrioritizeDownloadDecision>() Mocker.GetMock<IPrioritizeDownloadDecision>()
.Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>())) .Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>()))
@ -82,14 +82,14 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
private void GivenHeldRelease(QualityModel quality) private void GivenHeldRelease(QualityModel quality)
{ {
var parsedEpisodeInfo = _parsedEpisodeInfo.JsonClone(); var parsedEpisodeInfo = _parsedAlbumInfo.JsonClone();
parsedEpisodeInfo.Quality = quality; parsedEpisodeInfo.Quality = quality;
var heldReleases = Builder<PendingRelease>.CreateListOfSize(1) var heldReleases = Builder<PendingRelease>.CreateListOfSize(1)
.All() .All()
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.With(h => h.Release = _release.JsonClone()) .With(h => h.Release = _release.JsonClone())
.With(h => h.ParsedEpisodeInfo = parsedEpisodeInfo) .With(h => h.ParsedAlbumInfo = parsedEpisodeInfo)
.Build(); .Build();
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
@ -100,9 +100,9 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
[Test] [Test]
public void should_delete_if_the_grabbed_quality_is_the_same() public void should_delete_if_the_grabbed_quality_is_the_same()
{ {
GivenHeldRelease(_parsedEpisodeInfo.Quality); GivenHeldRelease(_parsedAlbumInfo.Quality);
Subject.Handle(new EpisodeGrabbedEvent(_remoteEpisode)); Subject.Handle(new AlbumGrabbedEvent(_remoteAlbum));
VerifyDelete(); VerifyDelete();
} }
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
GivenHeldRelease(new QualityModel(Quality.MP3_192)); GivenHeldRelease(new QualityModel(Quality.MP3_192));
Subject.Handle(new EpisodeGrabbedEvent(_remoteEpisode)); Subject.Handle(new AlbumGrabbedEvent(_remoteAlbum));
VerifyDelete(); VerifyDelete();
} }
@ -122,7 +122,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
GivenHeldRelease(new QualityModel(Quality.MP3_512)); GivenHeldRelease(new QualityModel(Quality.MP3_512));
Subject.Handle(new EpisodeGrabbedEvent(_remoteEpisode)); Subject.Handle(new AlbumGrabbedEvent(_remoteAlbum));
VerifyNoDelete(); VerifyNoDelete();
} }

@ -8,7 +8,7 @@ using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
@ -16,48 +16,48 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
public class RemovePendingFixture : CoreTest<PendingReleaseService> public class RemovePendingFixture : CoreTest<PendingReleaseService>
{ {
private List<PendingRelease> _pending; private List<PendingRelease> _pending;
private Episode _episode; private Album _album;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_pending = new List<PendingRelease>(); _pending = new List<PendingRelease>();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.Build(); .Build();
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
.Setup(s => s.AllBySeriesId(It.IsAny<int>())) .Setup(s => s.AllByArtistId(It.IsAny<int>()))
.Returns(_pending); .Returns(_pending);
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
.Setup(s => s.All()) .Setup(s => s.All())
.Returns( _pending); .Returns( _pending);
Mocker.GetMock<ISeriesService>() Mocker.GetMock<IArtistService>()
.Setup(s => s.GetSeries(It.IsAny<int>())) .Setup(s => s.GetArtist(It.IsAny<int>()))
.Returns(new Series()); .Returns(new Artist());
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Series>(), It.IsAny<bool>(), null)) .Setup(s => s.GetAlbums(It.IsAny<ParsedAlbumInfo>(), It.IsAny<Artist>(), null))
.Returns(new List<Episode>{ _episode }); .Returns(new List<Album>{ _album });
} }
private void AddPending(int id, int seasonNumber, int[] episodes) private void AddPending(int id, string album)
{ {
_pending.Add(new PendingRelease _pending.Add(new PendingRelease
{ {
Id = id, Id = id,
ParsedEpisodeInfo = new ParsedEpisodeInfo { SeasonNumber = seasonNumber, EpisodeNumbers = episodes } ParsedAlbumInfo = new ParsedAlbumInfo { AlbumTitle = album}
}); });
} }
[Test] [Test]
public void should_remove_same_release() public void should_remove_same_release()
{ {
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 3 }); AddPending(id: 1, album: "Album" );
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 1, _episode.Id)); var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-album{1}", 1, _album.Id));
Subject.RemovePendingQueueItems(queueId); Subject.RemovePendingQueueItems(queueId);
@ -67,12 +67,12 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
[Test] [Test]
public void should_remove_multiple_releases_release() public void should_remove_multiple_releases_release()
{ {
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 1 }); AddPending(id: 1, album: "Album 1");
AddPending(id: 2, seasonNumber: 2, episodes: new[] { 2 }); AddPending(id: 2, album: "Album 2");
AddPending(id: 3, seasonNumber: 2, episodes: new[] { 3 }); AddPending(id: 3, album: "Album 3");
AddPending(id: 4, seasonNumber: 2, episodes: new[] { 3 }); AddPending(id: 4, album: "Album 3");
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 3, _episode.Id)); var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-album{1}", 3, _album.Id));
Subject.RemovePendingQueueItems(queueId); Subject.RemovePendingQueueItems(queueId);
@ -80,61 +80,20 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
} }
[Test] [Test]
public void should_not_remove_diffrent_season() public void should_not_remove_diffrent_albums()
{ {
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 1 }); AddPending(id: 1, album: "Album 1");
AddPending(id: 2, seasonNumber: 2, episodes: new[] { 1 }); AddPending(id: 2, album: "Album 1");
AddPending(id: 3, seasonNumber: 3, episodes: new[] { 1 }); AddPending(id: 3, album: "Album 2");
AddPending(id: 4, seasonNumber: 3, episodes: new[] { 1 }); AddPending(id: 4, album: "Album 3");
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 1, _episode.Id)); var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-album{1}", 1, _album.Id));
Subject.RemovePendingQueueItems(queueId); Subject.RemovePendingQueueItems(queueId);
AssertRemoved(1, 2); AssertRemoved(1, 2);
} }
[Test]
public void should_not_remove_diffrent_episodes()
{
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 1 });
AddPending(id: 2, seasonNumber: 2, episodes: new[] { 1 });
AddPending(id: 3, seasonNumber: 2, episodes: new[] { 2 });
AddPending(id: 4, seasonNumber: 2, episodes: new[] { 3 });
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 1, _episode.Id));
Subject.RemovePendingQueueItems(queueId);
AssertRemoved(1, 2);
}
[Test]
public void should_not_remove_multiepisodes()
{
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 1 });
AddPending(id: 2, seasonNumber: 2, episodes: new[] { 1, 2 });
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 1, _episode.Id));
Subject.RemovePendingQueueItems(queueId);
AssertRemoved(1);
}
[Test]
public void should_not_remove_singleepisodes()
{
AddPending(id: 1, seasonNumber: 2, episodes: new[] { 1 });
AddPending(id: 2, seasonNumber: 2, episodes: new[] { 1, 2 });
var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-ep{1}", 2, _episode.Id));
Subject.RemovePendingQueueItems(queueId);
AssertRemoved(2);
}
private void AssertRemoved(params int[] ids) private void AssertRemoved(params int[] ids)
{ {
Mocker.GetMock<IPendingReleaseRepository>().Verify(c => c.DeleteMany(It.Is<IEnumerable<int>>(s => s.SequenceEqual(ids)))); Mocker.GetMock<IPendingReleaseRepository>().Verify(c => c.DeleteMany(It.Is<IEnumerable<int>>(s => s.SequenceEqual(ids))));

@ -14,7 +14,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{ {
@ -22,20 +22,20 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
public class RemoveRejectedFixture : CoreTest<PendingReleaseService> public class RemoveRejectedFixture : CoreTest<PendingReleaseService>
{ {
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Artist _artist;
private Episode _episode; private Album _album;
private Profile _profile; private Profile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedAlbumInfo _parsedAlbumInfo;
private RemoteEpisode _remoteEpisode; private RemoteAlbum _remoteAlbum;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_series = Builder<Series>.CreateNew() _artist = Builder<Artist>.CreateNew()
.Build(); .Build();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new Profile
@ -50,32 +50,32 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _artist.Profile = new LazyLoaded<Profile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();
_parsedEpisodeInfo = Builder<ParsedEpisodeInfo>.CreateNew().Build(); _parsedAlbumInfo = Builder<ParsedAlbumInfo>.CreateNew().Build();
_parsedEpisodeInfo.Quality = new QualityModel(Quality.MP3_192); _parsedAlbumInfo.Quality = new QualityModel(Quality.MP3_192);
_remoteEpisode = new RemoteEpisode(); _remoteAlbum = new RemoteAlbum();
_remoteEpisode.Episodes = new List<Episode>{ _episode }; _remoteAlbum.Albums = new List<Album>{ _album };
_remoteEpisode.Series = _series; _remoteAlbum.Artist = _artist;
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo; _remoteAlbum.ParsedAlbumInfo = _parsedAlbumInfo;
_remoteEpisode.Release = _release; _remoteAlbum.Release = _release;
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary)); _temporarilyRejected = new DownloadDecision(_remoteAlbum, new Rejection("Temp Rejected", RejectionType.Temporary));
Mocker.GetMock<IPendingReleaseRepository>() Mocker.GetMock<IPendingReleaseRepository>()
.Setup(s => s.All()) .Setup(s => s.All())
.Returns(new List<PendingRelease>()); .Returns(new List<PendingRelease>());
Mocker.GetMock<ISeriesService>() Mocker.GetMock<IArtistService>()
.Setup(s => s.GetSeries(It.IsAny<int>())) .Setup(s => s.GetArtist(It.IsAny<int>()))
.Returns(_series); .Returns(_artist);
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null)) .Setup(s => s.GetAlbums(It.IsAny<ParsedAlbumInfo>(), _artist, null))
.Returns(new List<Episode> {_episode}); .Returns(new List<Album> {_album});
Mocker.GetMock<IPrioritizeDownloadDecision>() Mocker.GetMock<IPrioritizeDownloadDecision>()
.Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>())) .Setup(s => s.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>()))
@ -91,7 +91,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
var heldReleases = Builder<PendingRelease>.CreateListOfSize(1) var heldReleases = Builder<PendingRelease>.CreateListOfSize(1)
.All() .All()
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.With(h => h.Title = title) .With(h => h.Title = title)
.With(h => h.Release = release) .With(h => h.Release = release)
.Build(); .Build();

@ -8,7 +8,7 @@ using NzbDrone.Core.History;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using System.Linq; using System.Linq;
@ -24,9 +24,9 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
.Returns(new List<History.History>(){ .Returns(new List<History.History>(){
new History.History(){ new History.History(){
DownloadId = "35238", DownloadId = "35238",
SourceTitle = "TV Series S01", SourceTitle = "Audio Artist - Audio Album",
SeriesId = 5, ArtistId = 5,
EpisodeId = 4 AlbumId = 4,
} }
}); });
} }
@ -36,20 +36,20 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenDownloadHistory(); GivenDownloadHistory();
var remoteEpisode = new RemoteEpisode var remoteAlbum = new RemoteAlbum
{ {
Series = new Series() { Id = 5 }, Artist = new Artist() { Id = 5 },
Episodes = new List<Episode> { new Episode { Id = 4 } }, Albums = new List<Album> { new Album { Id = 4 } },
ParsedEpisodeInfo = new ParsedEpisodeInfo() ParsedAlbumInfo = new ParsedAlbumInfo()
{ {
SeriesTitle = "TV Series", AlbumTitle = "Audio Album",
SeasonNumber = 1 ArtistName = "Audio Artist"
} }
}; };
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.Is<ParsedEpisodeInfo>(i => i.SeasonNumber == 1 && i.SeriesTitle == "TV Series"), It.IsAny<int>(), It.IsAny<IEnumerable<int>>())) .Setup(s => s.Map(It.Is<ParsedAlbumInfo>(i => i.AlbumTitle == "Audio Album" && i.ArtistName == "Audio Artist"), It.IsAny<int>(), It.IsAny<IEnumerable<int>>()))
.Returns(remoteEpisode); .Returns(remoteAlbum);
var client = new DownloadClientDefinition() var client = new DownloadClientDefinition()
{ {
@ -66,67 +66,11 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
var trackedDownload = Subject.TrackDownload(client, item); var trackedDownload = Subject.TrackDownload(client, item);
trackedDownload.Should().NotBeNull(); trackedDownload.Should().NotBeNull();
trackedDownload.RemoteEpisode.Should().NotBeNull(); trackedDownload.RemoteAlbum.Should().NotBeNull();
trackedDownload.RemoteEpisode.Series.Should().NotBeNull(); trackedDownload.RemoteAlbum.Artist.Should().NotBeNull();
trackedDownload.RemoteEpisode.Series.Id.Should().Be(5); trackedDownload.RemoteAlbum.Artist.Id.Should().Be(5);
trackedDownload.RemoteEpisode.Episodes.First().Id.Should().Be(4); trackedDownload.RemoteAlbum.Albums.First().Id.Should().Be(4);
trackedDownload.RemoteEpisode.ParsedEpisodeInfo.SeasonNumber.Should().Be(1);
} }
[Test]
public void should_parse_as_special_when_source_title_parsing_fails()
{
var remoteEpisode = new RemoteEpisode
{
Series = new Series() { Id = 5 },
Episodes = new List<Episode> { new Episode { Id = 4 } },
ParsedEpisodeInfo = new ParsedEpisodeInfo()
{
SeriesTitle = "TV Series",
SeasonNumber = 0,
EpisodeNumbers = new []{ 1 }
}
};
Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.Is<string>(sr => sr == "35238")))
.Returns(new List<History.History>(){
new History.History(){
DownloadId = "35238",
SourceTitle = "TV Series Special",
SeriesId = 5,
EpisodeId = 4
}
});
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.Is<ParsedEpisodeInfo>(i => i.SeasonNumber == 0 && i.SeriesTitle == "TV Series"), It.IsAny<int>(), It.IsAny<IEnumerable<int>>()))
.Returns(remoteEpisode);
Mocker.GetMock<IParsingService>()
.Setup(s => s.ParseSpecialEpisodeTitle(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Returns(remoteEpisode.ParsedEpisodeInfo);
var client = new DownloadClientDefinition()
{
Id = 1,
Protocol = DownloadProtocol.Torrent
};
var item = new DownloadClientItem()
{
Title = "The torrent release folder",
DownloadId = "35238",
};
var trackedDownload = Subject.TrackDownload(client, item);
trackedDownload.Should().NotBeNull();
trackedDownload.RemoteEpisode.Should().NotBeNull();
trackedDownload.RemoteEpisode.Series.Should().NotBeNull();
trackedDownload.RemoteEpisode.Series.Id.Should().Be(5);
trackedDownload.RemoteEpisode.Episodes.First().Id.Should().Be(4);
trackedDownload.RemoteEpisode.ParsedEpisodeInfo.SeasonNumber.Should().Be(0);
}
} }
} }

@ -32,13 +32,13 @@ namespace NzbDrone.Core.Test.HistoryTests
{ {
var historyBluray = Builder<History.History>.CreateNew() var historyBluray = Builder<History.History>.CreateNew()
.With(c => c.Quality = new QualityModel(Quality.MP3_320)) .With(c => c.Quality = new QualityModel(Quality.MP3_320))
.With(c => c.SeriesId = 12) .With(c => c.ArtistId = 12)
.With(c => c.EventType = HistoryEventType.Grabbed) .With(c => c.EventType = HistoryEventType.Grabbed)
.BuildNew(); .BuildNew();
var historyDvd = Builder<History.History>.CreateNew() var historyDvd = Builder<History.History>.CreateNew()
.With(c => c.Quality = new QualityModel(Quality.MP3_192)) .With(c => c.Quality = new QualityModel(Quality.MP3_192))
.With(c => c.SeriesId = 12) .With(c => c.ArtistId = 12)
.With(c => c.EventType = HistoryEventType.Grabbed) .With(c => c.EventType = HistoryEventType.Grabbed)
.BuildNew(); .BuildNew();

@ -4,44 +4,44 @@ using NUnit.Framework;
using NzbDrone.Core.Housekeeping.Housekeepers; using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{ {
[TestFixture] [TestFixture]
public class CleanupOrphanedHistoryItemsFixture : DbTest<CleanupOrphanedHistoryItems, History.History> public class CleanupOrphanedHistoryItemsFixture : DbTest<CleanupOrphanedHistoryItems, History.History>
{ {
private Series _series; private Artist _artist;
private Episode _episode; private Album _album;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_series = Builder<Series>.CreateNew() _artist = Builder<Artist>.CreateNew()
.BuildNew(); .BuildNew();
_episode = Builder<Episode>.CreateNew() _album = Builder<Album>.CreateNew()
.BuildNew(); .BuildNew();
} }
private void GivenSeries() private void GivenArtist()
{ {
Db.Insert(_series); Db.Insert(_artist);
} }
private void GivenEpisode() private void GivenAlbum()
{ {
Db.Insert(_episode); Db.Insert(_album);
} }
[Test] [Test]
public void should_delete_orphaned_items_by_series() public void should_delete_orphaned_items_by_artist()
{ {
GivenEpisode(); GivenAlbum();
var history = Builder<History.History>.CreateNew() var history = Builder<History.History>.CreateNew()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.EpisodeId = _episode.Id) .With(h => h.AlbumId = _album.Id)
.BuildNew(); .BuildNew();
Db.Insert(history); Db.Insert(history);
@ -50,13 +50,13 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
} }
[Test] [Test]
public void should_delete_orphaned_items_by_episode() public void should_delete_orphaned_items_by_album()
{ {
GivenSeries(); GivenArtist();
var history = Builder<History.History>.CreateNew() var history = Builder<History.History>.CreateNew()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.BuildNew(); .BuildNew();
Db.Insert(history); Db.Insert(history);
@ -65,45 +65,45 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
} }
[Test] [Test]
public void should_not_delete_unorphaned_data_by_series() public void should_not_delete_unorphaned_data_by_artist()
{ {
GivenSeries(); GivenArtist();
GivenEpisode(); GivenAlbum();
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<History.History>.CreateListOfSize(2)
.All() .All()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.EpisodeId = _episode.Id) .With(h => h.AlbumId = _album.Id)
.TheFirst(1) .TheFirst(1)
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.BuildListOfNew(); .BuildListOfNew();
Db.InsertMany(history); Db.InsertMany(history);
Subject.Clean(); Subject.Clean();
AllStoredModels.Should().HaveCount(1); AllStoredModels.Should().HaveCount(1);
AllStoredModels.Should().Contain(h => h.SeriesId == _series.Id); AllStoredModels.Should().Contain(h => h.ArtistId == _artist.Id);
} }
[Test] [Test]
public void should_not_delete_unorphaned_data_by_episode() public void should_not_delete_unorphaned_data_by_album()
{ {
GivenSeries(); GivenArtist();
GivenEpisode(); GivenAlbum();
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<History.History>.CreateListOfSize(2)
.All() .All()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.SeriesId = _series.Id) .With(h => h.ArtistId = _artist.Id)
.TheFirst(1) .TheFirst(1)
.With(h => h.EpisodeId = _episode.Id) .With(h => h.AlbumId = _album.Id)
.BuildListOfNew(); .BuildListOfNew();
Db.InsertMany(history); Db.InsertMany(history);
Subject.Clean(); Subject.Clean();
AllStoredModels.Should().HaveCount(1); AllStoredModels.Should().HaveCount(1);
AllStoredModels.Should().Contain(h => h.EpisodeId == _episode.Id); AllStoredModels.Should().Contain(h => h.AlbumId == _album.Id);
} }
} }
} }

@ -5,7 +5,7 @@ using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.Housekeeping.Housekeepers; using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{ {
@ -16,7 +16,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
public void should_delete_orphaned_pending_items() public void should_delete_orphaned_pending_items()
{ {
var pendingRelease = Builder<PendingRelease>.CreateNew() var pendingRelease = Builder<PendingRelease>.CreateNew()
.With(h => h.ParsedEpisodeInfo = new ParsedEpisodeInfo()) .With(h => h.ParsedAlbumInfo = new ParsedAlbumInfo())
.With(h => h.Release = new ReleaseInfo()) .With(h => h.Release = new ReleaseInfo())
.BuildNew(); .BuildNew();
@ -28,13 +28,13 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
[Test] [Test]
public void should_not_delete_unorphaned_pending_items() public void should_not_delete_unorphaned_pending_items()
{ {
var series = Builder<Series>.CreateNew().BuildNew(); var artist = Builder<Artist>.CreateNew().BuildNew();
Db.Insert(series); Db.Insert(artist);
var pendingRelease = Builder<PendingRelease>.CreateNew() var pendingRelease = Builder<PendingRelease>.CreateNew()
.With(h => h.SeriesId = series.Id) .With(h => h.ArtistId = artist.Id)
.With(h => h.ParsedEpisodeInfo = new ParsedEpisodeInfo()) .With(h => h.ParsedAlbumInfo = new ParsedAlbumInfo())
.With(h => h.Release = new ReleaseInfo()) .With(h => h.Release = new ReleaseInfo())
.BuildNew(); .BuildNew();

@ -51,8 +51,6 @@ namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/09/16 21:15:33")); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/09/16 21:15:33"));
torrentInfo.Size.Should().Be(505099926); torrentInfo.Size.Should().Be(505099926);
torrentInfo.InfoHash.Should().Be("123"); torrentInfo.InfoHash.Should().Be("123");
torrentInfo.TvdbId.Should().Be(71998);
torrentInfo.TvRageId.Should().Be(4055);
torrentInfo.MagnetUrl.Should().BeNullOrEmpty(); torrentInfo.MagnetUrl.Should().BeNullOrEmpty();
torrentInfo.Peers.Should().Be(40+9); torrentInfo.Peers.Should().Be(40+9);
torrentInfo.Seeders.Should().Be(40); torrentInfo.Seeders.Should().Be(40);

@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
_singleAlbumSearchCriteria = new AlbumSearchCriteria _singleAlbumSearchCriteria = new AlbumSearchCriteria
{ {
Artist = new Music.Artist { Name = "Alien Ant Farm" }, Artist = new Music.Artist { Name = "Alien Ant Farm" },
Album = new Music.Album { Title = "TruANT" } Albums = new List<Music.Album> { new Music.Album { Title = "TruANT" } }
}; };

@ -56,8 +56,6 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests
torrentInfo.MagnetUrl.Should().BeNull(); torrentInfo.MagnetUrl.Should().BeNull();
torrentInfo.Peers.Should().Be(304 + 200); torrentInfo.Peers.Should().Be(304 + 200);
torrentInfo.Seeders.Should().Be(304); torrentInfo.Seeders.Should().Be(304);
torrentInfo.TvdbId.Should().Be(268156);
torrentInfo.TvRageId.Should().Be(35197);
} }
[Test] [Test]

@ -60,8 +60,6 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
releaseInfo.Indexer.Should().Be(Subject.Definition.Name); releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2015/03/14 21:10:42")); releaseInfo.PublishDate.Should().Be(DateTime.Parse("2015/03/14 21:10:42"));
releaseInfo.Size.Should().Be(2538463390); releaseInfo.Size.Should().Be(2538463390);
releaseInfo.TvdbId.Should().Be(273181);
releaseInfo.TvRageId.Should().Be(37780);
releaseInfo.InfoHash.Should().Be("63e07ff523710ca268567dad344ce1e0e6b7e8a3"); releaseInfo.InfoHash.Should().Be("63e07ff523710ca268567dad344ce1e0e6b7e8a3");
releaseInfo.Seeders.Should().Be(7); releaseInfo.Seeders.Should().Be(7);
releaseInfo.Peers.Should().Be(7); releaseInfo.Peers.Should().Be(7);

@ -151,13 +151,12 @@
<Compile Include="Datastore\ReflectionStrategyFixture\Benchmarks.cs" /> <Compile Include="Datastore\ReflectionStrategyFixture\Benchmarks.cs" />
<Compile Include="Datastore\SqliteSchemaDumperTests\SqliteSchemaDumperFixture.cs" /> <Compile Include="Datastore\SqliteSchemaDumperTests\SqliteSchemaDumperFixture.cs" />
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\AnimeVersionUpgradeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\CutoffSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\CutoffSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" /> <Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />
<Compile Include="DecisionEngineTests\HistorySpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\HistorySpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\MonitoredEpisodeSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\MonitoredAlbumSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\QueueSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\QueueSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\ReleaseRestrictionsSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\ReleaseRestrictionsSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" /> <Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
@ -167,7 +166,7 @@
<Compile Include="DecisionEngineTests\RetentionSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\RetentionSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\Search\ArtistSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\SameEpisodesSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\SameEpisodesSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\RawDiskSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\RawDiskSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />

@ -1,4 +1,4 @@
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -62,5 +62,52 @@ namespace NzbDrone.Core.Test.ParserTests
{ {
Parser.Parser.ParseTitle(postTitle).SeriesTitle.Should().Be(title); Parser.Parser.ParseTitle(postTitle).SeriesTitle.Should().Be(title);
} }
[TestCase("VA - The Best 101 Love Ballads (2017) MP3 [192 kbps]", "The Best 101 Love Ballads")]
[TestCase("ATCQ - The Love Movement 1998 2CD 192kbps RIP", "The Love Movement")]
[TestCase("A Tribe Called Quest - The Love Movement 1998 2CD [192kbps] RIP", "The Love Movement")]
[TestCase("Maula - Jism 2 [2012] Mp3 - 192Kbps [Extended]- TK", "Jism 2")]
[TestCase("VA - Complete Clubland - The Ultimate Ride Of Your Lfe [2014][MP3][192 kbps]")]
[TestCase("Complete Clubland - The Ultimate Ride Of Your Lfe [2014][MP3](192kbps)", "The Ultimate Ride Of Your Lfe")]
[TestCase("The Ultimate Ride Of Your Lfe [192 KBPS][2014][MP3]", "The Ultimate Ride Of Your Lfe")]
[TestCase("Gary Clark Jr - Live North America 2016 (2017) MP3 192kbps", "Live North America 2016")]
[TestCase("Beyoncé Lemonade [320] 2016 Beyonce Lemonade [320] 2016", "Lemonade")]
[TestCase("Childish Gambino - Awaken, My Love Album 2016 mp3 320 Kbps", "Awaken, My Love Album")]
[TestCase("Maluma Felices Los 4 MP3 320 Kbps 2017 Download", "Felices Los 4")]
[TestCase("Ricardo Arjona - APNEA (Single 2014) (320 kbps)", "APNEA")]
[TestCase("Kehlani - SweetSexySavage (Deluxe Edition) (2017) 320", "SweetSexySavage")]
[TestCase("Anderson Paak - Malibu (320)(2016)", "Malibu")]
[TestCase("Caetano Veloso Discografia Completa MP3 @256","")]
[TestCase("Little Mix - Salute [Deluxe Edition] [2013] [M4A-256]-V3nom [GLT", "Salute")]
[TestCase("Ricky Martin - A Quien Quiera Escuchar (2015) 256 kbps [GloDLS]", "A Quien Quiera Escuchar")]
[TestCase("Jake Bugg - Jake Bugg (Album) [2012] {MP3 256 kbps}", "Jake Bugg")]
[TestCase("Milky Chance - Sadnecessary [256 Kbps] [M4A]", "Sadnecessary")]
[TestCase("Clean Bandit - New Eyes [2014] [Mp3-256]-V3nom [GLT]", "New Eyes")]
[TestCase("Armin van Buuren - A State Of Trance 810 (20.04.2017) 256 kbps", "A State Of Trance 810")]
[TestCase("PJ Harvey - Let England Shake [mp3-256-2011][trfkad]", "Let England Shake")]
[TestCase("X-Men Soundtracks (2006-2014) AAC, 256 kbps","")]
[TestCase("Walk the Line Soundtrack (2005) [AAC, 256 kbps]", "Walk the Line Soundtrack")]
[TestCase("Emeli Sande Next To Me (512 Kbps)", "Next To Me")]
[TestCase("Kendrick Lamar - DAMN (2017) FLAC", "DAMN")]
[TestCase("Alicia Keys - Vault Playlist Vol. 1 (2017) [FLAC CD]", "Vault Playlist Vol 1")]
[TestCase("Gorillaz - Humanz (Deluxe) - lossless FLAC Tracks - 2017 - CDrip", "Humanz")]
[TestCase("David Bowie - Blackstar (2016) [FLAC]", "Blackstar")]
[TestCase("The Cure - Greatest Hits (2001) FLAC Soup", "Greatest Hits")]
[TestCase("Slowdive - Souvlaki (FLAC)", "Souvlaki")]
[TestCase("John Coltrane - Kulu Se Mama (1965) [EAC-FLAC]", "Kulu Se Mama")]
[TestCase("The Rolling Stones - The Very Best Of '75-'94 (1995) {FLAC}", "The Very Best Of '75-'94")]
[TestCase("Migos-No_Label_II-CD-FLAC-2014-FORSAKEN", "No Label II")]
[TestCase("ADELE 25 CD FLAC 2015 PERFECT", "25")]
[TestCase("A.I. - Sex & Robots [2007/MP3/V0(VBR)]", "Sex & Robots")]
[TestCase("Jay-Z - 4:44 (Deluxe Edition) (2017) 320", "444")]
[TestCase("Roberta Flack 2006 - The Very Best of", "The Very Best of")]
[TestCase("VA - NOW Thats What I Call Music 96 (2017) [Mp3~Kbps]", "NOW Thats What I Call Music 96")]
[TestCase("Queen - The Ultimate Best Of Queen(2011)[mp3]", "The Ultimate Best Of Queen")]
[TestCase("Little Mix - Salute [Deluxe Edition] [2013] [M4A-256]-V3nom [GLT]", "Salute")]
[TestCase("Barış Manço - Ben Bilirim [1993/FLAC/Lossless/Log]", "Ben Bilirim")]
public void should_parse_album_title(string postTitle, string title)
{
Parser.Parser.ParseAlbumTitle(postTitle).AlbumTitle.Should().Be(title);
}
} }
} }

@ -0,0 +1,36 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(112)]
public class music_history : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("History")
.AddColumn("ArtistId").AsInt32().WithDefaultValue(0)
.AddColumn("AlbumId").AsInt32().WithDefaultValue(0);
Alter.Table("PendingReleases")
.AddColumn("ArtistId").AsInt32().WithDefaultValue(0)
.AddColumn("ParsedAlbumInfo").AsString().WithDefaultValue("");
Alter.Table("Tracks")
.AddColumn("Duration").AsInt32().WithDefaultValue(0);
Alter.Table("Albums")
.AddColumn("Duration").AsInt32().WithDefaultValue(0);
Delete.Column("SeriesId").FromTable("History");
Delete.Column("EpisodeId").FromTable("History");
Delete.Column("SeriesId").FromTable("PendingReleases");
Delete.Column("ParsedEpisodeInfo").FromTable("PendingReleases");
}
}
}

@ -106,7 +106,7 @@ namespace NzbDrone.Core.Datastore
.For("Tracks") .For("Tracks")
.LazyLoad(condition: parent => parent.Id > 0, .LazyLoad(condition: parent => parent.Id > 0,
query: (db, parent) => db.Query<Track>().Where(c => c.ArtistId == parent.Id).ToList()) // TODO: Figure what the hell to do here query: (db, parent) => db.Query<Track>().Where(c => c.ArtistId == parent.Id).ToList()) // TODO: Figure what the hell to do here
.HasOne(file => file.Artist, file => file.AlbumId); .HasOne(file => file.Artist, file => file.ArtistId);
Mapper.Entity<Track>().RegisterModel("Tracks") Mapper.Entity<Track>().RegisterModel("Tracks")
//.Ignore(e => e.SeriesTitle) //.Ignore(e => e.SeriesTitle)

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -6,7 +6,7 @@ namespace NzbDrone.Core.DecisionEngine
{ {
public class DownloadDecision public class DownloadDecision
{ {
public RemoteEpisode RemoteEpisode { get; private set; } public RemoteAlbum RemoteAlbum { get; private set; }
public IEnumerable<Rejection> Rejections { get; private set; } public IEnumerable<Rejection> Rejections { get; private set; }
public bool Approved => !Rejections.Any(); public bool Approved => !Rejections.Any();
@ -27,9 +27,9 @@ namespace NzbDrone.Core.DecisionEngine
} }
} }
public DownloadDecision(RemoteEpisode episode, params Rejection[] rejections) public DownloadDecision(RemoteAlbum album, params Rejection[] rejections)
{ {
RemoteEpisode = episode; RemoteAlbum = album;
Rejections = rejections.ToList(); Rejections = rejections.ToList();
} }
@ -37,10 +37,10 @@ namespace NzbDrone.Core.DecisionEngine
{ {
if (Approved) if (Approved)
{ {
return "[OK] " + RemoteEpisode; return "[OK] " + RemoteAlbum;
} }
return "[Rejected " + Rejections.Count() + "]" + RemoteEpisode; return "[Rejected " + Rejections.Count() + "]" + RemoteAlbum;
} }
} }
} }

@ -4,7 +4,6 @@ using System.Linq;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine namespace NzbDrone.Core.DecisionEngine
{ {
@ -25,9 +24,8 @@ namespace NzbDrone.Core.DecisionEngine
{ {
CompareQuality, CompareQuality,
CompareProtocol, CompareProtocol,
CompareEpisodeCount,
CompareEpisodeNumber,
ComparePeersIfTorrent, ComparePeersIfTorrent,
CompareAlbumCount,
CompareAgeIfUsenet, CompareAgeIfUsenet,
CompareSize CompareSize
}; };
@ -57,67 +55,48 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareQuality(DownloadDecision x, DownloadDecision y) private int CompareQuality(DownloadDecision x, DownloadDecision y)
{ {
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedEpisodeInfo.Quality.Quality)), return CompareAll(CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Artist.Profile.Value.Items.FindIndex(v => v.Quality == remoteAlbum.ParsedAlbumInfo.Quality.Quality)),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Real), CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision.Real),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version)); CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision.Version));
} }
private int CompareProtocol(DownloadDecision x, DownloadDecision y) private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{ {
var result = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => var result = CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
{ {
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Series.Tags); var delayProfile = _delayProfileService.BestForTags(remoteAlbum.Artist.Tags);
var downloadProtocol = remoteEpisode.Release.DownloadProtocol; var downloadProtocol = remoteAlbum.Release.DownloadProtocol;
return downloadProtocol == delayProfile.PreferredProtocol; return downloadProtocol == delayProfile.PreferredProtocol;
}); });
return result; return result;
} }
private int CompareEpisodeCount(DownloadDecision x, DownloadDecision y) private int CompareAlbumCount(DownloadDecision x, DownloadDecision y)
{ {
var seasonPackCompare = CompareBy(x.RemoteEpisode, y.RemoteEpisode, return CompareByReverse(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Albums.Count);
remoteEpisode => remoteEpisode.ParsedEpisodeInfo.FullSeason);
if (seasonPackCompare != 0)
{
return seasonPackCompare;
}
if (x.RemoteEpisode.Series.SeriesType == SeriesTypes.Anime &
y.RemoteEpisode.Series.SeriesType == SeriesTypes.Anime)
{
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Episodes.Count);
}
return CompareByReverse(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Episodes.Count);
}
private int CompareEpisodeNumber(DownloadDecision x, DownloadDecision y)
{
return CompareByReverse(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault());
} }
private int ComparePeersIfTorrent(DownloadDecision x, DownloadDecision y) private int ComparePeersIfTorrent(DownloadDecision x, DownloadDecision y)
{ {
// Different protocols should get caught when checking the preferred protocol, // Different protocols should get caught when checking the preferred protocol,
// since we're dealing with the same series in our comparisions // since we're dealing with the same series in our comparisions
if (x.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent || if (x.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent) y.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Torrent)
{ {
return 0; return 0;
} }
return CompareAll( return CompareAll(
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
{ {
var seeders = TorrentInfo.GetSeeders(remoteEpisode.Release); var seeders = TorrentInfo.GetSeeders(remoteAlbum.Release);
return seeders.HasValue && seeders.Value > 0 ? Math.Round(Math.Log10(seeders.Value)) : 0; return seeders.HasValue && seeders.Value > 0 ? Math.Round(Math.Log10(seeders.Value)) : 0;
}), }),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
{ {
var peers = TorrentInfo.GetPeers(remoteEpisode.Release); var peers = TorrentInfo.GetPeers(remoteAlbum.Release);
return peers.HasValue && peers.Value > 0 ? Math.Round(Math.Log10(peers.Value)) : 0; return peers.HasValue && peers.Value > 0 ? Math.Round(Math.Log10(peers.Value)) : 0;
})); }));
@ -125,16 +104,16 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareAgeIfUsenet(DownloadDecision x, DownloadDecision y) private int CompareAgeIfUsenet(DownloadDecision x, DownloadDecision y)
{ {
if (x.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Usenet || if (x.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Usenet ||
y.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Usenet) y.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Usenet)
{ {
return 0; return 0;
} }
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
{ {
var ageHours = remoteEpisode.Release.AgeHours; var ageHours = remoteAlbum.Release.AgeHours;
var age = remoteEpisode.Release.Age; var age = remoteAlbum.Release.Age;
if (ageHours < 1) if (ageHours < 1)
{ {
@ -159,7 +138,7 @@ namespace NzbDrone.Core.DecisionEngine
{ {
// TODO: Is smaller better? Smaller for usenet could mean no par2 files. // TODO: Is smaller better? Smaller for usenet could mean no par2 files.
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes())); return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Release.Size.Round(200.Megabytes()));
} }
} }
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
@ -32,21 +32,20 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> GetRssDecision(List<ReleaseInfo> reports) public List<DownloadDecision> GetRssDecision(List<ReleaseInfo> reports)
{ {
return GetDecisions(reports).ToList(); return GetAlbumDecisions(reports).ToList();
} }
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase) public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
{ {
return GetDecisions(reports, searchCriteriaBase).ToList(); return GetAlbumDecisions(reports, searchCriteriaBase).ToList();
} }
private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null) private IEnumerable<DownloadDecision> GetAlbumDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
{ {
if (reports.Any()) if (reports.Any())
{ {
_logger.ProgressInfo("Processing {0} releases", reports.Count); _logger.ProgressInfo("Processing {0} releases", reports.Count);
} }
else else
{ {
_logger.ProgressInfo("No results found"); _logger.ProgressInfo("No results found");
@ -61,35 +60,25 @@ namespace NzbDrone.Core.DecisionEngine
try try
{ {
var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title); var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(report.Title);
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode) if (parsedAlbumInfo != null && !parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace())
{ {
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(report.Title, report.TvdbId, report.TvRageId, searchCriteria); var remoteAlbum = _parsingService.Map(parsedAlbumInfo, searchCriteria);
remoteAlbum.Release = report;
if (specialEpisodeInfo != null) if (remoteAlbum.Artist == null)
{ {
parsedEpisodeInfo = specialEpisodeInfo; decision = new DownloadDecision(remoteAlbum, new Rejection("Unknown Artist"));
} }
} else if (remoteAlbum.Albums.Empty())
if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
{
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, searchCriteria);
remoteEpisode.Release = report;
if (remoteEpisode.Series == null)
{ {
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown Series")); decision = new DownloadDecision(remoteAlbum, new Rejection("Unable to parse albums from release name"));
}
else if (remoteEpisode.Episodes.Empty())
{
decision = new DownloadDecision(remoteEpisode, new Rejection("Unable to parse episodes from release name"));
} }
else else
{ {
remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any(); remoteAlbum.DownloadAllowed = remoteAlbum.Albums.Any();
decision = GetDecisionForReport(remoteEpisode, searchCriteria); decision = GetDecisionForReport(remoteAlbum, searchCriteria);
} }
} }
} }
@ -97,8 +86,8 @@ namespace NzbDrone.Core.DecisionEngine
{ {
_logger.Error(e, "Couldn't process release."); _logger.Error(e, "Couldn't process release.");
var remoteEpisode = new RemoteEpisode { Release = report }; var remoteAlbum = new RemoteAlbum { Release = report };
decision = new DownloadDecision(remoteEpisode, new Rejection("Unexpected error processing release")); decision = new DownloadDecision(remoteAlbum, new Rejection("Unexpected error processing release"));
} }
reportNumber++; reportNumber++;
@ -120,30 +109,34 @@ namespace NzbDrone.Core.DecisionEngine
} }
} }
private DownloadDecision GetDecisionForReport(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria = null) private DownloadDecision GetDecisionForReport(RemoteAlbum remoteAlbum, SearchCriteriaBase searchCriteria = null)
{ {
var reasons = _specifications.Select(c => EvaluateSpec(c, remoteEpisode, searchCriteria)) var reasons = _specifications.Select(c => EvaluateSpec(c, remoteAlbum, searchCriteria))
.Where(c => c != null); .Where(c => c != null);
return new DownloadDecision(remoteEpisode, reasons.ToArray()); return new DownloadDecision(remoteAlbum, reasons.ToArray());
} }
private Rejection EvaluateSpec(IDecisionEngineSpecification spec, RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteriaBase = null) private Rejection EvaluateSpec(IDecisionEngineSpecification spec, RemoteAlbum remoteAlbum, SearchCriteriaBase searchCriteriaBase = null)
{ {
try try
{ {
var result = spec.IsSatisfiedBy(remoteEpisode, searchCriteriaBase); var result = spec.IsSatisfiedBy(remoteAlbum, searchCriteriaBase);
if (!result.Accepted) if (!result.Accepted)
{ {
return new Rejection(result.Reason, spec.Type); return new Rejection(result.Reason, spec.Type);
} }
} }
catch (NotImplementedException e)
{
_logger.Trace("Spec " + spec.GetType().Name + " not implemented.");
}
catch (Exception e) catch (Exception e)
{ {
e.Data.Add("report", remoteEpisode.Release.ToJson()); e.Data.Add("report", remoteAlbum.Release.ToJson());
e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson()); e.Data.Add("parsed", remoteAlbum.ParsedAlbumInfo.ToJson());
_logger.Error(e, "Couldn't evaluate decision on {0}", remoteEpisode.Release.Title); _logger.Error(e, "Couldn't evaluate decision on {0}", remoteAlbum.Release.Title);
return new Rejection($"{spec.GetType().Name}: {e.Message}"); return new Rejection($"{spec.GetType().Name}: {e.Message}");
} }

@ -20,13 +20,13 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions) public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions)
{ {
return decisions.Where(c => c.RemoteEpisode.Series != null) return decisions.Where(c => c.RemoteAlbum.Artist != null)
.GroupBy(c => c.RemoteEpisode.Series.Id, (seriesId, downloadDecisions) => .GroupBy(c => c.RemoteAlbum.Artist.Id, (artistId, downloadDecisions) =>
{ {
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService)); return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService));
}) })
.SelectMany(c => c) .SelectMany(c => c)
.Union(decisions.Where(c => c.RemoteEpisode.Series == null)) .Union(decisions.Where(c => c.RemoteAlbum.Artist == null))
.ToList(); .ToList();
} }
} }

@ -1,4 +1,4 @@
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine namespace NzbDrone.Core.DecisionEngine
@ -7,6 +7,6 @@ namespace NzbDrone.Core.DecisionEngine
{ {
RejectionType Type { get; } RejectionType Type { get; }
Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria); Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria);
} }
} }

@ -1,10 +1,9 @@
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using System.Collections.Generic; using System.Collections.Generic;
namespace NzbDrone.Core.DecisionEngine.Specifications namespace NzbDrone.Core.DecisionEngine.Specifications
@ -12,29 +11,21 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public class AcceptableSizeSpecification : IDecisionEngineSpecification public class AcceptableSizeSpecification : IDecisionEngineSpecification
{ {
private readonly IQualityDefinitionService _qualityDefinitionService; private readonly IQualityDefinitionService _qualityDefinitionService;
private readonly IEpisodeService _episodeService;
private readonly Logger _logger; private readonly Logger _logger;
public AcceptableSizeSpecification(IQualityDefinitionService qualityDefinitionService, IEpisodeService episodeService, Logger logger) public AcceptableSizeSpecification(IQualityDefinitionService qualityDefinitionService, Logger logger)
{ {
_qualityDefinitionService = qualityDefinitionService; _qualityDefinitionService = qualityDefinitionService;
_episodeService = episodeService;
_logger = logger; _logger = logger;
} }
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
_logger.Debug("Beginning size check for: {0}", subject); _logger.Debug("Beginning size check for: {0}", subject);
var quality = subject.ParsedEpisodeInfo.Quality.Quality; var quality = subject.ParsedAlbumInfo.Quality.Quality;
if (subject.ParsedEpisodeInfo.Special)
{
_logger.Debug("Special release found, skipping size check.");
return Decision.Accept();
}
if (subject.Release.Size == 0) if (subject.Release.Size == 0)
{ {
@ -43,20 +34,22 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
} }
var qualityDefinition = _qualityDefinitionService.Get(quality); var qualityDefinition = _qualityDefinitionService.Get(quality);
var albumsDuration = subject.Albums.Sum(album => album.Duration) / 60000;
if (qualityDefinition.MinSize.HasValue) if (qualityDefinition.MinSize.HasValue)
{ {
var minSize = qualityDefinition.MinSize.Value.Megabytes(); var minSize = qualityDefinition.MinSize.Value.Megabytes();
//Multiply maxSize by Series.Runtime //Multiply minSize by Album.Duration
minSize = minSize * subject.Series.Runtime * subject.Episodes.Count; minSize = minSize * albumsDuration;
//If the parsed size is smaller than minSize we don't want it //If the parsed size is smaller than minSize we don't want it
if (subject.Release.Size < minSize) if (subject.Release.Size < minSize)
{ {
var runtimeMessage = subject.Episodes.Count == 1 ? $"{subject.Series.Runtime}min" : $"{subject.Episodes.Count}x {subject.Series.Runtime}min"; var runtimeMessage = $"{albumsDuration}min";
_logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes for {3}), rejecting.", subject, subject.Release.Size, minSize, runtimeMessage); _logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes), rejecting.", subject, subject.Release.Size, minSize);
return Decision.Reject("{0} is smaller than minimum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix(), runtimeMessage); return Decision.Reject("{0} is smaller than minimum allowed {1}", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix());
} }
} }
if (!qualityDefinition.MaxSize.HasValue || qualityDefinition.MaxSize.Value == 0) if (!qualityDefinition.MaxSize.HasValue || qualityDefinition.MaxSize.Value == 0)
@ -67,40 +60,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
var maxSize = qualityDefinition.MaxSize.Value.Megabytes(); var maxSize = qualityDefinition.MaxSize.Value.Megabytes();
//Multiply maxSize by Series.Runtime //Multiply maxSize by Album.Duration
maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count; maxSize = maxSize * albumsDuration;
if (subject.Episodes.Count == 1)
{
Episode episode = subject.Episodes.First();
List<Episode> seasonEpisodes;
var seasonSearchCriteria = searchCriteria as SeasonSearchCriteria;
if (seasonSearchCriteria != null && !seasonSearchCriteria.Series.UseSceneNumbering && seasonSearchCriteria.Episodes.Any(v => v.Id == episode.Id))
{
seasonEpisodes = (searchCriteria as SeasonSearchCriteria).Episodes;
}
else
{
seasonEpisodes = _episodeService.GetEpisodesBySeason(episode.SeriesId, episode.SeasonNumber);
}
//Ensure that this is either the first episode
//or is the last episode in a season that has 10 or more episodes
if (seasonEpisodes.First().Id == episode.Id || (seasonEpisodes.Count() >= 10 && seasonEpisodes.Last().Id == episode.Id))
{
_logger.Debug("Possible double episode, doubling allowed size.");
maxSize = maxSize * 2;
}
}
//If the parsed size is greater than maxSize we don't want it //If the parsed size is greater than maxSize we don't want it
if (subject.Release.Size > maxSize) if (subject.Release.Size > maxSize)
{ {
var runtimeMessage = subject.Episodes.Count == 1 ? $"{subject.Series.Runtime}min" : $"{subject.Episodes.Count}x {subject.Series.Runtime}min"; var runtimeMessage = $"{albumsDuration}min";
_logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2} for {3}), rejecting.", subject, subject.Release.Size, maxSize, runtimeMessage); _logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2}), rejecting.", subject, subject.Release.Size, maxSize);
return Decision.Reject("{0} is larger than maximum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix(), runtimeMessage); return Decision.Reject("{0} is larger than maximum allowed {1}", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix());
} }
} }

@ -1,59 +0,0 @@
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class AnimeVersionUpgradeSpecification : IDecisionEngineSpecification
{
private readonly QualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly Logger _logger;
public AnimeVersionUpgradeSpecification(QualityUpgradableSpecification qualityUpgradableSpecification, Logger logger)
{
_qualityUpgradableSpecification = qualityUpgradableSpecification;
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
var releaseGroup = subject.ParsedEpisodeInfo.ReleaseGroup;
if (subject.Series.SeriesType != SeriesTypes.Anime)
{
return Decision.Accept();
}
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
{
if (_qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedEpisodeInfo.Quality))
{
if (file.ReleaseGroup.IsNullOrWhiteSpace())
{
_logger.Debug("Unable to compare release group, existing file's release group is unknown");
return Decision.Reject("Existing release group is unknown");
}
if (releaseGroup.IsNullOrWhiteSpace())
{
_logger.Debug("Unable to compare release group, release's release group is unknown");
return Decision.Reject("Release group is unknown");
}
if (file.ReleaseGroup != releaseGroup)
{
_logger.Debug("Existing Release group is: {0} - release's release group is: {1}", file.ReleaseGroup, releaseGroup);
return Decision.Reject("{0} does not match existing release group {1}", releaseGroup, file.ReleaseGroup);
}
}
}
return Decision.Accept();
}
}
}

@ -1,4 +1,4 @@
using NLog; using NLog;
using NzbDrone.Core.Blacklisting; using NzbDrone.Core.Blacklisting;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -18,9 +18,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (_blacklistService.Blacklisted(subject.Series.Id, subject.Release)) if (_blacklistService.Blacklisted(subject.Artist.Id, subject.Release))
{ {
_logger.Debug("{0} is blacklisted, rejecting.", subject.Release.Title); _logger.Debug("{0} is blacklisted, rejecting.", subject.Release.Title);
return Decision.Reject("Release is blacklisted"); return Decision.Reject("Release is blacklisted");

@ -1,39 +1,46 @@
using System.Linq; using System;
using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.DecisionEngine.Specifications namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
public class CutoffSpecification : IDecisionEngineSpecification public class CutoffSpecification : IDecisionEngineSpecification
{ {
private readonly QualityUpgradableSpecification _qualityUpgradableSpecification; private readonly QualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly IMediaFileService _mediaFileService;
private readonly Logger _logger; private readonly Logger _logger;
public CutoffSpecification(QualityUpgradableSpecification qualityUpgradableSpecification, Logger logger) public CutoffSpecification(QualityUpgradableSpecification qualityUpgradableSpecification, Logger logger, IMediaFileService mediaFileService)
{ {
_qualityUpgradableSpecification = qualityUpgradableSpecification; _qualityUpgradableSpecification = qualityUpgradableSpecification;
_logger = logger; _logger = logger;
_mediaFileService = mediaFileService;
} }
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
foreach (var album in subject.Albums)
{ {
if (file == null) var trackFiles = _mediaFileService.GetFilesByAlbum(album.ArtistId, album.Id);
if (trackFiles.Any())
{ {
_logger.Debug("File is no longer available, skipping this file."); var lowestQuality = trackFiles.Select(c => c.Quality).OrderBy(c => c.Quality.Id).First();
continue;
}
_logger.Debug("Comparing file quality with report. Existing file is {0}", file.Quality); _logger.Debug("Comparing file quality with report. Existing file is {0}", lowestQuality);
if (!_qualityUpgradableSpecification.CutoffNotMet(subject.Artist.Profile, lowestQuality, subject.ParsedAlbumInfo.Quality))
{
_logger.Debug("Cutoff already met, rejecting.");
return Decision.Reject("Existing file meets cutoff: {0}", subject.Artist.Profile.Value.Cutoff);
}
if (!_qualityUpgradableSpecification.CutoffNotMet(subject.Series.Profile, file.Quality, subject.ParsedEpisodeInfo.Quality))
{
_logger.Debug("Cutoff already met, rejecting.");
return Decision.Reject("Existing file meets cutoff: {0}", subject.Series.Profile.Value.Cutoff);
} }
} }

@ -0,0 +1,26 @@
using System;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Common.Extensions;
using System.Linq;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class DiscographySpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public DiscographySpecification(Logger logger)
{
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{
throw new NotImplementedException();
}
}
}

@ -1,40 +0,0 @@
using System;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Common.Extensions;
using System.Linq;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class FullSeasonSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
private readonly IEpisodeService _episodeService;
public FullSeasonSpecification(Logger logger, IEpisodeService episodeService)
{
_logger = logger;
_episodeService = episodeService;
}
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
if (subject.ParsedEpisodeInfo.FullSeason)
{
_logger.Debug("Checking if all episodes in full season release have aired. {0}", subject.Release.Title);
if (subject.Episodes.Any(e => !e.AirDateUtc.HasValue || e.AirDateUtc.Value.After(DateTime.UtcNow)))
{
_logger.Debug("Full season release {0} rejected. All episodes haven't aired yet.", subject.Release.Title);
return Decision.Reject("Full season release rejected. All episodes haven't aired yet.");
}
}
return Decision.Accept();
}
}
}

@ -1,4 +1,4 @@
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -15,16 +15,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
var wantedLanguage = subject.Series.Profile.Value.Language; var wantedLanguage = subject.Artist.Profile.Value.Language;
_logger.Debug("Checking if report meets language requirements. {0}", subject.ParsedEpisodeInfo.Language); _logger.Debug("Checking if report meets language requirements. {0}", subject.ParsedAlbumInfo.Language);
if (subject.ParsedEpisodeInfo.Language != wantedLanguage) if (subject.ParsedAlbumInfo.Language != wantedLanguage)
{ {
_logger.Debug("Report Language: {0} rejected because it is not wanted, wanted {1}", subject.ParsedEpisodeInfo.Language, wantedLanguage); _logger.Debug("Report Language: {0} rejected because it is not wanted, wanted {1}", subject.ParsedAlbumInfo.Language, wantedLanguage);
return Decision.Reject("{0} is wanted, but found {1}", wantedLanguage, subject.ParsedEpisodeInfo.Language); return Decision.Reject("{0} is wanted, but found {1}", wantedLanguage, subject.ParsedAlbumInfo.Language);
} }
return Decision.Accept(); return Decision.Accept();

@ -18,7 +18,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Temporary; public RejectionType Type => RejectionType.Temporary;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet) if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet)
{ {

@ -1,4 +1,5 @@
using NLog; using System;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -15,15 +16,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (subject.Release.Title.ToLower().Contains("sample") && subject.Release.Size < 70.Megabytes()) if (subject.Release.Title.ToLower().Contains("sample") && subject.Release.Size < 20.Megabytes())
{ {
_logger.Debug("Sample release, rejecting."); _logger.Debug("Sample release, rejecting.");
return Decision.Reject("Sample"); return Decision.Reject("Sample");
} }
return Decision.Accept(); return Decision.Accept();
} }
} }
} }

@ -1,4 +1,4 @@
using NLog; using NLog;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -20,20 +20,20 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
var delayProfile = _delayProfileService.BestForTags(subject.Series.Tags); var delayProfile = _delayProfileService.BestForTags(subject.Artist.Tags);
if (subject.Release.DownloadProtocol == DownloadProtocol.Usenet && !delayProfile.EnableUsenet) if (subject.Release.DownloadProtocol == DownloadProtocol.Usenet && !delayProfile.EnableUsenet)
{ {
_logger.Debug("[{0}] Usenet is not enabled for this series", subject.Release.Title); _logger.Debug("[{0}] Usenet is not enabled for this artist", subject.Release.Title);
return Decision.Reject("Usenet is not enabled for this series"); return Decision.Reject("Usenet is not enabled for this artist");
} }
if (subject.Release.DownloadProtocol == DownloadProtocol.Torrent && !delayProfile.EnableTorrent) if (subject.Release.DownloadProtocol == DownloadProtocol.Torrent && !delayProfile.EnableTorrent)
{ {
_logger.Debug("[{0}] Torrent is not enabled for this series", subject.Release.Title); _logger.Debug("[{0}] Torrent is not enabled for this artist", subject.Release.Title);
return Decision.Reject("Torrent is not enabled for this series"); return Decision.Reject("Torrent is not enabled for this artist");
} }
return Decision.Accept(); return Decision.Accept();

@ -1,4 +1,4 @@
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -15,13 +15,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
_logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality); _logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedAlbumInfo.Quality);
if (!subject.Series.Profile.Value.Items.Exists(v => v.Allowed && v.Quality == subject.ParsedEpisodeInfo.Quality.Quality)) if (!subject.Artist.Profile.Value.Items.Exists(v => v.Allowed && v.Quality == subject.ParsedAlbumInfo.Quality.Quality))
{ {
_logger.Debug("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality); _logger.Debug("Quality {0} rejected by Artist's quality profile", subject.ParsedAlbumInfo.Quality);
return Decision.Reject("{0} is not wanted in profile", subject.ParsedEpisodeInfo.Quality.Quality); return Decision.Reject("{0} is not wanted in profile", subject.ParsedAlbumInfo.Quality.Quality);
} }
return Decision.Accept(); return Decision.Accept();

@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@ -23,32 +24,33 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
var queue = _queueService.GetQueue() var queue = _queueService.GetQueue()
.Select(q => q.RemoteEpisode).ToList(); .Select(q => q.RemoteAlbum).ToList();
var matchingSeries = queue.Where(q => q.Series.Id == subject.Series.Id); var matchingArtist = queue.Where(q => q.Artist.Id == subject.Artist.Id);
var matchingEpisode = matchingSeries.Where(q => q.Episodes.Select(e => e.Id).Intersect(subject.Episodes.Select(e => e.Id)).Any()); var matchingAlbum = matchingArtist.Where(q => q.Albums.Select(e => e.Id).Intersect(subject.Albums.Select(e => e.Id)).Any());
foreach (var remoteEpisode in matchingEpisode) foreach (var remoteAlbum in matchingAlbum)
{ {
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteEpisode.ParsedEpisodeInfo.Quality); _logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteAlbum.ParsedAlbumInfo.Quality);
if (!_qualityUpgradableSpecification.CutoffNotMet(subject.Series.Profile, remoteEpisode.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Quality)) if (!_qualityUpgradableSpecification.CutoffNotMet(subject.Artist.Profile, remoteAlbum.ParsedAlbumInfo.Quality, subject.ParsedAlbumInfo.Quality))
{ {
return Decision.Reject("Quality for release in queue already meets cutoff: {0}", remoteEpisode.ParsedEpisodeInfo.Quality); return Decision.Reject("Quality for release in queue already meets cutoff: {0}", remoteAlbum.ParsedAlbumInfo.Quality);
} }
_logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0}", remoteEpisode.ParsedEpisodeInfo.Quality); _logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0}", remoteAlbum.ParsedAlbumInfo.Quality);
if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.Profile, remoteEpisode.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Quality)) if (!_qualityUpgradableSpecification.IsUpgradable(subject.Artist.Profile, remoteAlbum.ParsedAlbumInfo.Quality, subject.ParsedAlbumInfo.Quality))
{ {
return Decision.Reject("Quality for release in queue is of equal or higher preference: {0}", remoteEpisode.ParsedEpisodeInfo.Quality); return Decision.Reject("Quality for release in queue is of equal or higher preference: {0}", remoteAlbum.ParsedAlbumInfo.Quality);
} }
} }
return Decision.Accept(); return Decision.Accept();
} }
} }
} }

@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@ -8,9 +8,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
public class RawDiskSpecification : IDecisionEngineSpecification public class RawDiskSpecification : IDecisionEngineSpecification
{ {
private static readonly string[] _dvdContainerTypes = new[] { "vob", "iso" }; private static readonly string[] _cdContainerTypes = new[] { "vob", "iso" };
private static readonly string[] _blurayContainerTypes = new[] { "m2ts" };
private readonly Logger _logger; private readonly Logger _logger;
@ -21,24 +19,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (subject.Release == null || subject.Release.Container.IsNullOrWhiteSpace()) if (subject.Release == null || subject.Release.Container.IsNullOrWhiteSpace())
{ {
return Decision.Accept(); return Decision.Accept();
} }
if (_dvdContainerTypes.Contains(subject.Release.Container.ToLower())) if (_cdContainerTypes.Contains(subject.Release.Container.ToLower()))
{ {
_logger.Debug("Release contains raw DVD, rejecting."); _logger.Debug("Release contains raw CD, rejecting.");
return Decision.Reject("Raw DVD release"); return Decision.Reject("Raw CD release");
} }
if (_blurayContainerTypes.Contains(subject.Release.Container.ToLower()))
{
_logger.Debug("Release contains raw Bluray, rejecting.");
return Decision.Reject("Raw Bluray release");
}
return Decision.Accept(); return Decision.Accept();
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
@ -22,19 +22,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
_logger.Debug("Checking if release meets restrictions: {0}", subject); _logger.Debug("Checking if release meets restrictions: {0}", subject);
var title = subject.Release.Title; var title = subject.Release.Title;
var restrictions = _restrictionService.AllForTags(subject.Series.Tags); var restrictions = _restrictionService.AllForTags(subject.Artist.Tags);
var required = restrictions.Where(r => r.Required.IsNotNullOrWhiteSpace()); var required = restrictions.Where(r => r.Required.IsNotNullOrWhiteSpace());
var ignored = restrictions.Where(r => r.Ignored.IsNotNullOrWhiteSpace()); var ignored = restrictions.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
foreach (var r in required) foreach (var r in required)
{ {
var requiredTerms = r.Required.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList(); var requiredTerms = r.Required.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
var foundTerms = ContainsAny(requiredTerms, title); var foundTerms = ContainsAny(requiredTerms, title);
if (foundTerms.Empty()) if (foundTerms.Empty())

@ -18,7 +18,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet) if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet)
{ {

@ -1,10 +1,11 @@
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
{ {
@ -13,22 +14,25 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
private readonly IPendingReleaseService _pendingReleaseService; private readonly IPendingReleaseService _pendingReleaseService;
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification; private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly IDelayProfileService _delayProfileService; private readonly IDelayProfileService _delayProfileService;
private readonly IMediaFileService _mediaFileService;
private readonly Logger _logger; private readonly Logger _logger;
public DelaySpecification(IPendingReleaseService pendingReleaseService, public DelaySpecification(IPendingReleaseService pendingReleaseService,
IQualityUpgradableSpecification qualityUpgradableSpecification, IQualityUpgradableSpecification qualityUpgradableSpecification,
IDelayProfileService delayProfileService, IDelayProfileService delayProfileService,
IMediaFileService mediaFileService,
Logger logger) Logger logger)
{ {
_pendingReleaseService = pendingReleaseService; _pendingReleaseService = pendingReleaseService;
_qualityUpgradableSpecification = qualityUpgradableSpecification; _qualityUpgradableSpecification = qualityUpgradableSpecification;
_delayProfileService = delayProfileService; _delayProfileService = delayProfileService;
_mediaFileService = mediaFileService;
_logger = logger; _logger = logger;
} }
public RejectionType Type => RejectionType.Temporary; public RejectionType Type => RejectionType.Temporary;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (searchCriteria != null && searchCriteria.UserInvokedSearch) if (searchCriteria != null && searchCriteria.UserInvokedSearch)
{ {
@ -36,8 +40,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
return Decision.Accept(); return Decision.Accept();
} }
var profile = subject.Series.Profile.Value; var profile = subject.Artist.Profile.Value;
var delayProfile = _delayProfileService.BestForTags(subject.Series.Tags); var delayProfile = _delayProfileService.BestForTags(subject.Artist.Tags);
var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol); var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol; var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;
@ -51,18 +55,24 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (isPreferredProtocol) if (isPreferredProtocol)
{ {
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value)) foreach (var album in subject.Albums)
{ {
var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile, file.Quality, subject.ParsedEpisodeInfo.Quality); var trackFiles = _mediaFileService.GetFilesByAlbum(album.ArtistId, album.Id);
if (upgradable) if (trackFiles.Any())
{ {
var revisionUpgrade = _qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedEpisodeInfo.Quality); var lowestQuality = trackFiles.Select(c => c.Quality).OrderBy(c => c.Quality.Id).First();
var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile, lowestQuality, subject.ParsedAlbumInfo.Quality);
if (revisionUpgrade) if (upgradable)
{ {
_logger.Debug("New quality is a better revision for existing quality, skipping delay"); var revisionUpgrade = _qualityUpgradableSpecification.IsRevisionUpgrade(lowestQuality, subject.ParsedAlbumInfo.Quality);
return Decision.Accept();
if (revisionUpgrade)
{
_logger.Debug("New quality is a better revision for existing quality, skipping delay");
return Decision.Accept();
}
} }
} }
} }
@ -70,7 +80,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
// If quality meets or exceeds the best allowed quality in the profile accept it immediately // If quality meets or exceeds the best allowed quality in the profile accept it immediately
var bestQualityInProfile = new QualityModel(profile.LastAllowedQuality()); var bestQualityInProfile = new QualityModel(profile.LastAllowedQuality());
var isBestInProfile = comparer.Compare(subject.ParsedEpisodeInfo.Quality, bestQualityInProfile) >= 0; var isBestInProfile = comparer.Compare(subject.ParsedAlbumInfo.Quality, bestQualityInProfile) >= 0;
if (isBestInProfile && isPreferredProtocol) if (isBestInProfile && isPreferredProtocol)
{ {
@ -78,9 +88,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
return Decision.Accept(); return Decision.Accept();
} }
var episodeIds = subject.Episodes.Select(e => e.Id); var albumIds = subject.Albums.Select(e => e.Id);
var oldest = _pendingReleaseService.OldestPendingRelease(subject.Series.Id, episodeIds); var oldest = _pendingReleaseService.OldestPendingRelease(subject.Artist.Id, albumIds);
if (oldest != null && oldest.Release.AgeMinutes > delay) if (oldest != null && oldest.Release.AgeMinutes > delay)
{ {

@ -1,4 +1,4 @@
using System; using System;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
@ -28,7 +28,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (searchCriteria != null) if (searchCriteria != null)
{ {
@ -39,16 +39,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var cdhEnabled = _configService.EnableCompletedDownloadHandling; var cdhEnabled = _configService.EnableCompletedDownloadHandling;
_logger.Debug("Performing history status check on report"); _logger.Debug("Performing history status check on report");
foreach (var episode in subject.Episodes) foreach (var album in subject.Albums)
{ {
_logger.Debug("Checking current status of episode [{0}] in history", episode.Id); _logger.Debug("Checking current status of album [{0}] in history", album.Id);
var mostRecent = _historyService.MostRecentForEpisode(episode.Id); var mostRecent = _historyService.MostRecentForAlbum(album.Id);
if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed) if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed)
{ {
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12)); var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
var cutoffUnmet = _qualityUpgradableSpecification.CutoffNotMet(subject.Series.Profile, mostRecent.Quality, subject.ParsedEpisodeInfo.Quality); var cutoffUnmet = _qualityUpgradableSpecification.CutoffNotMet(subject.Artist.Profile, mostRecent.Quality, subject.ParsedAlbumInfo.Quality);
var upgradeable = _qualityUpgradableSpecification.IsUpgradable(subject.Series.Profile, mostRecent.Quality, subject.ParsedEpisodeInfo.Quality); var upgradeable = _qualityUpgradableSpecification.IsUpgradable(subject.Artist.Profile, mostRecent.Quality, subject.ParsedAlbumInfo.Quality);
if (!recent && cdhEnabled) if (!recent && cdhEnabled)
{ {

@ -1,22 +1,22 @@
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
{ {
public class MonitoredEpisodeSpecification : IDecisionEngineSpecification public class MonitoredAlbumSpecification : IDecisionEngineSpecification
{ {
private readonly Logger _logger; private readonly Logger _logger;
public MonitoredEpisodeSpecification(Logger logger) public MonitoredAlbumSpecification(Logger logger)
{ {
_logger = logger; _logger = logger;
} }
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (searchCriteria != null) if (searchCriteria != null)
{ {
@ -27,20 +27,20 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
} }
} }
if (!subject.Series.Monitored) if (!subject.Artist.Monitored)
{ {
_logger.Debug("{0} is present in the DB but not tracked. skipping.", subject.Series); _logger.Debug("{0} is present in the DB but not tracked. skipping.", subject.Artist);
return Decision.Reject("Series is not monitored"); return Decision.Reject("Artist is not monitored");
} }
var monitoredCount = subject.Episodes.Count(episode => episode.Monitored); var monitoredCount = subject.Albums.Count(album => album.Monitored);
if (monitoredCount == subject.Episodes.Count) if (monitoredCount == subject.Albums.Count)
{ {
return Decision.Accept(); return Decision.Accept();
} }
_logger.Debug("Only {0}/{1} episodes are monitored. skipping.", monitoredCount, subject.Episodes.Count); _logger.Debug("Only {0}/{1} albums are monitored. skipping.", monitoredCount, subject.Albums.Count);
return Decision.Reject("Episode is not monitored"); return Decision.Reject("Album is not monitored");
} }
} }
} }

@ -1,9 +1,10 @@
using System; using System;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
{ {
@ -11,39 +12,52 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
{ {
private readonly QualityUpgradableSpecification _qualityUpgradableSpecification; private readonly QualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly IMediaFileService _mediaFileService;
private readonly Logger _logger; private readonly Logger _logger;
public ProperSpecification(QualityUpgradableSpecification qualityUpgradableSpecification, IConfigService configService, Logger logger) public ProperSpecification(QualityUpgradableSpecification qualityUpgradableSpecification, IConfigService configService, IMediaFileService mediaFileService, Logger logger)
{ {
_qualityUpgradableSpecification = qualityUpgradableSpecification; _qualityUpgradableSpecification = qualityUpgradableSpecification;
_configService = configService; _configService = configService;
_mediaFileService = mediaFileService;
_logger = logger; _logger = logger;
} }
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (searchCriteria != null) if (searchCriteria != null)
{ {
return Decision.Accept(); return Decision.Accept();
} }
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value)) foreach (var album in subject.Albums)
{ {
if (_qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedEpisodeInfo.Quality)) var trackFiles = _mediaFileService.GetFilesByAlbum(album.ArtistId, album.Id);
if (trackFiles.Any())
{ {
if (file.DateAdded < DateTime.Today.AddDays(-7)) var lowestQuality = trackFiles.Select(c => c.Quality).OrderBy(c => c.Quality.Id).First();
{ var dateAdded = trackFiles[0].DateAdded;
_logger.Debug("Proper for old file, rejecting: {0}", subject);
return Decision.Reject("Proper for old file");
}
if (!_configService.AutoDownloadPropers) _logger.Debug("Comparing file quality with report. Existing file is {0}", lowestQuality);
if (_qualityUpgradableSpecification.IsRevisionUpgrade(lowestQuality, subject.ParsedAlbumInfo.Quality))
{ {
_logger.Debug("Auto downloading of propers is disabled"); if (dateAdded < DateTime.Today.AddDays(-7))
return Decision.Reject("Proper downloading is disabled"); {
_logger.Debug("Proper for old file, rejecting: {0}", subject);
return Decision.Reject("Proper for old file");
}
if (!_configService.AutoDownloadPropers)
{
_logger.Debug("Auto downloading of propers is disabled");
return Decision.Reject("Proper downloading is disabled");
}
} }
} }
} }

@ -1,31 +0,0 @@
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class SameEpisodesGrabSpecification : IDecisionEngineSpecification
{
private readonly SameEpisodesSpecification _sameEpisodesSpecification;
private readonly Logger _logger;
public SameEpisodesGrabSpecification(SameEpisodesSpecification sameEpisodesSpecification, Logger logger)
{
_sameEpisodesSpecification = sameEpisodesSpecification;
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
if (_sameEpisodesSpecification.IsSatisfiedBy(subject.Episodes))
{
return Decision.Accept();
}
_logger.Debug("Episode file on disk contains more episodes than this release contains");
return Decision.Reject("Episode file on disk contains more episodes than this release contains");
}
}
}

@ -0,0 +1,28 @@
using System;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class SameTracksGrabSpecification : IDecisionEngineSpecification
{
private readonly SameTracksSpecification _sameTracksSpecification;
private readonly Logger _logger;
public SameTracksGrabSpecification(SameTracksSpecification sameTracksSpecification, Logger logger)
{
_sameTracksSpecification = sameTracksSpecification;
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{
throw new NotImplementedException();
// TODO: Rework for Tracks if we can parse from release details.
}
}
}

@ -0,0 +1,40 @@
using System.Linq;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Music;
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
{
public class AlbumRequestedSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public AlbumRequestedSpecification(Logger logger)
{
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteAlbum remoteAlbum, SearchCriteriaBase searchCriteria)
{
if (searchCriteria == null)
{
return Decision.Accept();
}
var criteriaAlbum = searchCriteria.Albums.Select(v => v.Id).ToList();
var remoteAlbums = remoteAlbum.Albums.Select(v => v.Id).ToList();
if (!criteriaAlbum.Intersect(remoteAlbums).Any())
{
_logger.Debug("Release rejected since the album wasn't requested: {0}", remoteAlbum.ParsedAlbumInfo);
return Decision.Reject("Album wasn't requested");
}
return Decision.Accept();
}
}
}

@ -0,0 +1,36 @@
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
{
public class ArtistSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public ArtistSpecification(Logger logger)
{
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteAlbum remoteAlbum, SearchCriteriaBase searchCriteria)
{
if (searchCriteria == null)
{
return Decision.Accept();
}
_logger.Debug("Checking if artist matches searched artist");
if (remoteAlbum.Artist.Id != searchCriteria.Artist.Id)
{
_logger.Debug("Artist {0} does not match {1}", remoteAlbum.Artist, searchCriteria.Artist);
return Decision.Reject("Wrong artist");
}
return Decision.Accept();
}
}
}

@ -0,0 +1,26 @@
using System;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
{
public class DailyAudioMatchSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public DailyAudioMatchSpecification(Logger logger)
{
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{
throw new NotImplementedException();
// TODO Rework for Daily Audio/Podcasts
}
}
}

@ -1,43 +0,0 @@
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
{
public class DailyEpisodeMatchSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
private readonly IEpisodeService _episodeService;
public DailyEpisodeMatchSpecification(Logger logger, IEpisodeService episodeService)
{
_logger = logger;
_episodeService = episodeService;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria)
{
if (searchCriteria == null)
{
return Decision.Accept();
}
var dailySearchSpec = searchCriteria as DailyEpisodeSearchCriteria;
if (dailySearchSpec == null) return Decision.Accept();
var episode = _episodeService.GetEpisode(dailySearchSpec.Series.Id, dailySearchSpec.AirDate.ToString(Episode.AIR_DATE_FORMAT));
if (!remoteEpisode.ParsedEpisodeInfo.IsDaily || remoteEpisode.ParsedEpisodeInfo.AirDate != episode.AirDate)
{
_logger.Debug("Episode AirDate does not match searched episode number, skipping.");
return Decision.Reject("Episode does not match");
}
return Decision.Accept();
}
}
}

@ -1,39 +0,0 @@
using System.Linq;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
{
public class EpisodeRequestedSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public EpisodeRequestedSpecification(Logger logger)
{
_logger = logger;
}
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria)
{
if (searchCriteria == null)
{
return Decision.Accept();
}
var criteriaEpisodes = searchCriteria.Episodes.Select(v => v.Id).ToList();
var remoteEpisodes = remoteEpisode.Episodes.Select(v => v.Id).ToList();
if (!criteriaEpisodes.Intersect(remoteEpisodes).Any())
{
_logger.Debug("Release rejected since the episode wasn't requested: {0}", remoteEpisode.ParsedEpisodeInfo);
return Decision.Reject("Episode wasn't requested");
}
return Decision.Accept();
}
}
}

@ -1,3 +1,4 @@
using System;
using NLog; using NLog;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -15,23 +16,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
public RejectionType Type => RejectionType.Permanent; public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
{ {
if (searchCriteria == null) throw new NotImplementedException();
{
return Decision.Accept();
}
var singleEpisodeSpec = searchCriteria as SeasonSearchCriteria;
if (singleEpisodeSpec == null) return Decision.Accept();
if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber)
{
_logger.Debug("Season number does not match searched season number, skipping.");
return Decision.Reject("Wrong season");
}
return Decision.Accept();
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save