Пример #1
0
        private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria)
        {
            Series series = null;

            var sceneMappingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle);

            if (sceneMappingTvdbId.HasValue)
            {
                if (searchCriteria != null && searchCriteria.Series.TvdbId == sceneMappingTvdbId.Value)
                {
                    return(searchCriteria.Series);
                }

                series = _seriesService.FindByTvdbId(sceneMappingTvdbId.Value);

                if (series == null)
                {
                    _logger.Debug("No matching series {0}", parsedEpisodeInfo.SeriesTitle);
                    return(null);
                }

                return(series);
            }

            if (searchCriteria != null)
            {
                if (searchCriteria.Series.CleanTitle == parsedEpisodeInfo.SeriesTitle.CleanSeriesTitle())
                {
                    return(searchCriteria.Series);
                }

                if (tvdbId > 0 && tvdbId == searchCriteria.Series.TvdbId)
                {
                    //TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
                    return(searchCriteria.Series);
                }

                if (tvRageId > 0 && tvRageId == searchCriteria.Series.TvRageId)
                {
                    //TODO: If series is found by TvRageId, we should report it as a scene naming exception, since it will fail to import
                    return(searchCriteria.Series);
                }
            }

            series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);

            if (series == null && parsedEpisodeInfo.SeriesTitleInfo.Year > 0)
            {
                series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, parsedEpisodeInfo.SeriesTitleInfo.Year);
            }

            if (series == null && tvdbId > 0)
            {
                //TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
                series = _seriesService.FindByTvdbId(tvdbId);
            }

            if (series == null && tvRageId > 0)
            {
                //TODO: If series is found by TvRageId, we should report it as a scene naming exception, since it will fail to import
                series = _seriesService.FindByTvRageId(tvRageId);
            }

            if (series == null)
            {
                _logger.Debug("No matching series {0}", parsedEpisodeInfo.SeriesTitle);
                return(null);
            }

            return(series);
        }
Пример #2
0
        private bool TryGetMovieBySearchCriteria(ParsedMovieInfo parsedMovieInfo, SearchCriteriaBase searchCriteria, out MappingResult result)
        {
            Movie possibleMovie = null;

            List <string> possibleTitles = new List <string>();

            possibleTitles.Add(searchCriteria.Movie.CleanTitle);

            foreach (AlternativeTitle altTitle in searchCriteria.Movie.AlternativeTitles)
            {
                possibleTitles.Add(altTitle.CleanTitle);
            }

            string cleanTitle = parsedMovieInfo.MovieTitle.CleanSeriesTitle();

            foreach (string title in possibleTitles)
            {
                if (title == parsedMovieInfo.MovieTitle.CleanSeriesTitle())
                {
                    possibleMovie = searchCriteria.Movie;
                }

                foreach (ArabicRomanNumeral numeralMapping in _arabicRomanNumeralMappings)
                {
                    string arabicNumeral = numeralMapping.ArabicNumeralAsString;
                    string romanNumeral  = numeralMapping.RomanNumeralLowerCase;

                    //_logger.Debug(cleanTitle);

                    if (title.Replace(arabicNumeral, romanNumeral) == parsedMovieInfo.MovieTitle.CleanSeriesTitle())
                    {
                        possibleMovie = searchCriteria.Movie;
                    }

                    if (title == parsedMovieInfo.MovieTitle.CleanSeriesTitle().Replace(arabicNumeral, romanNumeral))
                    {
                        possibleMovie = searchCriteria.Movie;
                    }
                }
            }

            if (possibleMovie != null)
            {
                if (parsedMovieInfo.Year < 1800 || possibleMovie.Year == parsedMovieInfo.Year || possibleMovie.SecondaryYear == parsedMovieInfo.Year)
                {
                    result = new MappingResult {
                        Movie = possibleMovie, MappingResultType = MappingResultType.Success
                    };
                    return(true);
                }
                result = new MappingResult {
                    Movie = possibleMovie, MappingResultType = MappingResultType.WrongYear
                };
                return(false);
            }

            if (_config.ParsingLeniency == ParsingLeniencyType.MappingLenient)
            {
                if (searchCriteria.Movie.CleanTitle.Contains(cleanTitle) ||
                    cleanTitle.Contains(searchCriteria.Movie.CleanTitle))
                {
                    possibleMovie = searchCriteria.Movie;
                    if (parsedMovieInfo.Year > 1800 && parsedMovieInfo.Year == possibleMovie.Year || possibleMovie.SecondaryYear == parsedMovieInfo.Year)
                    {
                        result = new MappingResult {
                            Movie = possibleMovie, MappingResultType = MappingResultType.SuccessLenientMapping
                        };
                        return(true);
                    }

                    if (parsedMovieInfo.Year < 1800)
                    {
                        result = new MappingResult {
                            Movie = possibleMovie, MappingResultType = MappingResultType.SuccessLenientMapping
                        };
                        return(true);
                    }

                    result = new MappingResult {
                        Movie = possibleMovie, MappingResultType = MappingResultType.WrongYear
                    };
                    return(false);
                }
            }

            result = new MappingResult {
                Movie = searchCriteria.Movie, MappingResultType = MappingResultType.WrongTitle
            };

            return(false);
        }
