예제 #1
0
        public List <ManualImportItem> GetMediaFiles(int seriesId, int?seasonNumber)
        {
            var series        = _seriesService.GetSeries(seriesId);
            var directoryInfo = new DirectoryInfo(series.Path);
            var seriesFiles   = seasonNumber.HasValue ? _mediaFileService.GetFilesBySeason(seriesId, seasonNumber.Value) : _mediaFileService.GetFilesBySeries(seriesId);

            var items = seriesFiles.Select(episodeFile => MapItem(episodeFile, series, directoryInfo.Name)).ToList();

            if (!seasonNumber.HasValue)
            {
                var mediaFiles    = _diskScanService.FilterPaths(series.Path, _diskScanService.GetVideoFiles(series.Path)).ToList();
                var unmappedFiles = MediaFileService.FilterExistingFiles(mediaFiles, seriesFiles, series);

                items.AddRange(unmappedFiles.Select(file =>
                                                    new ManualImportItem
                {
                    Path         = Path.Combine(series.Path, file),
                    FolderName   = directoryInfo.Name,
                    RelativePath = series.Path.GetRelativePath(file),
                    Name         = Path.GetFileNameWithoutExtension(file),
                    Series       = series,
                    SeasonNumber = null,
                    Episodes     = new List <Episode>(),
                    ReleaseGroup = string.Empty,
                    Quality      = new QualityModel(Quality.Unknown),
                    Language     = Language.Unknown,
                    Size         = _diskProvider.GetFileSize(file),
                    Rejections   = Enumerable.Empty <Rejection>()
                }
                                                    ));
            }

            return(items);
        }
예제 #2
0
        private List <ManualImportItem> ProcessFolder(string rootFolder, string baseFolder, string downloadId, int?seriesId, bool filterExistingFiles)
        {
            DownloadClientItem downloadClientItem = null;
            Series             series             = null;

            var directoryInfo = new DirectoryInfo(baseFolder);

            if (seriesId.HasValue)
            {
                series = _seriesService.GetSeries(seriesId.Value);
            }
            else
            {
                try
                {
                    series = _parsingService.GetSeries(directoryInfo.Name);
                }
                catch (MultipleSeriesFoundException e)
                {
                    _logger.Warn(e, "Unable to find series from title");
                }
            }

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload.DownloadItem;

                if (series == null)
                {
                    series = trackedDownload.RemoteEpisode?.Series;
                }
            }

            if (series == null)
            {
                // Filter paths based on the rootFolder, so files in subfolders that should be ignored are ignored.
                // It will lead to some extra directories being checked for files, but it saves the processing of them and is cleaner than
                // teaching FilterPaths to know whether it's processing a file or a folder and changing it's filtering based on that.

                var files      = _diskScanService.FilterPaths(rootFolder, _diskScanService.GetVideoFiles(baseFolder, false));
                var subfolders = _diskScanService.FilterPaths(rootFolder, _diskProvider.GetDirectories(baseFolder));

                var processedFiles   = files.Select(file => ProcessFile(rootFolder, baseFolder, file, downloadId));
                var processedFolders = subfolders.SelectMany(subfolder => ProcessFolder(rootFolder, subfolder, downloadId, null, filterExistingFiles));

                return(processedFiles.Concat(processedFolders).Where(i => i != null).ToList());
            }

            var folderInfo  = Parser.Parser.ParseTitle(directoryInfo.Name);
            var seriesFiles = _diskScanService.GetVideoFiles(baseFolder).ToList();
            var decisions   = _importDecisionMaker.GetImportDecisions(seriesFiles, series, downloadClientItem, folderInfo, SceneSource(series, baseFolder), filterExistingFiles);

            return(decisions.Select(decision => MapItem(decision, rootFolder, downloadId, directoryInfo.Name)).ToList());
        }
