Esempio n. 1
0
        public List <RenameEpisodeFilePreview> GetRenamePreviews(int seriesId, int seasonNumber)
        {
            var series   = _seriesService.GetSeries(seriesId);
            var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);
            var files    = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber);

            return(GetPreviews(series, episodes, files)
                   .OrderByDescending(e => e.EpisodeNumbers.First()).ToList());
        }
Esempio n. 2
0
        public List <DownloadDecision> SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool monitoredOnly, bool userInvokedSearch, bool interactiveSearch)
        {
            var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);

            if (missingOnly)
            {
                episodes = episodes.Where(e => !e.HasFile).ToList();
            }

            return(SeasonSearch(seriesId, seasonNumber, episodes, monitoredOnly, userInvokedSearch, interactiveSearch));
        }
Esempio n. 3
0
        public List <DownloadDecision> SeasonSearch(int seriesId, int seasonNumber)
        {
            var series   = _seriesService.GetSeries(seriesId);
            var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);

            var searchSpec = Get <SeasonSearchCriteria>(series, episodes);

            searchSpec.SeasonNumber = seasonNumber;

            return(Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec));
        }
        private List <Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, int mappedSeasonNumber, bool sceneSource, SearchCriteriaBase searchCriteria)
        {
            if (parsedEpisodeInfo.FullSeason)
            {
                if (series.UseSceneNumbering && sceneSource)
                {
                    var episodes = _episodeService.GetEpisodesBySceneSeason(series.Id, mappedSeasonNumber);

                    // If episodes were found by the scene season number return them, otherwise fallback to look-up by season number
                    if (episodes.Any())
                    {
                        return(episodes);
                    }
                }

                return(_episodeService.GetEpisodesBySeason(series.Id, mappedSeasonNumber));
            }

            if (parsedEpisodeInfo.IsDaily)
            {
                var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, parsedEpisodeInfo.DailyPart, searchCriteria);

                if (episodeInfo != null)
                {
                    return(new List <Episode> {
                        episodeInfo
                    });
                }

                return(new List <Episode>());
            }

            if (parsedEpisodeInfo.IsAbsoluteNumbering)
            {
                return(GetAnimeEpisodes(series, parsedEpisodeInfo, mappedSeasonNumber, sceneSource, searchCriteria));
            }

            if (parsedEpisodeInfo.IsPossibleSceneSeasonSpecial)
            {
                var parsedSpecialEpisodeInfo = ParseSpecialEpisodeTitle(parsedEpisodeInfo, parsedEpisodeInfo.ReleaseTitle, series);

                if (parsedSpecialEpisodeInfo != null)
                {
                    // Use the season number and disable scene source since the season/episode numbers that were returned are not scene numbers
                    return(GetStandardEpisodes(series, parsedSpecialEpisodeInfo, parsedSpecialEpisodeInfo.SeasonNumber, false, searchCriteria));
                }
            }

            return(GetStandardEpisodes(series, parsedEpisodeInfo, mappedSeasonNumber, sceneSource, searchCriteria));
        }
Esempio n. 5
0
        private List <Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, int mappedSeasonNumber, bool sceneSource, SearchCriteriaBase searchCriteria)
        {
            if (parsedEpisodeInfo.FullSeason)
            {
                if (series.UseSceneNumbering && sceneSource)
                {
                    return(_episodeService.GetEpisodesBySceneSeason(series.Id, mappedSeasonNumber));
                }
                else
                {
                    return(_episodeService.GetEpisodesBySeason(series.Id, mappedSeasonNumber));
                }
            }

            if (parsedEpisodeInfo.IsDaily)
            {
                var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, parsedEpisodeInfo.DailyPart, searchCriteria);

                if (episodeInfo != null)
                {
                    return(new List <Episode> {
                        episodeInfo
                    });
                }

                return(new List <Episode>());
            }

            if (parsedEpisodeInfo.IsAbsoluteNumbering)
            {
                return(GetAnimeEpisodes(series, parsedEpisodeInfo, mappedSeasonNumber, sceneSource, searchCriteria));
            }

            if (parsedEpisodeInfo.IsPossibleSceneSeasonSpecial)
            {
                parsedEpisodeInfo = ParseSpecialEpisodeTitle(parsedEpisodeInfo, parsedEpisodeInfo.ReleaseTitle, series) ?? parsedEpisodeInfo;
            }

            return(GetStandardEpisodes(series, parsedEpisodeInfo, mappedSeasonNumber, sceneSource, searchCriteria));
        }