Пример #3
0
        private List <Episode> GetStandardEpisodes(Series series, ParsedEpisodeInfo parsedEpisodeInfo, bool sceneSource, SearchCriteriaBase searchCriteria)
        {
            var result       = new List <Episode>();
            var seasonNumber = parsedEpisodeInfo.SeasonNumber;

            if (sceneSource)
            {
                var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle);

                if (sceneMapping != null && sceneMapping.SeasonNumber.HasValue && sceneMapping.SeasonNumber.Value >= 0 &&
                    sceneMapping.SceneSeasonNumber == seasonNumber)
                {
                    seasonNumber = sceneMapping.SeasonNumber.Value;
                }
            }

            if (parsedEpisodeInfo.EpisodeNumbers == null)
            {
                return(new List <Episode>());
            }

            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, 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 == seasonNumber && e.EpisodeNumber == episodeNumber);
                }

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

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

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

            return(result);
        }
Пример #4
0
        public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
        {
            var remoteEpisode = new RemoteEpisode
            {
                ParsedEpisodeInfo = parsedEpisodeInfo,
            };

            var series = GetSeries(parsedEpisodeInfo, tvdbId, tvRageId, searchCriteria);

            if (series == null)
            {
                return(remoteEpisode);
            }

            remoteEpisode.Series   = series;
            remoteEpisode.Episodes = GetEpisodes(parsedEpisodeInfo, series, true, searchCriteria);

            return(remoteEpisode);
        }
Пример #5
0
        public ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
        {
            if (searchCriteria != null)
            {
                if (tvdbId == 0)
                {
                    tvdbId = _sceneMappingService.FindTvdbId(title) ?? 0;
                }

                if (tvdbId != 0 && tvdbId == searchCriteria.Series.TvdbId)
                {
                    return(ParseSpecialEpisodeTitle(title, searchCriteria.Series));
                }

                if (tvRageId != 0 && tvRageId == searchCriteria.Series.TvRageId)
                {
                    return(ParseSpecialEpisodeTitle(title, searchCriteria.Series));
                }
            }

            var series = GetSeries(title);

            if (series == null)
            {
                series = _seriesService.FindByTitleInexact(title);
            }

            if (series == null && tvdbId > 0)
            {
                series = _seriesService.FindByTvdbId(tvdbId);
            }

            if (series == null && tvRageId > 0)
            {
                series = _seriesService.FindByTvRageId(tvRageId);
            }

            if (series == null)
            {
                _logger.Debug("No matching series {0}", title);
                return(null);
            }

            return(ParseSpecialEpisodeTitle(title, series));
        }
Пример #6
0
        public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
        {
            throw new NotImplementedException();

            // TODO: Rework for Tracks if we can parse from release details.
        }
Пример #7
0
        private void AddTvIdPageableRequests(IndexerPageableRequestChain chain, IEnumerable <int> categories, SearchCriteriaBase searchCriteria, string parameters)
        {
            var includeTvdbSearch   = SupportsTvdbSearch && searchCriteria.Series.TvdbId > 0;
            var includeImdbSearch   = SupportsImdbSearch && searchCriteria.Series.ImdbId.IsNotNullOrWhiteSpace();
            var includeTvRageSearch = SupportsTvRageSearch && searchCriteria.Series.TvRageId > 0;
            var includeTvMazeSearch = SupportsTvMazeSearch && searchCriteria.Series.TvMazeId > 0;

            if (SupportsAggregatedIdSearch && (includeTvdbSearch || includeTvRageSearch || includeTvMazeSearch))
            {
                var ids = "";

                if (includeTvdbSearch)
                {
                    ids += "&tvdbid=" + searchCriteria.Series.TvdbId;
                }
                if (includeImdbSearch)
                {
                    ids += "&imdbid=" + searchCriteria.Series.ImdbId;
                }

                if (includeTvRageSearch)
                {
                    ids += "&rid=" + searchCriteria.Series.TvRageId;
                }

                if (includeTvMazeSearch)
                {
                    ids += "&tvmazeid=" + searchCriteria.Series.TvMazeId;
                }

                chain.Add(GetPagedRequests(MaxPages, categories, "tvsearch", ids + parameters));
            }
            else
            {
                if (includeTvdbSearch)
                {
                    chain.Add(GetPagedRequests(MaxPages, categories, "tvsearch",
                                               string.Format("&tvdbid={0}{1}", searchCriteria.Series.TvdbId, parameters)));
                }
                else if (includeImdbSearch)
                {
                    chain.Add(GetPagedRequests(MaxPages, categories, "tvsearch",
                                               string.Format("&imdbid={0}{1}", searchCriteria.Series.ImdbId, parameters)));
                }
                else if (includeTvRageSearch)
                {
                    chain.Add(GetPagedRequests(MaxPages, categories, "tvsearch",
                                               string.Format("&rid={0}{1}", searchCriteria.Series.TvRageId, parameters)));
                }

                else if (includeTvMazeSearch)
                {
                    chain.Add(GetPagedRequests(MaxPages, categories, "tvsearch",
                                               string.Format("&tvmazeid={0}{1}", searchCriteria.Series.TvMazeId, parameters)));
                }
            }
        }