예제 #3
0
        private List <ManualImportItem> ProcessFolder(string rootFolder, string baseFolder, string downloadId, int?movieId, bool filterExistingFiles)
        {
            DownloadClientItem downloadClientItem = null;

            var directoryInfo = new DirectoryInfo(baseFolder);

            var movie = movieId.HasValue ?
                        _movieService.GetMovie(movieId.Value) :
                        _parsingService.GetMovie(directoryInfo.Name);

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload.DownloadItem;

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

            if (movie == null)
            {
                // Filter paths based on the rootFolder, so files in subfolders that should be ignored are ignored.
                // It will lead to some extra directories being checked for files, but it saves the processing of them and is cleaner than
                // teaching FilterPaths to know whether it's processing a file or a folder and changing it's filtering based on that.
                // If the movie is unknown for the directory and there are more than 100 files in the folder don't process the items before returning.
                var files = _diskScanService.FilterPaths(rootFolder, _diskScanService.GetVideoFiles(baseFolder, false));

                if (files.Count() > 100)
                {
                    return(ProcessDownloadDirectory(rootFolder, files));
                }

                var subfolders = _diskScanService.FilterPaths(rootFolder, _diskProvider.GetDirectories(baseFolder));

                var processedFiles   = files.Select(file => ProcessFile(rootFolder, baseFolder, file, downloadId));
                var processedFolders = subfolders.SelectMany(subfolder => ProcessFolder(rootFolder, subfolder, downloadId, null, filterExistingFiles));

                return(processedFiles.Concat(processedFolders).Where(i => i != null).ToList());
            }

            var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name);
            var movieFiles = _diskScanService.FilterPaths(rootFolder, _diskScanService.GetVideoFiles(baseFolder).ToList());
            var decisions  = _importDecisionMaker.GetImportDecisions(movieFiles, movie, downloadClientItem, folderInfo, SceneSource(movie, baseFolder), filterExistingFiles);

            return(decisions.Select(decision => MapItem(decision, rootFolder, downloadId, directoryInfo.Name)).ToList());
        }
예제 #4
0
        public void Handle(MovieScannedEvent message)
        {
            var movie      = message.Movie;
            var extraFiles = new List <ExtraFile>();

            if (!_diskProvider.FolderExists(movie.Path))
            {
                return;
            }

            _logger.Debug("Looking for existing extra files in {0}", movie.Path);

            var filesOnDisk        = _diskScanService.GetNonVideoFiles(movie.Path);
            var possibleExtraFiles = _diskScanService.FilterPaths(movie.Path, filesOnDisk, false);

            var filteredFiles = possibleExtraFiles;
            var importedFiles = new List <string>();

            foreach (var existingExtraFileImporter in _existingExtraFileImporters)
            {
                var imported = existingExtraFileImporter.ProcessFiles(movie, filteredFiles, importedFiles);

                importedFiles.AddRange(imported.Select(f => Path.Combine(movie.Path, f.RelativePath)));
            }

            _logger.Info("Found {0} extra files", extraFiles.Count);
        }
        public void Handle(SeriesScannedEvent message)
        {
            var series = message.Series;

            if (!_diskProvider.FolderExists(series.Path))
            {
                return;
            }

            _logger.Debug("Looking for existing extra files in {0}", series.Path);

            var filesOnDisk        = _diskScanService.GetNonVideoFiles(series.Path);
            var possibleExtraFiles = _diskScanService.FilterPaths(series.Path, filesOnDisk);

            var importedFiles = new List <string>();

            foreach (var existingExtraFileImporter in _existingExtraFileImporters)
            {
                var imported = existingExtraFileImporter.ProcessFiles(series, possibleExtraFiles, importedFiles);

                importedFiles.AddRange(imported.Select(f => Path.Combine(series.Path, f.RelativePath)));
            }

            _logger.Info("Found {0} possible extra files, imported {1} files.", possibleExtraFiles.Count, importedFiles.Count);
        }
        private List <ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Movie movie, DownloadClientItem downloadClientItem)
        {
            if (_movieService.MoviePathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing show");
                return(new List <ImportResult>());
            }

            var cleanedUpName    = GetCleanedUpFolderName(directoryInfo.Name);
            var historyItems     = _historyService.FindByDownloadId(downloadClientItem?.DownloadId ?? "");
            var firstHistoryItem = historyItems?.OrderByDescending(h => h.Date).FirstOrDefault();
            var folderInfo       = _parsingService.ParseMovieInfo(cleanedUpName, new List <object> {
                firstHistoryItem
            });

            if (folderInfo != null)
            {
                _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
            }

            var videoFiles = _diskScanService.FilterPaths(directoryInfo.FullName, _diskScanService.GetVideoFiles(directoryInfo.FullName));

            if (downloadClientItem == null)
            {
                foreach (var videoFile in videoFiles)
                {
                    if (_diskProvider.IsFileLocked(videoFile))
                    {
                        return(new List <ImportResult>
                        {
                            FileIsLockedResult(videoFile)
                        });
                    }
                }
            }

            var decisions     = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, downloadClientItem, folderInfo, true);
            var importResults = _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);

            if (importMode == ImportMode.Auto)
            {
                importMode = (downloadClientItem == null || downloadClientItem.CanMoveFiles) ? ImportMode.Move : ImportMode.Copy;
            }

            if (importMode == ImportMode.Move &&
                importResults.Any(i => i.Result == ImportResultType.Imported) &&
                ShouldDeleteFolder(directoryInfo, movie))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
        private List <ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem)
        {
            if (_seriesService.SeriesPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing show");
                return(new List <ImportResult>());
            }

            var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
            var videoFiles = _diskScanService.FilterPaths(directoryInfo.FullName, _diskScanService.GetVideoFiles(directoryInfo.FullName));

            if (downloadClientItem == null)
            {
                foreach (var videoFile in videoFiles)
                {
                    if (_diskProvider.IsFileLocked(videoFile))
                    {
                        return(new List <ImportResult>
                        {
                            FileIsLockedResult(videoFile)
                        });
                    }
                }
            }

            var decisions     = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, downloadClientItem, folderInfo, true);
            var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);

            if (importMode == ImportMode.Auto)
            {
                importMode = (downloadClientItem == null || downloadClientItem.CanMoveFiles) ? ImportMode.Move : ImportMode.Copy;
            }

            if (importMode == ImportMode.Move &&
                importResults.Any(i => i.Result == ImportResultType.Imported) &&
                ShouldDeleteFolder(directoryInfo, series))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