Esempio n. 6
0
        public void HandleAsync(DownloadFailedEvent message)
        {
            if (!_configService.AutoRedownloadFailed)
            {
                _logger.Debug("Auto redownloading failed episodes is disabled");
                return;
            }

            if (message.EpisodeIds.Count == 1)
            {
                _logger.Debug("Failed download only contains one episode, searching again");

                _commandExecutor.PublishCommandAsync(new EpisodeSearchCommand(message.EpisodeIds));

                return;
            }

            var seasonNumber     = _episodeService.GetEpisode(message.EpisodeIds.First()).SeasonNumber;
            var episodesInSeason = _episodeService.GetEpisodesBySeason(message.SeriesId, seasonNumber);

            if (message.EpisodeIds.Count == episodesInSeason.Count)
            {
                _logger.Debug("Failed download was entire season, searching again");

                _commandExecutor.PublishCommandAsync(new SeasonSearchCommand
                {
                    SeriesId     = message.SeriesId,
                    SeasonNumber = seasonNumber
                });

                return;
            }

            _logger.Debug("Failed download contains multiple episodes, probably a double episode, searching again");

            _commandExecutor.PublishCommandAsync(new EpisodeSearchCommand(message.EpisodeIds));
        }
Esempio n. 7
0
        public List <Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null)
        {
            var result = new List <Episode>();

            if (parsedEpisodeInfo.FullSeason)
            {
                return(_episodeService.GetEpisodesBySeason(series.Id, parsedEpisodeInfo.SeasonNumber));
            }

            if (parsedEpisodeInfo.IsDaily)
            {
                if (series.SeriesType == SeriesTypes.Standard)
                {
                    _logger.Warn("Found daily-style episode for non-daily series: {0}.", series);
                    return(result);
                }

                var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, searchCriteria);

                if (episodeInfo != null)
                {
                    result.Add(episodeInfo);
                }

                return(result);
            }

            if (parsedEpisodeInfo.IsAbsoluteNumbering)
            {
                var sceneSeasonNumber = _sceneMappingService.GetSeasonNumber(parsedEpisodeInfo.SeriesTitle);

                foreach (var absoluteEpisodeNumber in parsedEpisodeInfo.AbsoluteEpisodeNumbers)
                {
                    Episode episode = null;

                    if (parsedEpisodeInfo.Special)
                    {
                        episode = _episodeService.FindEpisode(series.Id, 0, absoluteEpisodeNumber);
                    }

                    else if (sceneSource)
                    {
                        if (sceneSeasonNumber.HasValue && (sceneSeasonNumber == 0 || sceneSeasonNumber > 1))
                        {
                            var episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, sceneSeasonNumber.Value, absoluteEpisodeNumber);

                            if (episodes.Count == 1)
                            {
                                episode = episodes.First();
                            }

                            if (episode == null)
                            {
                                episode = _episodeService.FindEpisode(series.Id, sceneSeasonNumber.Value,
                                                                      absoluteEpisodeNumber);
                            }
                        }

                        else
                        {
                            episode = _episodeService.FindEpisodeBySceneNumbering(series.Id, absoluteEpisodeNumber);
                        }
                    }

                    if (episode == null)
                    {
                        episode = _episodeService.FindEpisode(series.Id, absoluteEpisodeNumber);
                    }

                    if (episode != null)
                    {
                        _logger.Debug("Using absolute episode number {0} for: {1} - TVDB: {2}x{3:00}",
                                      absoluteEpisodeNumber,
                                      series.Title,
                                      episode.SeasonNumber,
                                      episode.EpisodeNumber);

                        result.Add(episode);
                    }
                }

                return(result);
            }

            if (parsedEpisodeInfo.EpisodeNumbers == null)
            {
                return(result);
            }

            foreach (var episodeNumber in parsedEpisodeInfo.EpisodeNumbers)
            {
                if (series.UseSceneNumbering && sceneSource)
                {
                    List <Episode> episodes = new List <Episode>();

                    if (searchCriteria != null)
                    {
                        episodes = searchCriteria.Episodes.Where(e => e.SceneSeasonNumber == parsedEpisodeInfo.SeasonNumber &&
                                                                 e.SceneEpisodeNumber == episodeNumber).ToList();
                    }

                    if (!episodes.Any())
                    {
                        episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, parsedEpisodeInfo.SeasonNumber, episodeNumber);
                    }

                    if (episodes != null && episodes.Any())
                    {
                        _logger.Debug("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}",
                                      series.Title,
                                      episodes.First().SceneSeasonNumber,
                                      episodes.First().SceneEpisodeNumber,
                                      String.Join(", ", episodes.Select(e => String.Format("{0}x{1:00}", e.SeasonNumber, e.EpisodeNumber))));

                        result.AddRange(episodes);
                        continue;
                    }
                }

                Episode episodeInfo = null;

                if (searchCriteria != null)
                {
                    episodeInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SeasonNumber == parsedEpisodeInfo.SeasonNumber &&
                                                                          e.EpisodeNumber == episodeNumber);
                }

                if (episodeInfo == null)
                {
                    episodeInfo = _episodeService.FindEpisode(series.Id, parsedEpisodeInfo.SeasonNumber, episodeNumber);
                }

                if (episodeInfo != null)
                {
                    result.Add(episodeInfo);
                }

                else
                {
                    _logger.Debug("Unable to find {0}", parsedEpisodeInfo);
                }
            }

            return(result);
        }
        public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
        {
            _logger.Debug("Beginning size check for: {0}", subject);

            var quality = subject.ParsedEpisodeInfo.Quality.Quality;

            if (quality == Quality.RAWHD)
            {
                _logger.Debug("Raw-HD release found, skipping size check.");
                return(Decision.Accept());
            }

            if (subject.ParsedEpisodeInfo.Special)
            {
                _logger.Debug("Special release found, skipping size check.");
                return(Decision.Accept());
            }

            var qualityDefinition = _qualityDefinitionService.Get(quality);
            var minSize           = qualityDefinition.MinSize.Megabytes();

            //Multiply maxSize by Series.Runtime
            minSize = minSize * subject.Series.Runtime * subject.Episodes.Count;

            //If the parsed size is smaller than minSize we don't want it
            if (subject.Release.Size < minSize)
            {
                _logger.Debug("Item: {0}, Size: {1:0n} is smaller than minimum allowed size ({2:0}), rejecting.", subject, subject.Release.Size, minSize);
                return(Decision.Reject("{0} is smaller than minimum allowed: {1}", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix()));
            }
            if (qualityDefinition.MaxSize == 0)
            {
                _logger.Debug("Max size is 0 (unlimited) - skipping check.");
            }
            else
            {
                var maxSize = qualityDefinition.MaxSize.Megabytes();

                //Multiply maxSize by Series.Runtime
                maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;

                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 (subject.Release.Size > maxSize)
                {
                    _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}", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix()));
                }
            }

            _logger.Debug("Item: {0}, meets size constraints.", subject);
            return(Decision.Accept());
        }