Пример #8
0
        public List <Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null)
        {
            var result = new List <Episode>();

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

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

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

                return(result);
            }

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

            foreach (var episodeNumber in parsedEpisodeInfo.EpisodeNumbers)
            {
                Episode episodeInfo = null;

                if (series.UseSceneNumbering && sceneSource)
                {
                    if (searchCriteria != null)
                    {
                        episodeInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SceneSeasonNumber == parsedEpisodeInfo.SeasonNumber &&
                                                                              e.SceneEpisodeNumber == episodeNumber);
                    }

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

                    if (episodeInfo != null)
                    {
                        _logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}",
                                     series.Title,
                                     episodeInfo.SceneSeasonNumber,
                                     episodeInfo.SceneEpisodeNumber,
                                     episodeInfo.SeasonNumber,
                                     episodeInfo.EpisodeNumber);
                    }
                }

                if (episodeInfo == null && 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);
        }
Пример #9
0
        public List <Book> GetBooks(ParsedBookInfo parsedBookInfo, Author author, SearchCriteriaBase searchCriteria = null)
        {
            var bookTitle = parsedBookInfo.BookTitle;
            var result    = new List <Book>();

            if (parsedBookInfo.BookTitle == null)
            {
                return(new List <Book>());
            }

            Book bookInfo = null;

            if (parsedBookInfo.Discography)
            {
                if (parsedBookInfo.DiscographyStart > 0)
                {
                    return(_bookService.AuthorBooksBetweenDates(author,
                                                                new DateTime(parsedBookInfo.DiscographyStart, 1, 1),
                                                                new DateTime(parsedBookInfo.DiscographyEnd, 12, 31),
                                                                false));
                }

                if (parsedBookInfo.DiscographyEnd > 0)
                {
                    return(_bookService.AuthorBooksBetweenDates(author,
                                                                new DateTime(1800, 1, 1),
                                                                new DateTime(parsedBookInfo.DiscographyEnd, 12, 31),
                                                                false));
                }

                return(_bookService.GetBooksByAuthor(author.Id));
            }

            if (searchCriteria != null)
            {
                var cleanTitle = Parser.CleanAuthorName(parsedBookInfo.BookTitle);
                bookInfo = searchCriteria.Books.ExclusiveOrDefault(e => e.Title == bookTitle || e.CleanTitle == cleanTitle);
            }

            if (bookInfo == null)
            {
                // TODO: Search by Title and Year instead of just Title when matching
                bookInfo = _bookService.FindByTitle(author.AuthorMetadataId, parsedBookInfo.BookTitle);
            }

            if (bookInfo == null)
            {
                _logger.Debug("Trying inexact book match for {0}", parsedBookInfo.BookTitle);
                bookInfo = _bookService.FindByTitleInexact(author.AuthorMetadataId, parsedBookInfo.BookTitle);
            }

            if (bookInfo != null)
            {
                result.Add(bookInfo);
            }
            else
            {
                _logger.Debug("Unable to find {0}", parsedBookInfo);
            }

            return(result);
        }
Пример #10
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);
        }