예제 #8
0
        private IEnumerable <WatchFolderItem> GetDownloadItems(string watchFolder, Dictionary <string, WatchFolderItem> lastWatchItems, TimeSpan waitPeriod)
        {
            foreach (var folder in _diskScanService.FilterPaths(watchFolder, _diskProvider.GetDirectories(watchFolder)))
            {
                var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder));

                var newWatchItem = new WatchFolderItem
                {
                    DownloadId = Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks,
                    Title      = title,

                    OutputPath = new OsPath(folder),

                    Status        = DownloadItemStatus.Completed,
                    RemainingTime = TimeSpan.Zero
                };

                var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId);

                if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
                {
                    var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);

                    newWatchItem.TotalSize = files.Select(_diskProvider.GetFileSize).Sum();
                    newWatchItem.Hash      = GetHash(folder, files);

                    if (files.Any(_diskProvider.IsFileLocked))
                    {
                        newWatchItem.Status        = DownloadItemStatus.Downloading;
                        newWatchItem.RemainingTime = null;
                    }

                    UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod);
                }

                yield return(newWatchItem);
            }

            foreach (var videoFile in _diskScanService.FilterPaths(watchFolder, _diskScanService.GetVideoFiles(watchFolder, false)))
            {
                var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));

                var newWatchItem = new WatchFolderItem
                {
                    DownloadId = Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks,
                    Title      = title,

                    OutputPath = new OsPath(videoFile),

                    Status        = DownloadItemStatus.Completed,
                    RemainingTime = TimeSpan.Zero
                };

                var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId);

                if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
                {
                    newWatchItem.TotalSize = _diskProvider.GetFileSize(videoFile);
                    newWatchItem.Hash      = GetHash(videoFile);

                    if (_diskProvider.IsFileLocked(videoFile))
                    {
                        newWatchItem.Status = DownloadItemStatus.Downloading;
                    }

                    UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod);
                }

                yield return(newWatchItem);
            }
        }