public override IEnumerable <ExtraFile> ProcessFiles(Author author, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing metadata in {0}", author.Path); var metadataFiles = new List <MetadataFile>(); var filterResult = FilterAndClean(author, filesOnDisk, importedFiles); foreach (var possibleMetadataFile in filterResult.FilesOnDisk) { foreach (var consumer in _consumers) { var metadata = consumer.FindMetadataFile(author, possibleMetadataFile); if (metadata == null) { continue; } if (metadata.Type == MetadataType.BookImage || metadata.Type == MetadataType.BookMetadata) { var localAlbum = _parsingService.GetLocalAlbum(possibleMetadataFile, author); if (localAlbum == null) { _logger.Debug("Extra file folder has multiple Books: {0}", possibleMetadataFile); continue; } metadata.BookId = localAlbum.Id; } if (metadata.Type == MetadataType.BookMetadata) { var localTrack = new LocalBook { FileTrackInfo = Parser.Parser.ParseMusicPath(possibleMetadataFile), Author = author, Path = possibleMetadataFile }; try { _augmentingService.Augment(localTrack, false); } catch (AugmentingFailedException) { _logger.Debug("Unable to parse extra file: {0}", possibleMetadataFile); continue; } if (localTrack.Book == null) { _logger.Debug("Cannot find related book for: {0}", possibleMetadataFile); continue; } } 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, Quality = file.Quality, Series = series, Size = 0 }; if (file.DownloadId.IsNotNullOrWhiteSpace()) { trackedDownload = _trackedDownloadService.Find(file.DownloadId); if (trackedDownload != null) { localEpisode.DownloadClientEpisodeInfo = trackedDownload.RemoteEpisode.ParsedEpisodeInfo; } } if (file.FolderName.IsNotNullOrWhiteSpace()) { localEpisode.FolderEpisodeInfo = Parser.Parser.ParseTitle(file.FolderName); } localEpisode = _augmentingService.Augment(localEpisode, false); // Apply the user-chosen values. localEpisode.Series = series; localEpisode.Episodes = episodes; localEpisode.Quality = file.Quality; //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 }); } } _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.CanMoveFiles) { _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 Tuple <List <LocalBook>, List <ImportDecision <LocalBook> > > GetLocalTracks(List <IFileInfo> musicFiles, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter) { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var files = _mediaFileService.FilterUnchangedFiles(musicFiles, filter); var localTracks = new List <LocalBook>(); var decisions = new List <ImportDecision <LocalBook> >(); _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count); if (!files.Any()) { return(Tuple.Create(localTracks, decisions)); } ParsedBookInfo downloadClientItemInfo = null; if (downloadClientItem != null) { downloadClientItemInfo = Parser.Parser.ParseBookTitle(downloadClientItem.Title); } var i = 1; foreach (var file in files) { _logger.ProgressInfo($"Reading file {i++}/{files.Count}"); var localTrack = new LocalBook { DownloadClientAlbumInfo = downloadClientItemInfo, FolderTrackInfo = folderInfo, Path = file.FullName, Size = file.Length, Modified = file.LastWriteTimeUtc, FileTrackInfo = _eBookTagService.ReadTags(file), AdditionalFile = false }; try { // TODO fix otherfiles? _augmentingService.Augment(localTrack, true); localTracks.Add(localTrack); } catch (AugmentingFailedException) { decisions.Add(new ImportDecision <LocalBook>(localTrack, new Rejection("Unable to parse file"))); } catch (Exception e) { _logger.Error(e, "Couldn't import file. {0}", localTrack.Path); decisions.Add(new ImportDecision <LocalBook>(localTrack, new Rejection("Unexpected error processing file"))); } } _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms"); return(Tuple.Create(localTracks, decisions)); }
public override IEnumerable <ExtraFile> ProcessFiles(Artist artist, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing lyrics files in {0}", artist.Path); var subtitleFiles = new List <LyricFile>(); var filterResult = FilterAndClean(artist, filesOnDisk, importedFiles); foreach (var possibleLyricFile in filterResult.FilesOnDisk) { var extension = Path.GetExtension(possibleLyricFile); if (LyricFileExtensions.Extensions.Contains(extension)) { var localTrack = new LocalTrack { FileTrackInfo = Parser.Parser.ParseMusicPath(possibleLyricFile), Artist = artist, Path = possibleLyricFile }; try { _augmentingService.Augment(localTrack, false); } catch (AugmentingFailedException) { _logger.Debug("Unable to parse lyric file: {0}", possibleLyricFile); continue; } if (localTrack.Tracks.Empty()) { _logger.Debug("Cannot find related tracks for: {0}", possibleLyricFile); continue; } if (localTrack.Tracks.DistinctBy(e => e.TrackFileId).Count() > 1) { _logger.Debug("Lyric file: {0} does not match existing files.", possibleLyricFile); continue; } var subtitleFile = new LyricFile { ArtistId = artist.Id, AlbumId = localTrack.Album.Id, TrackFileId = localTrack.Tracks.First().TrackFileId, RelativePath = artist.Path.GetRelativePath(possibleLyricFile), Extension = extension }; subtitleFiles.Add(subtitleFile); } } _logger.Info("Found {0} existing lyric files", subtitleFiles.Count); _lyricFileService.Upsert(subtitleFiles); // Return files that were just imported along with files that were // previously imported so previously imported files aren't imported twice return(subtitleFiles.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 { _augmentingService.Augment(localEpisode, false); } catch (AugmentingFailedException ex) { _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 override IEnumerable <ExtraFile> ProcessFiles(Artist artist, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing metadata in {0}", artist.Path); var metadataFiles = new List <MetadataFile>(); var filterResult = FilterAndClean(artist, 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 (LyricFileExtensions.Extensions.Contains(Path.GetExtension(possibleMetadataFile))) { continue; } foreach (var consumer in _consumers) { var metadata = consumer.FindMetadataFile(artist, possibleMetadataFile); if (metadata == null) { continue; } if (metadata.Type == MetadataType.AlbumImage || metadata.Type == MetadataType.AlbumMetadata) { var localAlbum = _parsingService.GetLocalAlbum(possibleMetadataFile, artist); if (localAlbum == null) { _logger.Debug("Extra file folder has multiple Albums: {0}", possibleMetadataFile); continue; } metadata.AlbumId = localAlbum.Id; } if (metadata.Type == MetadataType.TrackMetadata) { var localTrack = new LocalTrack { FileTrackInfo = Parser.Parser.ParseMusicPath(possibleMetadataFile), Artist = artist, Path = possibleMetadataFile }; try { _augmentingService.Augment(localTrack, false); } catch (AugmentingFailedException) { _logger.Debug("Unable to parse extra file: {0}", possibleMetadataFile); continue; } if (localTrack.Tracks.Empty()) { _logger.Debug("Cannot find related tracks for: {0}", possibleMetadataFile); continue; } if (localTrack.Tracks.DistinctBy(e => e.TrackFileId).Count() > 1) { _logger.Debug("Extra file: {0} does not match existing files.", possibleMetadataFile); continue; } metadata.TrackFileId = localTrack.Tracks.First().TrackFileId; } 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 List <ImportDecision <LocalTrack> > GetImportDecisions(List <IFileInfo> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter, bool newDownload, bool singleRelease, bool includeExisting) { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var files = filter != FilterFilesType.None && (artist != null) ? _mediaFileService.FilterUnchangedFiles(musicFiles, artist, filter) : musicFiles; var localTracks = new List <LocalTrack>(); var decisions = new List <ImportDecision <LocalTrack> >(); _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count); if (!files.Any()) { return(decisions); } ParsedAlbumInfo downloadClientItemInfo = null; if (downloadClientItem != null) { downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title); } foreach (var file in files) { var localTrack = new LocalTrack { Artist = artist, Album = album, DownloadClientAlbumInfo = downloadClientItemInfo, FolderTrackInfo = folderInfo, Path = file.FullName, Size = file.Length, Modified = file.LastWriteTimeUtc, FileTrackInfo = _audioTagService.ReadTags(file.FullName), ExistingFile = !newDownload, AdditionalFile = false }; try { // TODO fix otherfiles? _augmentingService.Augment(localTrack, true); localTracks.Add(localTrack); } catch (AugmentingFailedException) { decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unable to parse file"))); } catch (Exception e) { _logger.Error(e, "Couldn't import file. {0}", localTrack.Path); decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unexpected error processing file"))); } } _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms"); var releases = _identificationService.Identify(localTracks, artist, album, albumRelease, newDownload, singleRelease, includeExisting); foreach (var release in releases) { release.NewDownload = newDownload; var releaseDecision = GetDecision(release); foreach (var localTrack in release.LocalTracks) { if (releaseDecision.Approved) { decisions.AddIfNotNull(GetDecision(localTrack)); } else { decisions.Add(new ImportDecision <LocalTrack>(localTrack, releaseDecision.Rejections.ToArray())); } } } return(decisions); }
public override IEnumerable <ExtraFile> ProcessFiles(Series series, List <string> filesOnDisk, List <string> importedFiles) { _logger.Debug("Looking for existing subtitle files in {0}", series.Path); var subtitleFiles = new List <SubtitleFile>(); var filterResult = FilterAndClean(series, filesOnDisk, importedFiles); foreach (var possibleSubtitleFile in filterResult.FilesOnDisk) { var extension = Path.GetExtension(possibleSubtitleFile); if (SubtitleFileExtensions.Extensions.Contains(extension)) { var localEpisode = new LocalEpisode { FileEpisodeInfo = Parser.Parser.ParsePath(possibleSubtitleFile), Series = series, Path = possibleSubtitleFile }; try { _augmentingService.Augment(localEpisode, false); } catch (AugmentingFailedException ex) { _logger.Debug("Unable to parse extra file: {0}", possibleSubtitleFile); continue; } if (localEpisode.Episodes.Empty()) { _logger.Debug("Cannot find related episodes for: {0}", possibleSubtitleFile); continue; } if (localEpisode.Episodes.DistinctBy(e => e.EpisodeFileId).Count() > 1) { _logger.Debug("Subtitle file: {0} does not match existing files.", possibleSubtitleFile); continue; } var subtitleFile = new SubtitleFile { SeriesId = series.Id, SeasonNumber = localEpisode.SeasonNumber, EpisodeFileId = localEpisode.Episodes.First().EpisodeFileId, RelativePath = series.Path.GetRelativePath(possibleSubtitleFile), Language = LanguageParser.ParseSubtitleLanguage(possibleSubtitleFile), Extension = extension }; subtitleFiles.Add(subtitleFile); } } _logger.Info("Found {0} existing subtitle files", subtitleFiles.Count); _subtitleFileService.Upsert(subtitleFiles); // Return files that were just imported along with files that were // previously imported so previously imported files aren't imported twice return(subtitleFiles.Concat(filterResult.PreviouslyImported)); }