Пример #11
0
        public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
        {
            if (searchCriteria != null && searchCriteria.UserInvokedSearch)
            {
                _logger.Debug("Ignoring delay for user invoked search");
                return(Decision.Accept());
            }

            var qualityProfile      = subject.Artist.QualityProfile.Value;
            var delayProfile        = _delayProfileService.BestForTags(subject.Artist.Tags);
            var delay               = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
            var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;

            if (delay == 0)
            {
                _logger.Debug("Profile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol);
                return(Decision.Accept());
            }

            var qualityComparer = new QualityModelComparer(qualityProfile);

            if (isPreferredProtocol)
            {
                foreach (var album in subject.Albums)
                {
                    var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);

                    if (trackFiles.Any())
                    {
                        var currentQualities = trackFiles.Select(c => c.Quality).Distinct().ToList();

                        var upgradable = _upgradableSpecification.IsUpgradable(qualityProfile,
                                                                               currentQualities,
                                                                               _preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName()),
                                                                               subject.ParsedAlbumInfo.Quality,
                                                                               subject.PreferredWordScore);
                        if (upgradable)
                        {
                            _logger.Debug("New quality is a better revision for existing quality, skipping delay");
                            return(Decision.Accept());
                        }
                    }
                }
            }

            // If quality meets or exceeds the best allowed quality in the profile accept it immediately
            var bestQualityInProfile = qualityProfile.LastAllowedQuality();
            var isBestInProfile      = qualityComparer.Compare(subject.ParsedAlbumInfo.Quality.Quality, bestQualityInProfile) >= 0;

            if (isBestInProfile && isPreferredProtocol)
            {
                _logger.Debug("Quality is highest in profile for preferred protocol, will not delay");
                return(Decision.Accept());
            }

            var albumIds = subject.Albums.Select(e => e.Id);

            var oldest = _pendingReleaseService.OldestPendingRelease(subject.Artist.Id, albumIds.ToArray());

            if (oldest != null && oldest.Release.AgeMinutes > delay)
            {
                return(Decision.Accept());
            }

            if (subject.Release.AgeMinutes < delay)
            {
                _logger.Debug("Waiting for better quality release, There is a {0} minute delay on {1}", delay, subject.Release.DownloadProtocol);
                return(Decision.Reject("Waiting for better quality release"));
            }

            return(Decision.Accept());
        }
Пример #12
0
        private void AddTvIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable <int> categories, SearchCriteriaBase searchCriteria, string parameters)
        {
            var includeTvdbSearch   = SupportsTvdbSearch && searchCriteria.Series.TvdbId > 0;
            var includeTvRageSearch = SupportsTvRageSearch && searchCriteria.Series.TvRageId > 0;
            var includeTvMazeSearch = SupportsTvMazeSearch && searchCriteria.Series.TvMazeId > 0;

            if (SupportsAggregatedIdSearch && (includeTvdbSearch || includeTvRageSearch || includeTvMazeSearch))
            {
                var ids = "";

                if (includeTvdbSearch)
                {
                    ids += "&tvdbid=" + searchCriteria.Series.TvdbId;
                }

                if (includeTvRageSearch)
                {
                    ids += "&rid=" + searchCriteria.Series.TvRageId;
                }

                if (includeTvMazeSearch)
                {
                    ids += "&tvmazeid=" + searchCriteria.Series.TvMazeId;
                }

                chain.Add(GetPagedRequests(maxPages, categories, "tvsearch", ids + parameters));
            }
            else
            {
                if (includeTvdbSearch)
                {
                    chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
                                               string.Format("&tvdbid={0}{1}", searchCriteria.Series.TvdbId, parameters)));
                }
                else if (includeTvRageSearch)
                {
                    chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
                                               string.Format("&rid={0}{1}", searchCriteria.Series.TvRageId, parameters)));
                }

                else if (includeTvMazeSearch)
                {
                    chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
                                               string.Format("&tvmazeid={0}{1}", searchCriteria.Series.TvMazeId, parameters)));
                }
            }

            if (SupportsTvSearch)
            {
                chain.AddTier();
                foreach (var queryTitle in searchCriteria.QueryTitles)
                {
                    chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "tvsearch",
                                               string.Format("&q={0}{1}",
                                                             NewsnabifyTitle(queryTitle),
                                                             parameters)));
                }
            }
        }
