Example #1
0
        private Dictionary <int, string> GetSeasonFolders(Series series)
        {
            var seasonFolderMap = new Dictionary <int, string>();

            foreach (var folder in _diskProvider.GetDirectories(series.Path))
            {
                var directoryinfo = new DirectoryInfo(folder);
                var seasonMatch   = SeasonImagesRegex.Match(directoryinfo.Name);

                if (seasonMatch.Success)
                {
                    var seasonNumber = seasonMatch.Groups["season"].Value;

                    if (seasonNumber.Contains("specials"))
                    {
                        seasonFolderMap[0] = folder;
                    }
                    else
                    {
                        int matchedSeason;
                        if (int.TryParse(seasonNumber, out matchedSeason))
                        {
                            seasonFolderMap[matchedSeason] = folder;
                        }
                        else
                        {
                            _logger.Debug("Failed to parse season number from {0} for series {1}.", folder, series.Title);
                        }
                    }
                }

                else
                {
                    _logger.Debug("Rejecting folder {0} for series {1}.", Path.GetDirectoryName(folder), series.Title);
                }
            }

            return(seasonFolderMap);
        }
Example #2
0
        private List <UnmappedFolder> GetUnmappedFolders(string path, List <string> moviePaths)
        {
            _logger.Debug("Generating list of unmapped folders");

            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentException("Invalid path provided", nameof(path));
            }

            var results = new List <UnmappedFolder>();

            if (!_diskProvider.FolderExists(path))
            {
                _logger.Debug("Path supplied does not exist: {0}", path);
                return(results);
            }

            var possibleMovieFolders = _diskProvider.GetDirectories(path).ToList();
            var unmappedFolders      = possibleMovieFolders.Except(moviePaths.Select(s => s), PathEqualityComparer.Instance).ToList();

            foreach (string unmappedFolder in unmappedFolders)
            {
                var di = new DirectoryInfo(unmappedFolder.Normalize());
                if ((!di.Attributes.HasFlag(FileAttributes.System) && !di.Attributes.HasFlag(FileAttributes.Hidden)) || di.Attributes.ToString() == "-1")
                {
                    results.Add(new UnmappedFolder {
                        Name = di.Name, Path = di.FullName
                    });
                }
            }

            var setToRemove = SpecialFolders;

            results.RemoveAll(x => setToRemove.Contains(new DirectoryInfo(x.Path.ToLowerInvariant()).Name));

            _logger.Debug("{0} unmapped folders detected.", results.Count);
            return(results.OrderBy(u => u.Name, StringComparer.InvariantCultureIgnoreCase).ToList());
        }
        public void DeleteEpisodeFile(Series series, EpisodeFile episodeFile)
        {
            var fullPath   = Path.Combine(series.Path, episodeFile.RelativePath);
            var rootFolder = _diskProvider.GetParentFolder(series.Path);

            if (!_diskProvider.FolderExists(rootFolder))
            {
                _logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder);
                throw new NzbDroneClientException(HttpStatusCode.Conflict, "Series' root folder ({0}) doesn't exist.", rootFolder);
            }

            if (_diskProvider.GetDirectories(rootFolder).Empty())
            {
                _logger.Warn("Series' root folder ({0}) is empty.", rootFolder);
                throw new NzbDroneClientException(HttpStatusCode.Conflict, "Series' root folder ({0}) is empty.", rootFolder);
            }

            if (_diskProvider.FolderExists(series.Path) && _diskProvider.FileExists(fullPath))
            {
                _logger.Info("Deleting episode file: {0}", fullPath);

                var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));

                try
                {
                    _recycleBinProvider.DeleteFile(fullPath, subfolder);
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Unable to delete episode file");
                    throw new NzbDroneClientException(HttpStatusCode.InternalServerError, "Unable to delete episode file");
                }
            }

            // Delete the episode file from the database to clean it up even if the file was already deleted
            _mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
        }
