private ImportDecision GetDecision(LocalEpisode localEpisode, DownloadClientItem downloadClientItem, bool otherFiles)
        {
            ImportDecision decision = null;

            var fileEpisodeInfo = Parser.Parser.ParsePath(localEpisode.Path);

            localEpisode.FileEpisodeInfo = fileEpisodeInfo;
            localEpisode.Size            = _diskProvider.GetFileSize(localEpisode.Path);

            try
            {
                _aggregationService.Augment(localEpisode, downloadClientItem, otherFiles);

                if (localEpisode.Episodes.Empty())
                {
                    if (IsPartialSeason(localEpisode))
                    {
                        decision = new ImportDecision(localEpisode, new Rejection("Partial season packs are not supported"));
                    }
                    else if (IsSeasonExtra(localEpisode))
                    {
                        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);
                }
            }
            catch (AugmentingFailedException)
            {
                decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file"));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Couldn't import file. {0}", localEpisode.Path);

                decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file"));
            }

            if (decision == null)
            {
                _logger.Error("Unable to make a decision on {0}", localEpisode.Path);
            }
            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);
        }
Example #2
0
        private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles)
        {
            ImportDecision decision = null;

            var fileMovieInfo = Parser.Parser.ParseMoviePath(localMovie.Path);

            if (fileMovieInfo != null)
            {
                fileMovieInfo = _parsingService.EnhanceMovieInfo(fileMovieInfo);
            }

            localMovie.FileMovieInfo = fileMovieInfo;
            localMovie.Size          = _diskProvider.GetFileSize(localMovie.Path);

            try
            {
                _aggregationService.Augment(localMovie, downloadClientItem, otherFiles);

                if (localMovie.Movie == null)
                {
                    decision = new ImportDecision(localMovie, new Rejection("Invalid movie"));
                }
                else
                {
                    decision = GetDecision(localMovie, downloadClientItem);
                }
            }
            catch (AugmentingFailedException)
            {
                decision = new ImportDecision(localMovie, new Rejection("Unable to parse file"));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Couldn't import file. {0}", localMovie.Path);

                decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file"));
            }

            if (decision == null)
            {
                _logger.Error("Unable to make a decision on {0}", localMovie.Path);
            }
            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 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 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));
        }
Example #5
0
        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));
                }
            }
        }
Example #6
0
        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 movie = _movieService.GetMovie(file.MovieId);
                var fileMovieInfo = Parser.Parser.ParseMoviePath(file.Path) ?? new ParsedMovieInfo();
                var existingFile = movie.Path.IsParentPath(file.Path);
                TrackedDownload trackedDownload = null;

                var localMovie = new LocalMovie
                {
                    ExistingFile = false,
                    FileMovieInfo = fileMovieInfo,
                    Path = file.Path,
                    Quality = file.Quality,
                    Languages = file.Languages,
                    Movie = movie,
                    Size = 0
                };

                if (file.DownloadId.IsNotNullOrWhiteSpace())
                {
                    trackedDownload = _trackedDownloadService.Find(file.DownloadId);
                    localMovie.DownloadClientMovieInfo = trackedDownload?.RemoteMovie?.ParsedMovieInfo;
                }

                if (file.FolderName.IsNotNullOrWhiteSpace())
                {
                    localMovie.FolderMovieInfo = Parser.Parser.ParseMovieTitle(file.FolderName);
                    localMovie.SceneSource = !existingFile;
                }

                localMovie = _aggregationService.Augment(localMovie, trackedDownload?.DownloadItem, false);

                // Apply the user-chosen values.
                localMovie.Movie = movie;
                localMovie.Quality = file.Quality;
                localMovie.Languages = file.Languages;

                //TODO: Cleanup non-tracked downloads
                var importDecision = new ImportDecision(localMovie);

                if (trackedDownload == null)
                {
                    imported.AddRange(_importApprovedMovie.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
                }
                else
                {
                    var importResult = _importApprovedMovie.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).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;

                var importMovie = groupedTrackedDownload.First().ImportResult.ImportDecision.LocalMovie.Movie;
                var outputPath = trackedDownload.ImportItem.OutputPath.FullPath;

                if (_diskProvider.FolderExists(outputPath))
                {
                    if (_downloadedMovieImportService.ShouldDeleteFolder(
                            new DirectoryInfo(outputPath),
                            importMovie) && trackedDownload.DownloadItem.CanMoveFiles)
                    {
                        _diskProvider.DeleteFolder(outputPath, true);
                    }
                }

                if (groupedTrackedDownload.Select(c => c.ImportResult).Any(c => c.Result == ImportResultType.Imported))
                {
                    trackedDownload.State = TrackedDownloadState.Imported;
                    _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, importMovie.Id));
                }
            }
        }
Example #7
0
        private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Movie movie = null)
        {
            try
            {
                var trackedDownload = GetTrackedDownload(downloadId);
                var relativeFile    = baseFolder.GetRelativePath(file);

                if (movie == null)
                {
                    movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]);
                }

                if (movie == null)
                {
                    movie = _parsingService.GetMovie(relativeFile);
                }

                if (trackedDownload != null && movie == null)
                {
                    movie = trackedDownload?.RemoteMovie?.Movie;
                }

                if (movie == null)
                {
                    var relativeParseInfo = Parser.Parser.ParseMoviePath(relativeFile);

                    if (relativeParseInfo != null)
                    {
                        movie = _movieService.FindByTitle(relativeParseInfo.PrimaryMovieTitle, relativeParseInfo.Year);
                    }
                }

                if (movie == null)
                {
                    var localMovie = new LocalMovie();
                    localMovie.Path                    = file;
                    localMovie.FileMovieInfo           = Parser.Parser.ParseMoviePath(file);
                    localMovie.DownloadClientMovieInfo = trackedDownload?.RemoteMovie?.ParsedMovieInfo;

                    localMovie = _aggregationService.Augment(localMovie, null, false);

                    return(MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), rootFolder, downloadId, null));
                }

                var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                    file
                }, movie, trackedDownload?.DownloadItem, null, SceneSource(movie, 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>()
            });
        }