Пример #13
0
        private IEnumerable <DownloadDecision> GetDecisions(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
        {
            if (reports.Any())
            {
                _logger.ProgressInfo("Processing {0} releases", reports.Count);
            }

            else
            {
                _logger.ProgressInfo("No results found");
            }

            var reportNumber = 1;

            foreach (var report in reports)
            {
                DownloadDecision decision = null;
                _logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);
                _logger.Debug("Processing release '{0}' from '{1}'", report.Title, report.Indexer);

                try
                {
                    var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);

                    if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
                    {
                        var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, report.Title, report.TvdbId, report.TvRageId, searchCriteria);

                        if (specialEpisodeInfo != null)
                        {
                            parsedEpisodeInfo = specialEpisodeInfo;
                        }
                    }

                    if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
                    {
                        var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, searchCriteria);
                        remoteEpisode.Release = report;

                        if (remoteEpisode.Series == null)
                        {
                            var reason         = "Unknown Series";
                            var matchingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle);

                            if (matchingTvdbId.HasValue)
                            {
                                reason = $"{parsedEpisodeInfo.SeriesTitle} matches an alias for series with TVDB ID: {matchingTvdbId}";
                            }

                            decision = new DownloadDecision(remoteEpisode, new Rejection(reason));
                        }
                        else if (remoteEpisode.Episodes.Empty())
                        {
                            decision = new DownloadDecision(remoteEpisode, new Rejection("Unable to parse episodes from release name"));
                        }
                        else
                        {
                            _aggregationService.Augment(remoteEpisode);
                            remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
                            decision = GetDecisionForReport(remoteEpisode, searchCriteria);
                        }
                    }

                    if (searchCriteria != null)
                    {
                        if (parsedEpisodeInfo == null)
                        {
                            parsedEpisodeInfo = new ParsedEpisodeInfo
                            {
                                Language = LanguageParser.ParseLanguage(report.Title),
                                Quality  = QualityParser.ParseQuality(report.Title)
                            };
                        }

                        if (parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
                        {
                            var remoteEpisode = new RemoteEpisode
                            {
                                Release           = report,
                                ParsedEpisodeInfo = parsedEpisodeInfo
                            };

                            decision = new DownloadDecision(remoteEpisode, new Rejection("Unable to parse release"));
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't process release.");

                    var remoteEpisode = new RemoteEpisode {
                        Release = report
                    };
                    decision = new DownloadDecision(remoteEpisode, new Rejection("Unexpected error processing release"));
                }

                reportNumber++;

                if (decision != null)
                {
                    if (decision.Rejections.Any())
                    {
                        _logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
                    }

                    else
                    {
                        _logger.Debug("Release accepted");
                    }

                    yield return(decision);
                }
            }
        }
Пример #14
0
        private void AddAudioPageableRequests(IndexerPageableRequestChain chain, SearchCriteriaBase searchCriteria, string parameters)
        {
            chain.AddTier();

            chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "music", $"&q={parameters}"));
        }
        public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
        {
            var cdhEnabled = _configService.EnableCompletedDownloadHandling;

            if (!cdhEnabled)
            {
                _logger.Debug("Skipping already imported check because CDH is disabled");
                return(Decision.Accept());
            }

            _logger.Debug("Performing already imported check on report");
            foreach (var episode in subject.Episodes)
            {
                if (!episode.HasFile)
                {
                    _logger.Debug("Skipping already imported check for episode without file");
                    continue;
                }

                var historyForEpisode = _historyService.FindByEpisodeId(episode.Id);
                var lastGrabbed       = historyForEpisode.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed);

                if (lastGrabbed == null)
                {
                    continue;
                }

                var imported = historyForEpisode.FirstOrDefault(h =>
                                                                h.EventType == HistoryEventType.DownloadFolderImported &&
                                                                h.DownloadId == lastGrabbed.DownloadId);

                if (imported == null)
                {
                    continue;
                }

                // This is really only a guard against redownloading the same release over
                // and over when the grabbed and imported qualities do not match, if they do
                // match skip this check.
                if (lastGrabbed.Quality.Equals(imported.Quality))
                {
                    continue;
                }

                var release = subject.Release;

                if (release.DownloadProtocol == DownloadProtocol.Torrent)
                {
                    var torrentInfo = release as TorrentInfo;

                    if (torrentInfo?.InfoHash != null && torrentInfo.InfoHash.ToUpper() == lastGrabbed.DownloadId)
                    {
                        _logger.Debug("Has same torrent hash as a grabbed and imported release");
                        return(Decision.Reject("Has same torrent hash as a grabbed and imported release"));
                    }
                }

                // Only based on title because a release with the same title on another indexer/released at
                // a different time very likely has the exact same content and we don't need to also try it.

                if (release.Title.Equals(lastGrabbed.SourceTitle, StringComparison.InvariantCultureIgnoreCase))
                {
                    _logger.Debug("Has same release name as a grabbed and imported release");
                    return(Decision.Reject("Has same release name as a grabbed and imported release"));
                }
            }

            return(Decision.Accept());
        }
Пример #16
0
        private List <DownloadDecision> SearchSpecial(Series series, List <Episode> episodes)
        {
            var searchSpec = Get <SpecialEpisodeSearchCriteria>(series, episodes);

            // build list of queries for each episode in the form: "<series> <episode-title>"
            searchSpec.EpisodeQueryTitles = episodes.Where(e => !string.IsNullOrWhiteSpace(e.Title))
                                            .SelectMany(e => searchSpec.QueryTitles.Select(title => title + " " + SearchCriteriaBase.GetQueryTitle(e.Title)))
                                            .ToArray();

            return(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec));
        }