Example #4
0
        private List <ManualImportItem> ProcessFolder(string rootFolder, string baseFolder, string downloadId, int?seriesId, bool filterExistingFiles)
        {
            DownloadClientItem downloadClientItem = null;
            var directoryInfo = new DirectoryInfo(baseFolder);

            var series = seriesId.HasValue ?
                         _seriesService.GetSeries(seriesId.Value) :
                         _parsingService.GetSeries(directoryInfo.Name);

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

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

            if (series == null)
            {
                var files      = _diskScanService.FilterFiles(baseFolder, _diskScanService.GetVideoFiles(baseFolder, false));
                var subfolders = _diskScanService.FilterFiles(baseFolder, _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());
        }
        public List <UnmappedFolder> GetUnmappedFolders(string path)
        {
            Logger.Debug("Generating list of unmapped folders");
            if (String.IsNullOrEmpty(path))
            {
                throw new ArgumentException("Invalid path provided", "path");
            }

            var results = new List <UnmappedFolder>();
            var series  = _seriesRepository.All().ToList();

            if (!_diskProvider.FolderExists(path))
            {
                Logger.Debug("Path supplied does not exist: {0}", path);
                return(results);
            }

            var seriesFolders   = _diskProvider.GetDirectories(path).ToList();
            var unmappedFolders = seriesFolders.Except(series.Select(s => s.Path), new PathEqualityComparer()).ToList();

            foreach (string unmappedFolder in unmappedFolders)
            {
                var di = new DirectoryInfo(unmappedFolder.Normalize());
                results.Add(new UnmappedFolder {
                    Name = di.Name, Path = di.FullName
                });
            }

            if (Path.GetPathRoot(path).Equals(path, StringComparison.InvariantCultureIgnoreCase))
            {
                var setToRemove = SpecialFolders;
                results.RemoveAll(x => setToRemove.Contains(new DirectoryInfo(x.Path.ToLowerInvariant()).Name));
            }

            Logger.Debug("{0} unmapped folders detected.", results.Count);
            return(results);
        }
Example #6
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.

                // If the series 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.ParseTitle(directoryInfo.Name);
            var seriesFiles = _diskScanService.FilterPaths(rootFolder, _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());
        }
Example #7
0
        private IEnumerable <WatchFolderItem> GetDownloadItems(string watchFolder, Dictionary <string, WatchFolderItem> lastWatchItems, TimeSpan waitPeriod)
        {
            // get a fresh naming config each time, in case the user has made changes
            foreach (var folder in _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.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);
            }
        }
Example #8
0
        public void Scan(List <string> folders = null, FilterFilesType filter = FilterFilesType.Known, bool addNewArtists = false, List <int> authorIds = null)
        {
            if (folders == null)
            {
                folders = _rootFolderService.All().Select(x => x.Path).ToList();
            }

            if (authorIds == null)
            {
                authorIds = new List <int>();
            }

            var mediaFileList = new List <IFileInfo>();

            var musicFilesStopwatch = Stopwatch.StartNew();

            foreach (var folder in folders)
            {
                // We could be scanning a root folder or a subset of a root folder.  If it's a subset,
                // check if the root folder exists before cleaning.
                var rootFolder = _rootFolderService.GetBestRootFolder(folder);

                if (rootFolder == null)
                {
                    _logger.Error("Not scanning {0}, it's not a subdirectory of a defined root folder", folder);
                    return;
                }

                if (!_diskProvider.FolderExists(rootFolder.Path))
                {
                    _logger.Warn("Root folder {0} doesn't exist.", rootFolder.Path);

                    var skippedArtists = _authorService.GetAuthors(authorIds);
                    skippedArtists.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderDoesNotExist)));
                    return;
                }

                if (_diskProvider.GetDirectories(rootFolder.Path).Empty())
                {
                    _logger.Warn("Root folder {0} is empty.", rootFolder.Path);

                    var skippedArtists = _authorService.GetAuthors(authorIds);
                    skippedArtists.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderIsEmpty)));
                    return;
                }

                if (!_diskProvider.FolderExists(folder))
                {
                    _logger.Debug("Specified scan folder ({0}) doesn't exist.", folder);

                    CleanMediaFiles(folder, new List <string>());
                    continue;
                }

                _logger.ProgressInfo("Scanning {0}", folder);

                var files = FilterFiles(folder, GetBookFiles(folder));

                if (!files.Any())
                {
                    _logger.Warn("Scan folder {0} is empty.", folder);
                    continue;
                }

                CleanMediaFiles(folder, files.Select(x => x.FullName).ToList());
                mediaFileList.AddRange(files);
            }

            musicFilesStopwatch.Stop();
            _logger.Trace("Finished getting track files for:\n{0} [{1}]", folders.ConcatToString("\n"), musicFilesStopwatch.Elapsed);

            var decisionsStopwatch = Stopwatch.StartNew();

            var config = new ImportDecisionMakerConfig
            {
                Filter          = filter,
                IncludeExisting = true,
                AddNewAuthors   = addNewArtists
            };

            var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, null, null, config);

            decisionsStopwatch.Stop();
            _logger.Debug("Import decisions complete [{0}]", decisionsStopwatch.Elapsed);

            var importStopwatch = Stopwatch.StartNew();

            _importApprovedTracks.Import(decisions, false);

            // decisions may have been filtered to just new files.  Anything new and approved will have been inserted.
            // Now we need to make sure anything new but not approved gets inserted
            // Note that knownFiles will include anything imported just now
            var knownFiles = new List <BookFile>();

            folders.ForEach(x => knownFiles.AddRange(_mediaFileService.GetFilesWithBasePath(x)));

            var newFiles = decisions
                           .ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance)
                           .Select(decision => new BookFile
            {
                Path      = decision.Item.Path,
                CalibreId = decision.Item.Path.ParseCalibreId(),
                Size      = decision.Item.Size,
                Modified  = decision.Item.Modified,
                DateAdded = DateTime.UtcNow,
                Quality   = decision.Item.Quality,
                MediaInfo = decision.Item.FileTrackInfo.MediaInfo
            })
                           .ToList();

            _mediaFileService.AddMany(newFiles);

            _logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles");

            // finally update info on size/modified for existing files
            var updatedFiles = knownFiles
                               .Join(decisions,
                                     x => x.Path,
                                     x => x.Item.Path,
                                     (file, decision) => new
            {
                File = file,
                Item = decision.Item
            },
                                     PathEqualityComparer.Instance)
                               .Where(x => x.File.Size != x.Item.Size ||
                                      Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1)
                               .Select(x =>
            {
                x.File.Size      = x.Item.Size;
                x.File.Modified  = x.Item.Modified;
                x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo;
                x.File.Quality   = x.Item.Quality;
                return(x.File);
            })
                               .ToList();

            _mediaFileService.Update(updatedFiles);

            _logger.Debug($"Updated info for {updatedFiles.Count} known files");

            var artists = _authorService.GetAuthors(authorIds);

            foreach (var author in artists)
            {
                CompletedScanning(author);
            }

            importStopwatch.Stop();
            _logger.Debug("Book import complete for:\n{0} [{1}]", folders.ConcatToString("\n"), importStopwatch.Elapsed);
        }