Esempio n. 9
0
        public List <DownloadDecision> SeasonSearch(int seriesId, int seasonNumber)
        {
            var series   = _seriesService.GetSeries(seriesId);
            var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);

            if (series.SeriesType == SeriesTypes.Anime)
            {
                return(SearchAnimeSeason(series, episodes));
            }

            if (seasonNumber == 0)
            {
                // search for special episodes in season 0
                return(SearchSpecial(series, episodes));
            }

            var downloadDecisions = new List <DownloadDecision>();

            if (series.UseSceneNumbering)
            {
                var sceneSeasonGroups = episodes.GroupBy(v =>
                {
                    if (v.SceneSeasonNumber == 0 && v.SceneEpisodeNumber == 0)
                    {
                        return(v.SeasonNumber);
                    }

                    return(v.SceneSeasonNumber);
                }).Distinct();

                foreach (var sceneSeasonEpisodes in sceneSeasonGroups)
                {
                    if (sceneSeasonEpisodes.Count() == 1)
                    {
                        var episode    = sceneSeasonEpisodes.First();
                        var searchSpec = Get <SingleEpisodeSearchCriteria>(series, sceneSeasonEpisodes.ToList());
                        searchSpec.SeasonNumber = sceneSeasonEpisodes.Key;
                        if (episode.SceneSeasonNumber == 0 && episode.SceneEpisodeNumber == 0)
                        {
                            searchSpec.EpisodeNumber = episode.EpisodeNumber;
                        }
                        else
                        {
                            searchSpec.EpisodeNumber = episode.SceneEpisodeNumber;
                        }

                        var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
                        downloadDecisions.AddRange(decisions);
                    }
                    else
                    {
                        var searchSpec = Get <SeasonSearchCriteria>(series, sceneSeasonEpisodes.ToList());
                        searchSpec.SeasonNumber = sceneSeasonEpisodes.Key;

                        var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
                        downloadDecisions.AddRange(decisions);
                    }
                }
            }
            else
            {
                var searchSpec = Get <SeasonSearchCriteria>(series, episodes);
                searchSpec.SeasonNumber = seasonNumber;

                var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
                downloadDecisions.AddRange(decisions);
            }

            return(downloadDecisions);
        }