Пример #17
0
        public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
        {
            //How do we want to handle drone being off and the automatic search being triggered?
            //TODO: Add a flag to the search to state it is a "scheduled" search

            if (searchCriteria != null)
            {
                _logger.Debug("Ignore delay for searches");
                return(Decision.Accept());
            }

            var profile = subject.Series.Profile.Value;

            if (profile.GrabDelay == 0)
            {
                _logger.Debug("Profile does not delay before download");
                return(Decision.Accept());
            }

            var comparer = new QualityModelComparer(profile);

            foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
            {
                var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile, file.Quality, subject.ParsedEpisodeInfo.Quality);

                if (upgradable)
                {
                    var revisionUpgrade = _qualityUpgradableSpecification.IsRevisionUpgrade(file.Quality, subject.ParsedEpisodeInfo.Quality);

                    if (revisionUpgrade)
                    {
                        _logger.Debug("New quality is a better revision for existing quality, skipping delay");
                        return(Decision.Accept());
                    }
                }
            }

            //If quality meets or exceeds the best allowed quality in the profile accept it immediately
            var bestQualityInProfile = new QualityModel(profile.Items.Last(q => q.Allowed).Quality);
            var bestCompare          = comparer.Compare(subject.ParsedEpisodeInfo.Quality, bestQualityInProfile);

            if (bestCompare >= 0)
            {
                _logger.Debug("Quality is highest in profile, will not delay");
                return(Decision.Accept());
            }

            if (profile.GrabDelayMode == GrabDelayMode.Cutoff)
            {
                var cutoff        = new QualityModel(profile.Cutoff);
                var cutoffCompare = comparer.Compare(subject.ParsedEpisodeInfo.Quality, cutoff);

                if (cutoffCompare >= 0)
                {
                    _logger.Debug("Quality meets or exceeds the cutoff, will not delay");
                    return(Decision.Accept());
                }
            }

            if (profile.GrabDelayMode == GrabDelayMode.First)
            {
                var episodeIds = subject.Episodes.Select(e => e.Id);

                var oldest = _pendingReleaseService.GetPendingRemoteEpisodes(subject.Series.Id)
                             .Where(r => r.Episodes.Select(e => e.Id).Intersect(episodeIds).Any())
                             .OrderByDescending(p => p.Release.AgeHours)
                             .FirstOrDefault();

                if (oldest != null && oldest.Release.AgeHours > profile.GrabDelay)
                {
                    return(Decision.Accept());
                }
            }

            if (subject.Release.AgeHours < profile.GrabDelay)
            {
                _logger.Debug("Age ({0}) is less than delay {1}, delaying", subject.Release.AgeHours, profile.GrabDelay);
                return(Decision.Reject("Waiting for better quality release"));
            }

            return(Decision.Accept());
        }
Пример #18
0
        private List <DownloadDecision> Dispatch(Func <IIndexer, IEnumerable <ReleaseInfo> > searchAction, SearchCriteriaBase criteriaBase)
        {
            var indexers = _indexerFactory.SearchEnabled();
            var reports  = new List <ReleaseInfo>();

            _logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase);

            var taskList    = new List <Task>();
            var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);

            foreach (var indexer in indexers)
            {
                var indexerLocal = indexer;

                taskList.Add(taskFactory.StartNew(() =>
                {
                    try
                    {
                        var indexerReports = searchAction(indexerLocal);

                        lock (reports)
                        {
                            reports.AddRange(indexerReports);
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.Error(e, "Error while searching for " + criteriaBase);
                    }
                }).LogExceptions());
            }

            Task.WaitAll(taskList.ToArray());

            _logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);

            return(_makeDownloadDecision.GetSearchDecision(reports, criteriaBase).ToList());
        }
Пример #19
0
        private List <DownloadDecision> Dispatch(Func <IIndexer, IEnumerable <ReleaseInfo> > searchAction, SearchCriteriaBase criteriaBase)
        {
            var indexers = criteriaBase.InteractiveSearch ?
                           _indexerFactory.InteractiveSearchEnabled() :
                           _indexerFactory.AutomaticSearchEnabled();

            // Filter indexers to untagged indexers and indexers with intersecting tags
            indexers = indexers.Where(i => i.Definition.Tags.Empty() || i.Definition.Tags.Intersect(criteriaBase.Movie.Tags).Any()).ToList();

            var reports = new List <ReleaseInfo>();

            _logger.ProgressInfo("Searching indexers for {0}. {1} active indexers", criteriaBase, indexers.Count);

            var taskList    = new List <Task>();
            var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);

            foreach (var indexer in indexers)
            {
                var indexerLocal = indexer;

                taskList.Add(taskFactory.StartNew(() =>
                {
                    try
                    {
                        var indexerReports = searchAction(indexerLocal);

                        lock (reports)
                        {
                            reports.AddRange(indexerReports);
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.Error(e, "Error while searching for {0}", criteriaBase);
                    }
                }).LogExceptions());
            }

            Task.WaitAll(taskList.ToArray());

            _logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);

            return(_makeDownloadDecision.GetSearchDecision(reports, criteriaBase).ToList());
        }
