public List <ImportDecision> GetImportDecisions(List <string> videoFiles, Series series, DownloadClientItem downloadClientItem, ParsedEpisodeInfo folderInfo, bool sceneSource, bool filterExistingFiles) { var newFiles = filterExistingFiles ? _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series) : videoFiles.ToList(); _logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count()); ParsedEpisodeInfo downloadClientItemInfo = null; if (downloadClientItem != null) { downloadClientItemInfo = Parser.Parser.ParseTitle(downloadClientItem.Title); } // If not importing from a scene source (series folder for example), then assume all files are not samples // to avoid using media info on every file needlessly (especially if Analyse Media Files is disabled). var nonSampleVideoFileCount = sceneSource ? GetNonSampleVideoFileCount(newFiles, series, downloadClientItemInfo, folderInfo) : videoFiles.Count; var decisions = new List <ImportDecision>(); foreach (var file in newFiles) { var localEpisode = new LocalEpisode { Series = series, DownloadClientEpisodeInfo = downloadClientItemInfo, FolderEpisodeInfo = folderInfo, Path = file, SceneSource = sceneSource, ExistingFile = series.Path.IsParentPath(file), OtherVideoFiles = nonSampleVideoFileCount > 1 }; decisions.AddIfNotNull(GetDecision(localEpisode, downloadClientItem, nonSampleVideoFileCount > 1)); } return(decisions); }
private string GetOriginalFilePath(DownloadClientItem downloadClientItem, LocalEpisode localEpisode) { var path = localEpisode.Path; if (downloadClientItem != null && !downloadClientItem.OutputPath.IsEmpty) { var outputDirectory = downloadClientItem.OutputPath.Directory.ToString(); if (outputDirectory.IsParentPath(path)) { return(outputDirectory.GetRelativePath(path)); } } var folderEpisodeInfo = localEpisode.FolderEpisodeInfo; if (folderEpisodeInfo != null) { var folderPath = path.GetAncestorPath(folderEpisodeInfo.ReleaseTitle); if (folderPath != null) { return(folderPath.GetParentPath().GetRelativePath(path)); } } var parentPath = path.GetParentPath(); var grandparentPath = parentPath.GetParentPath(); if (grandparentPath != null) { return(grandparentPath.GetRelativePath(path)); } return(Path.GetFileName(path)); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (!_buildFileNames.RequiresEpisodeTitle(localEpisode.Series, localEpisode.Episodes)) { _logger.Debug("File name format does not require episode title, skipping check"); return(Decision.Accept()); } foreach (var episode in localEpisode.Episodes) { var airDateUtc = episode.AirDateUtc; var title = episode.Title; if (airDateUtc.HasValue && airDateUtc.Value.Before(DateTime.UtcNow.AddDays(-1))) { _logger.Debug("Episode aired more than 1 day 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()); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { var episodeFiles = localEpisode.Episodes.Where(e => e.EpisodeFileId != 0).Select(e => e.EpisodeFile).ToList(); if (episodeFiles.Count == 0) { _logger.Debug("No existing episode file, skipping"); return(Decision.Accept()); } if (episodeFiles.Count > 1) { _logger.Debug("More than one existing episode file, skipping."); return(Decision.Accept()); } if (episodeFiles.First().Value.Size == localEpisode.Size) { _logger.Debug("'{0}' Has the same filesize as existing file", localEpisode.Path); return(Decision.Reject("Has the same filesize as existing file")); } return(Decision.Accept()); }
public LocalEpisode Augment(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { var isMediaFile = MediaFileExtensions.Extensions.Contains(Path.GetExtension(localEpisode.Path)); if (localEpisode.DownloadClientEpisodeInfo == null && localEpisode.FolderEpisodeInfo == null && localEpisode.FileEpisodeInfo == null) { if (isMediaFile) { throw new AugmentingFailedException("Unable to parse episode info from path: {0}", localEpisode.Path); } } localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path); localEpisode.SceneName = localEpisode.SceneSource ? SceneNameCalculator.GetSceneName(localEpisode) : null; if (isMediaFile && (!localEpisode.ExistingFile || _configService.EnableMediaInfo)) { localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(localEpisode.Path); } foreach (var augmenter in _augmenters) { try { augmenter.Aggregate(localEpisode, downloadClientItem); } catch (Exception ex) { _logger.Warn(ex, ex.Message); } } return(localEpisode); }
public void Setup() { _localEpisode = new LocalEpisode(); _localEpisode.Series = new Series { Path = @"C:\Test\TV\Series".AsOsAgnostic() }; _episodeFile = Builder <EpisodeFile> .CreateNew() .Build(); Mocker.GetMock <IDiskProvider>() .Setup(c => c.FolderExists(Directory.GetParent(_localEpisode.Series.Path).FullName)) .Returns(true); Mocker.GetMock <IDiskProvider>() .Setup(c => c.FileExists(It.IsAny <string>())) .Returns(true); Mocker.GetMock <IDiskProvider>() .Setup(c => c.GetParentFolder(It.IsAny <string>())) .Returns <string>(c => Path.GetDirectoryName(c)); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (downloadClientItem == null) { _logger.Debug("No download client information is available, skipping"); return(Decision.Accept()); } foreach (var episode in localEpisode.Episodes) { if (!episode.HasFile) { _logger.Debug("Skipping already imported check for episode without file"); continue; } var episodeHistory = _historyService.FindByEpisodeId(episode.Id); var lastImported = episodeHistory.FirstOrDefault(h => h.EventType == HistoryEventType.DownloadFolderImported); if (lastImported == null) { continue; } // TODO: Ignore last imported check if the same release was grabbed again // See: https://github.com/Sonarr/Sonarr/issues/2393 if (lastImported.DownloadId == downloadClientItem.DownloadId) { _logger.Debug("Episode file previously imported at {0}", lastImported.Date); return(Decision.Reject("Episode file already imported at {0}", lastImported.Date)); } } return(Decision.Accept()); }
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { if (localEpisode.ExistingFile) { _logger.Debug("Existing file, skipping sample check"); return(Decision.Accept()); } var sample = _detectSample.IsSample(localEpisode.Series, localEpisode.Path, localEpisode.IsSpecial); if (sample == DetectSampleResult.Sample) { return(Decision.Reject("Sample")); } else if (sample == DetectSampleResult.Indeterminate) { return(Decision.Reject("Unable to determine if file is a sample")); } return(Decision.Accept()); }
public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, bool newDownload) { EpisodeInfo = episodeInfo; ImportedEpisode = importedEpisode; NewDownload = newDownload; }
public EpisodeImportedEvent(LocalEpisode droppedEpisode, EpisodeFile importedEpisode) { DroppedEpisode = droppedEpisode; ImportedEpisode = importedEpisode; }
public override IEnumerable <ExtraFile> ProcessFiles(Series series, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing metadata in {0}", series.Path); var metadataFiles = new List <MetadataFile>(); var filterResult = FilterAndClean(series, filesOnDisk, importedFiles); foreach (var possibleMetadataFile in filterResult.FilesOnDisk) { // Don't process files that have known Subtitle file extensions (saves a bit of unecessary processing) if (SubtitleFileExtensions.Extensions.Contains(Path.GetExtension(possibleMetadataFile))) { continue; } foreach (var consumer in _consumers) { var metadata = consumer.FindMetadataFile(series, possibleMetadataFile); if (metadata == null) { continue; } if (metadata.Type == MetadataType.EpisodeImage || metadata.Type == MetadataType.EpisodeMetadata) { var localEpisode = new LocalEpisode { FileEpisodeInfo = Parser.Parser.ParsePath(possibleMetadataFile), Series = series, Path = possibleMetadataFile }; try { _aggregationService.Augment(localEpisode, null); } catch (AugmentingFailedException) { _logger.Debug("Unable to parse extra file: {0}", possibleMetadataFile); continue; } if (localEpisode.Episodes.Empty()) { _logger.Debug("Cannot find related episodes for: {0}", possibleMetadataFile); continue; } if (localEpisode.Episodes.DistinctBy(e => e.EpisodeFileId).Count() > 1) { _logger.Debug("Extra file: {0} does not match existing files.", possibleMetadataFile); continue; } metadata.SeasonNumber = localEpisode.SeasonNumber; metadata.EpisodeFileId = localEpisode.Episodes.First().EpisodeFileId; } metadata.Extension = Path.GetExtension(possibleMetadataFile); metadataFiles.Add(metadata); } } _logger.Info("Found {0} existing metadata files", metadataFiles.Count); _metadataFileService.Upsert(metadataFiles); // Return files that were just imported along with files that were // previously imported so previously imported files aren't imported twice return(metadataFiles.Concat(filterResult.PreviouslyImported)); }
public void Execute(ManualImportCommand message) { _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode); var imported = new List <ImportResult>(); var importedTrackedDownload = new List <ManuallyImportedFile>(); for (int i = 0; i < message.Files.Count; i++) { _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); var file = message.Files[i]; var series = _seriesService.GetSeries(file.SeriesId); var episodes = _episodeService.GetEpisodes(file.EpisodeIds); var fileEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo(); var existingFile = series.Path.IsParentPath(file.Path); TrackedDownload trackedDownload = null; var localEpisode = new LocalEpisode { ExistingFile = false, Episodes = episodes, FileEpisodeInfo = fileEpisodeInfo, Path = file.Path, ReleaseGroup = file.ReleaseGroup, Quality = file.Quality, Language = file.Language, Series = series, Size = 0 }; if (file.DownloadId.IsNotNullOrWhiteSpace()) { trackedDownload = _trackedDownloadService.Find(file.DownloadId); localEpisode.DownloadClientEpisodeInfo = trackedDownload?.RemoteEpisode?.ParsedEpisodeInfo; } if (file.FolderName.IsNotNullOrWhiteSpace()) { localEpisode.FolderEpisodeInfo = Parser.Parser.ParseTitle(file.FolderName); localEpisode.SceneSource = !existingFile; } // Augment episode file so imported files have all additional information an automatic import would localEpisode = _aggregationService.Augment(localEpisode, trackedDownload?.DownloadItem); // Apply the user-chosen values. localEpisode.Series = series; localEpisode.Episodes = episodes; localEpisode.ReleaseGroup = file.ReleaseGroup; localEpisode.Quality = file.Quality; localEpisode.Language = file.Language; //TODO: Cleanup non-tracked downloads var importDecision = new ImportDecision(localEpisode); if (trackedDownload == null) { imported.AddRange(_importApprovedEpisodes.Import(new List <ImportDecision> { importDecision }, !existingFile, null, message.ImportMode)); } else { var importResult = _importApprovedEpisodes.Import(new List <ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); imported.Add(importResult); importedTrackedDownload.Add(new ManuallyImportedFile { TrackedDownload = trackedDownload, ImportResult = importResult }); } } if (imported.Any()) { _logger.ProgressTrace("Manually imported {0} files", imported.Count); } foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList()) { var trackedDownload = groupedTrackedDownload.First().TrackedDownload; var importedSeries = imported.First().ImportDecision.LocalEpisode.Series; var outputPath = trackedDownload.ImportItem.OutputPath.FullPath; if (_diskProvider.FolderExists(outputPath)) { if (_downloadedEpisodesImportService.ShouldDeleteFolder( new DirectoryInfo(outputPath), importedSeries) && trackedDownload.DownloadItem.CanMoveFiles) { _diskProvider.DeleteFolder(outputPath, true); } } var allEpisodesImported = groupedTrackedDownload.Select(c => c.ImportResult) .Where(c => c.Result == ImportResultType.Imported) .SelectMany(c => c.ImportDecision.LocalEpisode.Episodes).Count() >= Math.Max(1, trackedDownload.RemoteEpisode?.Episodes?.Count ?? 1); if (allEpisodesImported) { trackedDownload.State = TrackedDownloadState.Imported; _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, importedSeries.Id)); } } }
public EpisodeDownloadedEvent(LocalEpisode episode) { Episode = episode; }
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()); }
public override IEnumerable <ExtraFile> ImportFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, List <string> files, bool isReadOnly) { var importedFiles = new List <ExtraFile>(); var filteredFiles = files.Where(f => CanImportFile(localEpisode, episodeFile, f, Path.GetExtension(f), isReadOnly)).ToList(); var sourcePath = localEpisode.Path; var sourceFolder = _diskProvider.GetParentFolder(sourcePath); var sourceFileName = Path.GetFileNameWithoutExtension(sourcePath); var matchingFiles = new List <string>(); var hasNfo = false; foreach (var file in filteredFiles) { try { // Filter out duplicate NFO files if (file.EndsWith(".nfo", StringComparison.InvariantCultureIgnoreCase)) { if (hasNfo) { continue; } hasNfo = true; } // Filename match if (Path.GetFileNameWithoutExtension(file).StartsWith(sourceFileName, StringComparison.InvariantCultureIgnoreCase)) { matchingFiles.Add(file); continue; } // Season and episode match var fileEpisodeInfo = Parser.Parser.ParsePath(file) ?? new ParsedEpisodeInfo(); if (fileEpisodeInfo.EpisodeNumbers.Length == 0) { continue; } if (fileEpisodeInfo.SeasonNumber == localEpisode.FileEpisodeInfo.SeasonNumber && fileEpisodeInfo.EpisodeNumbers.SequenceEqual(localEpisode.FileEpisodeInfo.EpisodeNumbers)) { matchingFiles.Add(file); } } catch (Exception ex) { _logger.Warn(ex, "Failed to import extra file: {0}", file); } } foreach (string file in matchingFiles) { try { var extraFile = ImportFile(localEpisode.Series, episodeFile, file, isReadOnly, Path.GetExtension(file), null); _mediaFileAttributeService.SetFilePermissions(file); _otherExtraFileService.Upsert(extraFile); importedFiles.Add(extraFile); } catch (Exception ex) { _logger.Warn(ex, "Failed to import extra file: {0}", file); } } return(importedFiles); }
public EpisodeDownloadedEvent(LocalEpisode episode, EpisodeFile episodeFile, List <EpisodeFile> oldFiles) { Episode = episode; EpisodeFile = episodeFile; OldFiles = oldFiles; }
private ImportDecision GetDecision(string file, Series series, DownloadClientItem downloadClientItem, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName) { ImportDecision decision = null; try { var localEpisode = _parsingService.GetLocalEpisode(file, series, shouldUseFolderName ? folderInfo : null, sceneSource); if (localEpisode != null) { localEpisode.Quality = GetQuality(folderInfo, localEpisode.Quality, series); localEpisode.Size = _diskProvider.GetFileSize(file); _logger.Debug("Size: {0}", localEpisode.Size); //TODO: make it so media info doesn't ruin the import process of a new series if (sceneSource) { localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(file); } if (localEpisode.Episodes.Empty()) { if (localEpisode.ParsedEpisodeInfo.IsPartialSeason) { decision = new ImportDecision(localEpisode, new Rejection("Partial season packs are not supported")); } else if (localEpisode.ParsedEpisodeInfo.IsSeasonExtra) { decision = new ImportDecision(localEpisode, new Rejection("Extras are not supported")); } else { decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode")); } } else { decision = GetDecision(localEpisode, downloadClientItem); } } else { localEpisode = new LocalEpisode(); localEpisode.Path = file; decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file")); } } catch (Exception e) { _logger.Error(e, "Couldn't import file. {0}", file); var localEpisode = new LocalEpisode { Path = file }; decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file")); } if (decision == null) { _logger.Error("Unable to make a decision on {0}", file); } else if (decision.Rejections.Any()) { _logger.Debug("File rejected for the following reasons: {0}", string.Join(", ", decision.Rejections)); } else { _logger.Debug("File accepted"); } return(decision); }
public void Execute(ManualImportCommand message) { _logger.ProgressTrace("Manually importing {0} files", message.Files.Count); var imported = new List <ImportResult>(); var importedTrackedDownload = new List <ManuallyImportedFile>(); for (int i = 0; i < message.Files.Count; i++) { _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); var file = message.Files[i]; var series = _seriesService.GetSeries(file.SeriesId); var episodes = _episodeService.GetEpisodes(file.EpisodeIds); var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo(); var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path); var existingFile = series.Path.IsParentPath(file.Path); var localEpisode = new LocalEpisode { ExistingFile = false, Episodes = episodes, MediaInfo = mediaInfo, ParsedEpisodeInfo = parsedEpisodeInfo, Path = file.Path, Quality = file.Quality, Series = series, Size = 0 }; //TODO: Option to copy instead of import //TODO: Cleanup non-tracked downloads var importDecision = new ImportDecision(localEpisode); if (file.DownloadId.IsNullOrWhiteSpace()) { imported.AddRange(_importApprovedEpisodes.Import(new List <ImportDecision> { importDecision }, !existingFile)); } else { var trackedDownload = _trackedDownloadService.Find(file.DownloadId); var importResult = _importApprovedEpisodes.Import(new List <ImportDecision> { importDecision }, true, trackedDownload.DownloadItem).First(); imported.Add(importResult); importedTrackedDownload.Add(new ManuallyImportedFile { TrackedDownload = trackedDownload, ImportResult = importResult }); } } _logger.ProgressTrace("Manually imported {0} files", imported.Count); foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList()) { var trackedDownload = groupedTrackedDownload.First().TrackedDownload; if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath)) { if (_downloadedEpisodesImportService.ShouldDeleteFolder( new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath), trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly) { _diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true); } } if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count)) { trackedDownload.State = TrackedDownloadStage.Imported; _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload)); } } }
public ImportDecision(LocalEpisode localEpisode, params Rejection[] rejections) { LocalEpisode = localEpisode; Rejections = rejections.ToList(); }
public LocalEpisode Aggregate(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { localEpisode.Episodes = GetEpisodes(localEpisode); return(localEpisode); }
public LocalEpisode Aggregate(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { var source = QualitySource.Unknown; var sourceConfidence = Confidence.Default; var resolution = 0; var resolutionConfidence = Confidence.Default; var revision = new Revision(1); var revisionConfidence = Confidence.Default; foreach (var augmentQuality in _augmentQualities) { var augmentedQuality = augmentQuality.AugmentQuality(localEpisode, downloadClientItem); if (augmentedQuality == null) { continue; } _logger.Trace("Considering Source {0} ({1}) Resolution {2} ({3}) Revision {4} from {5}", augmentedQuality.Source, augmentedQuality.SourceConfidence, augmentedQuality.Resolution, augmentedQuality.ResolutionConfidence, augmentedQuality.Revision, augmentQuality.Name); if (source == QualitySource.Unknown || augmentedQuality.SourceConfidence > sourceConfidence && augmentedQuality.Source != QualitySource.Unknown) { source = augmentedQuality.Source; sourceConfidence = augmentedQuality.SourceConfidence; } if (resolution == 0 || augmentedQuality.ResolutionConfidence > resolutionConfidence && augmentedQuality.Resolution > 0) { resolution = augmentedQuality.Resolution; resolutionConfidence = augmentedQuality.ResolutionConfidence; } if (augmentedQuality.Revision != null) { // Update the revision and confidence if it is higher than the current confidence, // this will allow explicitly detected v0 to override the v1 default. if (augmentedQuality.RevisionConfidence > revisionConfidence) { revision = augmentedQuality.Revision; revisionConfidence = augmentedQuality.RevisionConfidence; } // Update the revision and confidence if it is the same confidence and the revision is higher, // this will allow the best revision to be used in the event there is a disagreement. else if (augmentedQuality.RevisionConfidence == revisionConfidence && augmentedQuality.Revision > revision) { revision = augmentedQuality.Revision; revisionConfidence = augmentedQuality.RevisionConfidence; } } } _logger.Trace("Selected Source {0} ({1}) Resolution {2} ({3}) Revision {4}", source, sourceConfidence, resolution, resolutionConfidence, revision); var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution), revision); if (resolutionConfidence == Confidence.MediaInfo) { quality.ResolutionDetectionSource = QualityDetectionSource.MediaInfo; } else if (resolutionConfidence == Confidence.Fallback) { quality.ResolutionDetectionSource = QualityDetectionSource.Extension; } else { quality.ResolutionDetectionSource = QualityDetectionSource.Name; } if (sourceConfidence == Confidence.Fallback) { quality.SourceDetectionSource = QualityDetectionSource.Extension; } else { quality.SourceDetectionSource = QualityDetectionSource.Name; } quality.RevisionDetectionSource = revisionConfidence == Confidence.Tag ? QualityDetectionSource.Name : QualityDetectionSource.Unknown; _logger.Debug("Using quality: {0}", quality); localEpisode.Quality = quality; return(localEpisode); }
public abstract IEnumerable <ExtraFile> ImportFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, List <string> files, bool isReadOnly);
private void EnsureEpisodeFolder(EpisodeFile episodeFile, LocalEpisode localEpisode, string filePath) { EnsureEpisodeFolder(episodeFile, localEpisode.Series, localEpisode.SeasonNumber, filePath); }
public override bool CanImportFile(LocalEpisode localEpisode, EpisodeFile episodeFile, string path, string extension, bool readOnly) { return(false); }
private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Series series = null) { try { var trackedDownload = GetTrackedDownload(downloadId); var relativeFile = baseFolder.GetRelativePath(file); if (series == null) { _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]); } if (series == null) { series = _parsingService.GetSeries(relativeFile); } if (trackedDownload != null && series == null) { series = trackedDownload?.RemoteEpisode?.Series; } if (series == null) { var relativeParseInfo = Parser.Parser.ParsePath(relativeFile); if (relativeParseInfo != null) { series = _seriesService.FindByTitle(relativeParseInfo.SeriesTitle); } } if (series == null) { var localEpisode = new LocalEpisode(); localEpisode.Path = file; localEpisode.ReleaseGroup = Parser.Parser.ParseReleaseGroup(file); localEpisode.Quality = QualityParser.ParseQuality(file); localEpisode.Language = LanguageParser.ParseLanguage(file); localEpisode.Size = _diskProvider.GetFileSize(file); return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), rootFolder, downloadId, null)); } var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> { file }, series, trackedDownload?.DownloadItem, null, SceneSource(series, baseFolder)); if (importDecisions.Any()) { return(MapItem(importDecisions.First(), rootFolder, downloadId, null)); } } catch (Exception ex) { _logger.Warn(ex, "Failed to process file: {0}", file); } return(new ManualImportItem { DownloadId = downloadId, Path = file, RelativePath = rootFolder.GetRelativePath(file), Name = Path.GetFileNameWithoutExtension(file), Rejections = new List <Rejection>() }); }
public override IEnumerable <ExtraFile> ImportFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, List <string> files, bool isReadOnly) { return(Enumerable.Empty <ExtraFile>()); }
public LocalEpisode Aggregate(LocalEpisode localEpisode, bool otherFiles) { localEpisode.Episodes = GetEpisodes(localEpisode, otherFiles); return(localEpisode); }
private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId) { DownloadClientItem downloadClientItem = null; var relativeFile = baseFolder.GetRelativePath(file); var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]); if (series == null) { series = _parsingService.GetSeries(relativeFile); } if (downloadId.IsNotNullOrWhiteSpace()) { var trackedDownload = _trackedDownloadService.Find(downloadId); downloadClientItem = trackedDownload.DownloadItem; if (series == null) { series = trackedDownload.RemoteEpisode.Series; } } if (series == null) { var relativeParseInfo = Parser.Parser.ParsePath(relativeFile); if (relativeParseInfo != null) { series = _seriesService.FindByTitle(relativeParseInfo.SeriesTitle); } } if (series == null) { var localEpisode = new LocalEpisode(); localEpisode.Path = file; localEpisode.Quality = QualityParser.ParseQuality(file); localEpisode.Size = _diskProvider.GetFileSize(file); return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), rootFolder, downloadId, null)); } var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> { file }, series, downloadClientItem, null, SceneSource(series, baseFolder)); if (importDecisions.Any()) { return(MapItem(importDecisions.First(), rootFolder, downloadId, null)); } return(new ManualImportItem { DownloadId = downloadId, Path = file, RelativePath = rootFolder.GetRelativePath(file), Name = Path.GetFileNameWithoutExtension(file), Rejections = new List <Rejection>() }); }
public override IEnumerable <ExtraFile> ProcessFiles(Series series, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing extra files in {0}", series.Path); var extraFiles = new List <OtherExtraFile>(); var filterResult = FilterAndClean(series, filesOnDisk, importedFiles); foreach (var possibleExtraFile in filterResult.FilesOnDisk) { var extension = Path.GetExtension(possibleExtraFile); if (extension.IsNullOrWhiteSpace()) { _logger.Debug("No extension for file: {0}", possibleExtraFile); continue; } var localEpisode = new LocalEpisode { FileEpisodeInfo = Parser.Parser.ParsePath(possibleExtraFile), Series = series, Path = possibleExtraFile }; try { _aggregationService.Augment(localEpisode, null); } catch (AugmentingFailedException) { _logger.Debug("Unable to parse extra file: {0}", possibleExtraFile); continue; } if (localEpisode.Episodes.Empty()) { _logger.Debug("Cannot find related episodes for: {0}", possibleExtraFile); continue; } if (localEpisode.Episodes.DistinctBy(e => e.EpisodeFileId).Count() > 1) { _logger.Debug("Extra file: {0} does not match existing files.", possibleExtraFile); continue; } var extraFile = new OtherExtraFile { SeriesId = series.Id, SeasonNumber = localEpisode.SeasonNumber, EpisodeFileId = localEpisode.Episodes.First().EpisodeFileId, RelativePath = series.Path.GetRelativePath(possibleExtraFile), Extension = extension }; extraFiles.Add(extraFile); } _logger.Info("Found {0} existing other extra files", extraFiles.Count); _otherExtraFileService.Upsert(extraFiles); // Return files that were just imported along with files that were // previously imported so previously imported files aren't imported twice return(extraFiles.Concat(filterResult.PreviouslyImported)); }
public LocalEpisode Aggregate(LocalEpisode localEpisode, DownloadClientItem downloadClientItem, bool otherFiles) { localEpisode.Episodes = GetEpisodes(localEpisode, otherFiles); return(localEpisode); }