private ParsedEpisodeInfo GetBestEpisodeInfo(LocalEpisode localEpisode, bool otherFiles) { var parsedEpisodeInfo = localEpisode.FileEpisodeInfo; var downloadClientEpisodeInfo = localEpisode.DownloadClientEpisodeInfo; var folderEpisodeInfo = localEpisode.FolderEpisodeInfo; if (!otherFiles && !SceneChecker.IsSceneTitle(Path.GetFileNameWithoutExtension(localEpisode.Path))) { if (downloadClientEpisodeInfo != null && !downloadClientEpisodeInfo.FullSeason && PreferOtherEpisodeInfo(parsedEpisodeInfo, downloadClientEpisodeInfo)) { parsedEpisodeInfo = localEpisode.DownloadClientEpisodeInfo; } else if (folderEpisodeInfo != null && !folderEpisodeInfo.FullSeason && PreferOtherEpisodeInfo(parsedEpisodeInfo, folderEpisodeInfo)) { parsedEpisodeInfo = localEpisode.FolderEpisodeInfo; } } if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode) { var title = Path.GetFileNameWithoutExtension(localEpisode.Path); var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, localEpisode.Series); return(specialEpisodeInfo); } return(parsedEpisodeInfo); }
private ParsedEpisodeInfo GetSpecialEpisodeInfo(LocalEpisode localEpisode, ParsedEpisodeInfo parsedEpisodeInfo) { var title = Path.GetFileNameWithoutExtension(localEpisode.Path); var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, localEpisode.Series); return(specialEpisodeInfo); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (localEpisode.ExistingFile) { return(Decision.Accept()); } var fileInfo = localEpisode.FileEpisodeInfo; var folderInfo = localEpisode.FolderEpisodeInfo; if (folderInfo != null && folderInfo.IsPossibleSceneSeasonSpecial) { folderInfo = _parsingService.ParseSpecialEpisodeTitle(folderInfo, folderInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0); } if (folderInfo == null) { _logger.Debug("No folder ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } if (fileInfo == null) { _logger.Debug("No file ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } if (!folderInfo.EpisodeNumbers.Any()) { _logger.Debug("No episode numbers in folder ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } if (folderInfo.SeasonNumber != fileInfo.SeasonNumber) { return(Decision.Reject("Season number {0} was unexpected considering the folder name {1}", fileInfo.SeasonNumber, folderInfo.ReleaseTitle)); } var unexpected = fileInfo.EpisodeNumbers.Where(f => !folderInfo.EpisodeNumbers.Contains(f)).ToList(); if (unexpected.Any()) { _logger.Debug("Unexpected episode number(s) in file: {0}", string.Join(", ", unexpected)); if (unexpected.Count == 1) { return(Decision.Reject("Episode number {0} was unexpected considering the {1} folder name", unexpected.First(), folderInfo.ReleaseTitle)); } return(Decision.Reject("Episode numbers {0} were unexpected considering the {1} folder name", string.Join(", ", unexpected), folderInfo.ReleaseTitle)); } return(Decision.Accept()); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (localEpisode.ExistingFile) { return(Decision.Accept()); } var dirInfo = new FileInfo(localEpisode.Path).Directory; if (dirInfo == null) { return(Decision.Accept()); } var folderInfo = Parser.Parser.ParseTitle(dirInfo.Name); if (folderInfo != null && folderInfo.IsPossibleSceneSeasonSpecial) { folderInfo = _parsingService.ParseSpecialEpisodeTitle(folderInfo, dirInfo.Name, localEpisode.Series.TvdbId, 0); } if (folderInfo == null) { return(Decision.Accept()); } if (!folderInfo.EpisodeNumbers.Any()) { return(Decision.Accept()); } if (folderInfo.FullSeason) { return(Decision.Accept()); } var unexpected = localEpisode.ParsedEpisodeInfo.EpisodeNumbers.Where(f => !folderInfo.EpisodeNumbers.Contains(f)).ToList(); if (unexpected.Any()) { _logger.Debug("Unexpected episode number(s) in file: {0}", string.Join(", ", unexpected)); if (unexpected.Count == 1) { return(Decision.Reject("Episode Number {0} was unexpected considering the {1} folder name", unexpected.First(), dirInfo.Name)); } return(Decision.Reject("Episode Numbers {0} were unexpected considering the {1} folder name", string.Join(", ", unexpected), dirInfo.Name)); } return(Decision.Accept()); }
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, parsedEpisodeInfo.SeasonNumber); 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 identify correct episode(s) using release name and scene mappings")); } 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); } } }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading) { LogItemChange(existingItem, existingItem.DownloadItem, downloadItem); existingItem.DownloadItem = downloadItem; return(existingItem); } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } if (historyItems.Any()) { var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First(); trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType); if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.Empty()) { // Try parsing the original source title and if that fails, try parsing it as a special // TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } if (trackedDownload.RemoteEpisode == null) { _logger.Trace("No Episode found for download '{0}', not tracking.", trackedDownload.DownloadItem.Title); return(null); } } catch (Exception e) { _logger.Debug(e, "Failed to find episode for " + downloadItem.Title); return(null); } LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem); _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return(trackedDownload); }
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.TvRageId, searchCriteria); if (specialEpisodeInfo != null) { parsedEpisodeInfo = specialEpisodeInfo; } } if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace()) { var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 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)); } yield return(decision); } } }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadState.Downloading) { LogItemChange(existingItem, existingItem.DownloadItem, downloadItem); existingItem.DownloadItem = downloadItem; existingItem.IsTrackable = true; return(existingItem); } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol, IsTrackable = true }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId) .OrderByDescending(h => h.Date) .ToList(); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } var downloadHistory = _downloadHistoryService.GetLatestDownloadHistoryItem(downloadItem.DownloadId); if (downloadHistory != null) { var state = GetStateFromHistory(downloadHistory.EventType); trackedDownload.State = state; } if (historyItems.Any()) { var firstHistoryItem = historyItems.First(); var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EpisodeHistoryEventType.Grabbed); trackedDownload.Indexer = grabbedEvent?.Data["indexer"]; if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.Empty()) { // Try parsing the original source title and if that fails, try parsing it as a special // TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == EpisodeHistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } // Track it so it can be displayed in the queue even though we can't determine which series it is for if (trackedDownload.RemoteEpisode == null) { _logger.Trace("No Episode found for download '{0}'", trackedDownload.DownloadItem.Title); } } catch (Exception e) { _logger.Debug(e, "Failed to find episode for " + downloadItem.Title); return(null); } LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem); _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return(trackedDownload); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (localEpisode.ExistingFile) { return(Decision.Accept()); } var fileInfo = localEpisode.FileEpisodeInfo; var folderInfo = localEpisode.FolderEpisodeInfo; if (fileInfo != null && fileInfo.IsPossibleSceneSeasonSpecial) { fileInfo = _parsingService.ParseSpecialEpisodeTitle(fileInfo, fileInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0); } if (folderInfo != null && folderInfo.IsPossibleSceneSeasonSpecial) { folderInfo = _parsingService.ParseSpecialEpisodeTitle(folderInfo, folderInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0); } if (folderInfo == null) { _logger.Debug("No folder ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } if (fileInfo == null) { _logger.Debug("No file ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } var folderEpisodes = _parsingService.GetEpisodes(folderInfo, localEpisode.Series, true); var fileEpisodes = _parsingService.GetEpisodes(fileInfo, localEpisode.Series, true); if (folderEpisodes.Empty()) { _logger.Debug("No episode numbers in folder ParsedEpisodeInfo, skipping check"); return(Decision.Accept()); } if (folderEpisodes.First().SeasonNumber != fileEpisodes.FirstOrDefault()?.SeasonNumber) { return(Decision.Reject("Season number {0} was unexpected considering the folder name {1}", fileInfo.SeasonNumber, folderInfo.ReleaseTitle)); } var unexpected = fileEpisodes.Where(e => folderEpisodes.All(o => o.Id != e.Id)).ToList(); if (unexpected.Any()) { _logger.Debug("Unexpected episode(s) in file: {0}", FormatEpisode(unexpected)); if (unexpected.Count == 1) { return(Decision.Reject("Episode {0} was unexpected considering the {1} folder name", FormatEpisode(unexpected), folderInfo.ReleaseTitle)); } return(Decision.Reject("Episodes {0} were unexpected considering the {1} folder name", FormatEpisode(unexpected), folderInfo.ReleaseTitle)); } return(Decision.Accept()); }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadState.Downloading) { LogItemChange(existingItem, existingItem.DownloadItem, downloadItem); existingItem.DownloadItem = downloadItem; existingItem.IsTrackable = true; return(existingItem); } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol, IsTrackable = true }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId) .OrderByDescending(h => h.Date) .ToList(); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } if (historyItems.Any()) { var firstHistoryItem = historyItems.First(); var state = GetStateFromHistory(firstHistoryItem.EventType); trackedDownload.State = state; // TODO: Restore check to confirm all files were imported // This will treat partially imported downloads as imported (as it was before), which means a partially imported download after a // restart will get marked as imported without importing the restart of the files. // One potential issue here is if the latest is imported, but other episodes are ignored or never imported. // It's unlikely that will happen, but could happen if additional episodes are added to season after it's already imported. // if (state == TrackedDownloadState.Imported) // { // trackedDownload.State = TrackedDownloadState.Imported; // // var allImported = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems); // // trackedDownload.State = allImported ? TrackedDownloadState.Imported : TrackedDownloadState.Downloading; // } // else // { // trackedDownload.State = state; // } var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == HistoryEventType.Grabbed); trackedDownload.Indexer = grabbedEvent?.Data["indexer"]; if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.Empty()) { // Try parsing the original source title and if that fails, try parsing it as a special // TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } // Track it so it can be displayed in the queue even though we can't determine which serires it is for if (trackedDownload.RemoteEpisode == null) { _logger.Trace("No Episode found for download '{0}'", trackedDownload.DownloadItem.Title); } } catch (Exception e) { _logger.Debug(e, "Failed to find episode for " + downloadItem.Title); return(null); } LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem); _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return(trackedDownload); }