Пример #20
0
        public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
        {
            if (searchCriteria != null)
            {
                _logger.Debug("Skipping history check during search");
                return(Decision.Accept());
            }

            var cdhEnabled = _configService.EnableCompletedDownloadHandling;

            _logger.Debug("Performing history status check on report");
            foreach (var album in subject.Albums)
            {
                _logger.Debug("Checking current status of album [{0}] in history", album.Id);
                var mostRecent = _historyService.MostRecentForAlbum(album.Id);

                if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed)
                {
                    var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
                    // The artist will be the same as the one in history since it's the same album.
                    // Instead of fetching the artist from the DB reuse the known artist.
                    var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Artist, mostRecent.SourceTitle);

                    var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
                        subject.Artist.QualityProfile,
                        new List <QualityModel> {
                        mostRecent.Quality
                    },
                        preferredWordScore,
                        subject.ParsedAlbumInfo.Quality,
                        subject.PreferredWordScore);

                    var upgradeable = _upgradableSpecification.IsUpgradable(
                        subject.Artist.QualityProfile,
                        new List <QualityModel> {
                        mostRecent.Quality
                    },
                        preferredWordScore,
                        subject.ParsedAlbumInfo.Quality,
                        subject.PreferredWordScore);

                    if (!recent && cdhEnabled)
                    {
                        continue;
                    }

                    if (!cutoffUnmet)
                    {
                        if (recent)
                        {
                            return(Decision.Reject("Recent grab event in history already meets cutoff: {0}", mostRecent.Quality));
                        }

                        return(Decision.Reject("CDH is disabled and grab event in history already meets cutoff: {0}", mostRecent.Quality));
                    }

                    if (!upgradeable)
                    {
                        if (recent)
                        {
                            return(Decision.Reject("Recent grab event in history is of equal or higher quality: {0}", mostRecent.Quality));
                        }

                        return(Decision.Reject("CDH is disabled and grab event in history is of equal or higher quality: {0}", mostRecent.Quality));
                    }
                }
            }

            return(Decision.Accept());
        }
Пример #21
0
 private void AddTitlePageableRequests(IndexerPageableRequestChain chain, IEnumerable <int> categories, SearchCriteriaBase searchCriteria, string parameters)
 {
     if (SupportsTvTitleSearch)
     {
         foreach (var searchTerm in searchCriteria.SceneTitles)
         {
             chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "tvsearch",
                                        string.Format("&title={0}{1}",
                                                      Uri.EscapeDataString(searchTerm),
                                                      parameters)));
         }
     }
     else if (SupportsTvSearch)
     {
         var queryTitles = TvTextSearchEngine == "raw" ? searchCriteria.SceneTitles : searchCriteria.QueryTitles;
         foreach (var queryTitle in queryTitles)
         {
             chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "tvsearch",
                                        string.Format("&q={0}{1}",
                                                      NewsnabifyTitle(queryTitle),
                                                      parameters)));
         }
     }
 }
Пример #22
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 check.");
            }
            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)
                {
                    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)
                {
                    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());
        }
Пример #23
0
        public List <Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null)
        {
            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(new List <Episode>());
                }

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

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

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

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

            return(GetStandardEpisodes(series, parsedEpisodeInfo, sceneSource, searchCriteria));
        }
Пример #24
0
        private Rejection EvaluateSpec(IDecisionEngineSpecification spec, RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteriaBase = null)
        {
            try
            {
                var result = spec.IsSatisfiedBy(remoteEpisode, searchCriteriaBase);

                if (!result.Accepted)
                {
                    return(new Rejection(result.Reason, spec.Type));
                }
            }
            catch (Exception e)
            {
                e.Data.Add("report", remoteEpisode.Release.ToJson());
                e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
                _logger.ErrorException("Couldn't evaluate decision on " + remoteEpisode.Release.Title, e);
                return(new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message)));
            }

            return(null);
        }
Пример #25
0
        private MappingResult GetMovie(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria)
        {
            // TODO: Answer me this: Wouldn't it be smarter to start out looking for a movie if we have an ImDb Id?
            MappingResult result = null;

            if (!String.IsNullOrWhiteSpace(imdbId) && imdbId != "0")
            {
                if (TryGetMovieByImDbId(parsedMovieInfo, imdbId, out result))
                {
                    return(result);
                }
            }

            if (searchCriteria != null)
            {
                if (TryGetMovieBySearchCriteria(parsedMovieInfo, searchCriteria, out result))
                {
                    return(result);
                }
            }
            else
            {
                TryGetMovieByTitleAndOrYear(parsedMovieInfo, out result);
                return(result);
            }

            // nothing found up to here => logging that and returning null
            _logger.Debug($"No matching movie {parsedMovieInfo.MovieTitle}");
            return(result);
        }