Example #9
0
        public void Scan(Artist artist, FilterFilesType filter = FilterFilesType.Known)
        {
            var rootFolder = _rootFolderService.GetBestRootFolderPath(artist.Path);

            if (!_diskProvider.FolderExists(rootFolder))
            {
                _logger.Warn("Artist' root folder ({0}) doesn't exist.", rootFolder);
                _eventAggregator.PublishEvent(new ArtistScanSkippedEvent(artist, ArtistScanSkippedReason.RootFolderDoesNotExist));
                return;
            }

            if (_diskProvider.GetDirectories(rootFolder).Empty())
            {
                _logger.Warn("Artist' root folder ({0}) is empty.", rootFolder);
                _eventAggregator.PublishEvent(new ArtistScanSkippedEvent(artist, ArtistScanSkippedReason.RootFolderIsEmpty));
                return;
            }

            _logger.ProgressInfo("Scanning {0}", artist.Name);

            if (!_diskProvider.FolderExists(artist.Path))
            {
                if (_configService.CreateEmptyArtistFolders)
                {
                    _logger.Debug("Creating missing artist folder: {0}", artist.Path);
                    _diskProvider.CreateFolder(artist.Path);
                    SetPermissions(artist.Path);
                }
                else
                {
                    _logger.Debug("Artist folder doesn't exist: {0}", artist.Path);
                }

                CleanMediaFiles(artist, new List <string>());
                CompletedScanning(artist);

                return;
            }

            var musicFilesStopwatch = Stopwatch.StartNew();
            var mediaFileList       = FilterFiles(artist.Path, GetAudioFiles(artist.Path)).ToList();

            musicFilesStopwatch.Stop();
            _logger.Trace("Finished getting track files for: {0} [{1}]", artist, musicFilesStopwatch.Elapsed);

            CleanMediaFiles(artist, mediaFileList.Select(x => x.FullName).ToList());

            var decisionsStopwatch = Stopwatch.StartNew();
            var decisions          = _importDecisionMaker.GetImportDecisions(mediaFileList, artist, filter, true);

            decisionsStopwatch.Stop();
            _logger.Debug("Import decisions complete for: {0} [{1}]", artist, decisionsStopwatch.Elapsed);

            var importStopwatch = Stopwatch.StartNew();

            _importApprovedTracks.Import(decisions, false);

            // decisions may have been filtered to just new files.  Anything new and approved will have been inserted.
            // Now we need to make sure anything new but not approved gets inserted
            // Note that knownFiles will include anything imported just now
            var knownFiles = _mediaFileService.GetFilesWithBasePath(artist.Path);

            var newFiles = decisions
                           .ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance)
                           .Select(decision => new TrackFile {
                Path      = decision.Item.Path,
                Size      = decision.Item.Size,
                Modified  = decision.Item.Modified,
                DateAdded = DateTime.UtcNow,
                Quality   = decision.Item.Quality,
                MediaInfo = decision.Item.FileTrackInfo.MediaInfo
            })
                           .ToList();

            _mediaFileService.AddMany(newFiles);

            _logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles");

            // finally update info on size/modified for existing files
            var updatedFiles = knownFiles
                               .Join(decisions,
                                     x => x.Path,
                                     x => x.Item.Path,
                                     (file, decision) => new {
                File = file,
                Item = decision.Item
            },
                                     PathEqualityComparer.Instance)
                               .Where(x => x.File.Size != x.Item.Size ||
                                      Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1)
                               .Select(x => {
                x.File.Size      = x.Item.Size;
                x.File.Modified  = x.Item.Modified;
                x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo;
                x.File.Quality   = x.Item.Quality;
                return(x.File);
            })
                               .ToList();

            _mediaFileService.Update(updatedFiles);

            _logger.Debug($"Updated info for {updatedFiles.Count} known files");

            RemoveEmptyArtistFolder(artist.Path);

            CompletedScanning(artist);
            importStopwatch.Stop();
            _logger.Debug("Track import complete for: {0} [{1}]", artist, importStopwatch.Elapsed);
        }