Esempio n. 10
0
        public List <DownloadDecision> SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool userInvokedSearch, bool interactiveSearch)
        {
            var series   = _seriesService.GetSeries(seriesId);
            var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);

            if (missingOnly)
            {
                episodes = episodes.Where(e => e.Monitored && !e.HasFile).ToList();
            }

            if (series.SeriesType == SeriesTypes.Anime)
            {
                return(SearchAnimeSeason(series, episodes, userInvokedSearch, interactiveSearch));
            }

            if (series.SeriesType == SeriesTypes.Daily)
            {
                return(SearchDailySeason(series, episodes, userInvokedSearch, interactiveSearch));
            }

            if (seasonNumber == 0)
            {
                // search for special episodes in season 0
                return(SearchSpecial(series, episodes, userInvokedSearch, interactiveSearch));
            }

            var downloadDecisions = new List <DownloadDecision>();

            if (series.UseSceneNumbering)
            {
                var sceneSeasonGroups = episodes.GroupBy(v =>
                {
                    if (v.SceneSeasonNumber.HasValue && v.SceneEpisodeNumber.HasValue)
                    {
                        return(v.SceneSeasonNumber.Value);
                    }
                    return(v.SeasonNumber);
                }).Distinct();

                foreach (var sceneSeasonEpisodes in sceneSeasonGroups)
                {
                    if (sceneSeasonEpisodes.Count() == 1)
                    {
                        var episode    = sceneSeasonEpisodes.First();
                        var searchSpec = Get <SingleEpisodeSearchCriteria>(series, sceneSeasonEpisodes.ToList(), userInvokedSearch, interactiveSearch);

                        searchSpec.SeasonNumber          = sceneSeasonEpisodes.Key;
                        searchSpec.MonitoredEpisodesOnly = true;

                        if (episode.SceneSeasonNumber.HasValue && episode.SceneEpisodeNumber.HasValue)
                        {
                            searchSpec.EpisodeNumber = episode.SceneEpisodeNumber.Value;
                        }
                        else
                        {
                            searchSpec.EpisodeNumber = episode.EpisodeNumber;
                        }

                        var decisions = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
                        downloadDecisions.AddRange(decisions);
                    }
                    else
                    {
                        var searchSpec = Get <SeasonSearchCriteria>(series, sceneSeasonEpisodes.ToList(), userInvokedSearch, interactiveSearch);
                        searchSpec.SeasonNumber = sceneSeasonEpisodes.Key;

                        var decisions = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
                        downloadDecisions.AddRange(decisions);
                    }
                }
            }
            else
            {
                var searchSpec = Get <SeasonSearchCriteria>(series, episodes, userInvokedSearch, interactiveSearch);
                searchSpec.SeasonNumber = seasonNumber;

                var decisions = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
                downloadDecisions.AddRange(decisions);
            }

            return(downloadDecisions);
        }