Пример #26
0
 public List <DownloadDecision> GetSearchDecision(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
 {
     return(GetDecisions(reports, searchCriteriaBase).ToList());
 }
Пример #27
0
        private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria)
        {
            Series series = null;

            /*var localEpisode = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
             *
             * var sceneMappingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle);
             * if (localEpisode != null)
             * {
             *  if (searchCriteria != null && searchCriteria.Series.TvdbId == localEpisode.TvdbId)
             *  {
             *      return searchCriteria.Series;
             *  }
             *
             *  series = _seriesService.FindByTvdbId(sceneMappingTvdbId.Value);
             *
             *  if (series == null)
             *  {
             *      _logger.Debug("No matching series {0}", parsedEpisodeInfo.SeriesTitle);
             *      return null;
             *  }
             *
             *  return series;
             * }*///This is only to find scene mapping should not be necessary for movies.

            if (searchCriteria != null)
            {
                if (searchCriteria.Series.CleanTitle == parsedEpisodeInfo.SeriesTitle.CleanSeriesTitle())
                {
                    return(searchCriteria.Series);
                }

                if (tvdbId > 0 && tvdbId == searchCriteria.Series.TvdbId)
                {
                    //TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
                    return(searchCriteria.Series);
                }

                if (tvRageId > 0 && tvRageId == searchCriteria.Series.TvRageId)
                {
                    //TODO: If series is found by TvRageId, we should report it as a scene naming exception, since it will fail to import
                    return(searchCriteria.Series);
                }
            }

            series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);

            if (series == null && tvdbId > 0)
            {
                //TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
                series = _seriesService.FindByTvdbId(tvdbId);
            }

            if (series == null && tvRageId > 0)
            {
                //TODO: If series is found by TvRageId, we should report it as a scene naming exception, since it will fail to import
                series = _seriesService.FindByTvRageId(tvRageId);
            }

            if (series == null)
            {
                _logger.Debug("No matching series {0}", parsedEpisodeInfo.SeriesTitle);
                return(null);
            }

            return(series);
        }
Пример #28
0
        private IEnumerable <DownloadDecision> GetDecisions(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
        {
            if (reports.Any())
            {
                _logger.ProgressInfo("Processing {0} releases", reports.Count);
            }

            else
            {
                _logger.ProgressInfo("No results found");
            }

            var reportNumber = 1;

            foreach (var report in reports)
            {
                DownloadDecision decision = null;
                _logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);

                try
                {
                    var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);

                    if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
                    {
                        var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(report.Title, report.TvdbId, report.TvRageId, searchCriteria);

                        if (specialEpisodeInfo != null)
                        {
                            parsedEpisodeInfo = specialEpisodeInfo;
                        }
                    }

                    if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
                    {
                        var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, searchCriteria);
                        remoteEpisode.Release = report;

                        if (remoteEpisode.Series != null)
                        {
                            remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
                            decision = GetDecisionForReport(remoteEpisode, searchCriteria);
                        }
                        else
                        {
                            decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown Series"));
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Couldn't process release.", e);
                }

                reportNumber++;

                if (decision != null)
                {
                    if (decision.Rejections.Any())
                    {
                        _logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
                    }

                    else
                    {
                        _logger.Debug("Release accepted");
                    }

                    yield return(decision);
                }
            }
        }
Пример #29
0
 public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
 {
     throw new NotImplementedException();
 }
Пример #30
0
        private List <DownloadDecision> SearchSpecial(Series series, List <Episode> episodes, bool monitoredOnly, bool userInvokedSearch, bool interactiveSearch)
        {
            var downloadDecisions = new List <DownloadDecision>();

            var searchSpec = Get <SpecialEpisodeSearchCriteria>(series, episodes, monitoredOnly, userInvokedSearch, interactiveSearch);

            // build list of queries for each episode in the form: "<series> <episode-title>"
            searchSpec.EpisodeQueryTitles = episodes.Where(e => !string.IsNullOrWhiteSpace(e.Title))
                                            .SelectMany(e => searchSpec.CleanSceneTitles.Select(title => title + " " + SearchCriteriaBase.GetCleanSceneTitle(e.Title)))
                                            .ToArray();

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

            // Search for each episode by season/episode number as well
            foreach (var episode in episodes)
            {
                // Episode needs to be monitored if it's not an interactive search
                if (!interactiveSearch && monitoredOnly && !episode.Monitored)
                {
                    continue;
                }

                downloadDecisions.AddRange(SearchSingle(series, episode, monitoredOnly, userInvokedSearch, interactiveSearch));
            }

            return(DeDupeDecisions(downloadDecisions));
        }