Example #10
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 audioFile in _diskScanService.FilterFiles(watchFolder, _diskScanService.GetAudioFiles(watchFolder, false)))
            {
                var title = FileNameBuilder.CleanFileName(audioFile.Name);

                var newWatchItem = new WatchFolderItem
                {
                    DownloadId = audioFile.Name + "_" + audioFile.LastWriteTimeUtc.Ticks,
                    Title      = title,

                    OutputPath = new OsPath(audioFile.FullName),

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

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

                if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
                {
                    newWatchItem.TotalSize = audioFile.Length;
                    newWatchItem.Hash      = GetHash(audioFile.FullName);

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

                    UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod);
                }

                yield return(newWatchItem);
            }
        }
Example #11
0
        public void Scan(Movie movie)
        {
            //Try renaming the movie path in case anything changed such as year, title or something else.
            _renameMovieFiles.RenameMoviePath(movie, true);

            var rootFolder = _diskProvider.GetParentFolder(movie.Path);

            if (!_diskProvider.FolderExists(rootFolder))
            {
                _logger.Warn("Movies' root folder ({0}) doesn't exist.", rootFolder);
                _eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.RootFolderDoesNotExist));
                return;
            }

            if (_diskProvider.GetDirectories(rootFolder).Empty())
            {
                _logger.Warn("Movies' root folder ({0}) is empty.", rootFolder);
                _eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.RootFolderIsEmpty));
                return;
            }

            _logger.ProgressInfo("Scanning disk for {0}", movie.Title);

            if (!_diskProvider.FolderExists(movie.Path))
            {
                if (movie.MovieFileId != 0)
                {
                    //Since there is no folder, there can't be any files right?
                    _mediaFileTableCleanupService.Clean(movie, new List <string>());

                    _logger.Debug("Movies folder doesn't exist: {0}", movie.Path);
                }
                else if (_configService.CreateEmptySeriesFolders &&
                         _diskProvider.FolderExists(rootFolder))
                {
                    _logger.Debug("Creating missing movies folder: {0}", movie.Path);
                    _diskProvider.CreateFolder(movie.Path);
                    SetPermissions(movie.Path);
                }
                else
                {
                    _logger.Debug("Movies folder doesn't exist: {0}", movie.Path);
                }

                _eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.MovieFolderDoesNotExist));
                return;
            }

            var videoFilesStopwatch = Stopwatch.StartNew();
            var mediaFileList       = FilterFiles(movie, GetVideoFiles(movie.Path)).ToList();

            videoFilesStopwatch.Stop();
            _logger.Trace("Finished getting movie files for: {0} [{1}]", movie, videoFilesStopwatch.Elapsed);

            _logger.Debug("{0} Cleaning up media files in DB", movie);
            _mediaFileTableCleanupService.Clean(movie, mediaFileList);

            var decisionsStopwatch = Stopwatch.StartNew();
            var decisions          = _importDecisionMaker.GetImportDecisions(mediaFileList, movie, true);

            decisionsStopwatch.Stop();
            _logger.Trace("Import decisions complete for: {0} [{1}]", movie, decisionsStopwatch.Elapsed);

            _importApprovedMovies.Import(decisions, false);

            _logger.Info("Completed scanning disk for {0}", movie.Title);
            _eventAggregator.PublishEvent(new MovieScannedEvent(movie));
        }