Esempio n. 11
0
        public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
        {
            _logger.Debug("Beginning size check for: {0}", subject);

            var quality = subject.ParsedEpisodeInfo.Quality.Quality;

            if (subject.ParsedEpisodeInfo.Special)
            {
                _logger.Debug("Special release found, skipping size check.");
                return(Decision.Accept());
            }

            if (subject.Release.Size == 0)
            {
                _logger.Debug("Release has unknown size, skipping size check");
                return(Decision.Accept());
            }

            var qualityDefinition = _qualityDefinitionService.Get(quality);

            if (qualityDefinition.MinSize.HasValue)
            {
                var minSize = qualityDefinition.MinSize.Value.Megabytes();

                //Multiply maxSize by Series.Runtime
                minSize = minSize * subject.Series.Runtime * subject.Episodes.Count;

                //If the parsed size is smaller than minSize we don't want it
                if (subject.Release.Size < minSize)
                {
                    var runtimeMessage = subject.Episodes.Count == 1 ? $"{subject.Series.Runtime}min" : $"{subject.Episodes.Count}x {subject.Series.Runtime}min";

                    _logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes for {3}), rejecting.", subject, subject.Release.Size, minSize, runtimeMessage);
                    return(Decision.Reject("{0} is smaller than minimum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix(), runtimeMessage));
                }
            }
            if (!qualityDefinition.MaxSize.HasValue || qualityDefinition.MaxSize.Value == 0)
            {
                _logger.Debug("Max size is unlimited, skipping size check");
            }
            else if (subject.Series.Runtime == 0)
            {
                _logger.Debug("Series runtime is 0, unable to validate size until it is available, rejecting");
                return(Decision.Reject("Series runtime is 0, unable to validate size until it is available"));
            }
            else
            {
                var maxSize = qualityDefinition.MaxSize.Value.Megabytes();

                //Multiply maxSize by Series.Runtime
                maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;

                if (subject.Episodes.Count == 1 && subject.Series.SeriesType == SeriesTypes.Standard)
                {
                    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 = 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 (subject.Release.Size > maxSize)
                {
                    var runtimeMessage = subject.Episodes.Count == 1 ? $"{subject.Series.Runtime}min" : $"{subject.Episodes.Count}x {subject.Series.Runtime}min";

                    _logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2} for {3}), rejecting", subject, subject.Release.Size, maxSize, runtimeMessage);
                    return(Decision.Reject("{0} is larger than maximum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix(), runtimeMessage));
                }
            }

            _logger.Debug("Item: {0}, meets size constraints", subject);
            return(Decision.Accept());
        }
        public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
        {
            if (localEpisode.ExistingFile)
            {
                _logger.Debug("{0} is in series folder, skipping check", localEpisode.Path);
                return(Decision.Accept());
            }

            var episodeTitleRequired = _configService.EpisodeTitleRequired;

            if (episodeTitleRequired == EpisodeTitleRequiredType.Never)
            {
                _logger.Debug("Episode titles are never required, skipping check");
                return(Decision.Accept());
            }

            if (!_buildFileNames.RequiresEpisodeTitle(localEpisode.Series, localEpisode.Episodes))
            {
                _logger.Debug("File name format does not require episode title, skipping check");
                return(Decision.Accept());
            }

            var episodes                = localEpisode.Episodes;
            var firstEpisode            = episodes.First();
            var episodesInSeason        = _episodeService.GetEpisodesBySeason(firstEpisode.SeriesId, firstEpisode.EpisodeNumber);
            var allEpisodesOnTheSameDay = firstEpisode.AirDateUtc.HasValue && episodes.All(e =>
                                                                                           !e.AirDateUtc.HasValue ||
                                                                                           e.AirDateUtc.Value == firstEpisode.AirDateUtc.Value);

            if (episodeTitleRequired == EpisodeTitleRequiredType.BulkSeasonReleases &&
                allEpisodesOnTheSameDay &&
                episodesInSeason.Count(e => !e.AirDateUtc.HasValue ||
                                       e.AirDateUtc.Value == firstEpisode.AirDateUtc.Value
                                       ) < 4
                )
            {
                _logger.Debug("Episode title only required for bulk season releases");
                return(Decision.Accept());
            }

            foreach (var episode in episodes)
            {
                var airDateUtc = episode.AirDateUtc;
                var title      = episode.Title;

                if (airDateUtc.HasValue && airDateUtc.Value.Before(DateTime.UtcNow.AddHours(-48)))
                {
                    _logger.Debug("Episode aired more than 48 hours ago");
                    continue;
                }

                if (title.IsNullOrWhiteSpace())
                {
                    _logger.Debug("Episode does not have a title and recently aired");

                    return(Decision.Reject("Episode does not have a title and recently aired"));
                }

                if (title.Equals("TBA"))
                {
                    _logger.Debug("Episode has a TBA title and recently aired");

                    return(Decision.Reject("Episode has a TBA title and recently aired"));
                }
            }

            return(Decision.Accept());
        }
Esempio n. 13
0
        public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
        {
            _logger.Debug("Beginning size check for: {0}", subject);

            var quality = subject.ParsedEpisodeInfo.Quality.Quality;

            if (subject.ParsedEpisodeInfo.Special)
            {
                _logger.Debug("Special release found, skipping size check.");
                return(Decision.Accept());
            }

            if (subject.Release.Size == 0)
            {
                _logger.Debug("Release has unknown size, skipping size check");
                return(Decision.Accept());
            }

            var runtime = subject.Series.Runtime;

            if (runtime == 0)
            {
                var firstSeasonNumber = subject.Series.Seasons.Where(s => s.SeasonNumber > 0).Min(s => s.SeasonNumber);
                var pilotEpisode      = _episodeService.GetEpisodesBySeason(subject.Series.Id, firstSeasonNumber).First();

                if (subject.Episodes.First().SeasonNumber == pilotEpisode.SeasonNumber)
                {
                    // If the first episode has an air date use it, otherwise use the release's publish date because like runtime it may not have updated yet.
                    var gracePeriodEnd = (pilotEpisode.AirDateUtc ?? subject.Release.PublishDate).AddHours(24);

                    // If episodes don't have an air date that is okay, otherwise make sure it's within 24 hours of the first episode airing.
                    if (subject.Episodes.All(e => !e.AirDateUtc.HasValue || e.AirDateUtc.Value.Before(gracePeriodEnd)))
                    {
                        _logger.Debug("Series runtime is 0, but all episodes in release aired within 24 hours of first episode in season, defaulting runtime to 45 minutes");
                        runtime = 45;
                    }
                }

                // Reject if the run time is still 0
                if (runtime == 0)
                {
                    _logger.Debug("Series runtime is 0, unable to validate size until it is available, rejecting");
                    return(Decision.Reject("Series runtime is 0, unable to validate size until it is available"));
                }
            }

            var qualityDefinition = _qualityDefinitionService.Get(quality);

            if (qualityDefinition.MinSize.HasValue)
            {
                var minSize = qualityDefinition.MinSize.Value.Megabytes();

                // Multiply maxSize by Series.Runtime
                minSize = minSize * runtime * subject.Episodes.Count;

                // If the parsed size is smaller than minSize we don't want it
                if (subject.Release.Size < minSize)
                {
                    var runtimeMessage = subject.Episodes.Count == 1 ? $"{runtime}min" : $"{subject.Episodes.Count}x {runtime}min";

                    _logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes for {3}), rejecting.", subject, subject.Release.Size, minSize, runtimeMessage);
                    return(Decision.Reject("{0} is smaller than minimum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix(), runtimeMessage));
                }
            }
            if (!qualityDefinition.MaxSize.HasValue || qualityDefinition.MaxSize.Value == 0)
            {
                _logger.Debug("Max size is unlimited, skipping size check");
            }
            else
            {
                var maxSize = qualityDefinition.MaxSize.Value.Megabytes();

                // Multiply maxSize by Series.Runtime
                maxSize = maxSize * runtime * subject.Episodes.Count;

                if (subject.Episodes.Count == 1 && subject.Series.SeriesType == SeriesTypes.Standard)
                {
                    var firstEpisode   = subject.Episodes.First();
                    var seasonEpisodes = GetSeasonEpisodes(subject, searchCriteria);

                    // 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 == firstEpisode.Id || (seasonEpisodes.Count() >= 10 && seasonEpisodes.Last().Id == firstEpisode.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 (subject.Release.Size > maxSize)
                {
                    var runtimeMessage = subject.Episodes.Count == 1 ? $"{runtime}min" : $"{subject.Episodes.Count}x {runtime}min";

                    _logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2} for {3}), rejecting", subject, subject.Release.Size, maxSize, runtimeMessage);
                    return(Decision.Reject("{0} is larger than maximum allowed {1} (for {2})", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix(), runtimeMessage));
                }
            }

            _logger.Debug("Item: {0}, meets size constraints", subject);
            return(Decision.Accept());
        }