Пример #1
0
        private ParsedTrackInfo ReadPdf(string file)
        {
            _logger.Trace($"Reading {file}");
            var result = new ParsedTrackInfo
            {
                Quality = new QualityModel
                {
                    Quality = Quality.PDF,
                    QualityDetectionSource = QualityDetectionSource.TagLib
                }
            };

            try
            {
                var book = PdfReader.Open(file, PdfDocumentOpenMode.InformationOnly);
                result.AuthorTitle = book.Info.Author;
                result.BookTitle   = book.Info.Title;

                _logger.Trace(book.Info.ToJson());
                _logger.Trace(book.CustomValues.ToJson());
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error reading pdf");
                result.Quality.QualityDetectionSource = QualityDetectionSource.Extension;
            }

            _logger.Trace($"Got:\n{result.ToJson()}");

            return(result);
        }
Пример #2
0
        private static ParsedTrackInfo ParseMatchMusicCollection(MatchCollection matchCollection)
        {
            var authorName = matchCollection[0].Groups["author"].Value./*Removed for cases like Will.I.Am Replace('.', ' ').*/ Replace('_', ' ');

            authorName = RequestInfoRegex.Replace(authorName, "").Trim(' ');

            // Coppied from Radarr (https://github.com/Radarr/Radarr/blob/develop/src/NzbDrone.Core/Parser/Parser.cs)
            // TODO: Split into separate method and write unit tests for.
            var parts = authorName.Split('.');

            authorName = "";
            int    n = 0;
            bool   previousAcronym = false;
            string nextPart        = "";

            foreach (var part in parts)
            {
                if (parts.Length >= n + 2)
                {
                    nextPart = parts[n + 1];
                }

                if (part.Length == 1 && part.ToLower() != "a" && !int.TryParse(part, out n))
                {
                    authorName     += part + ".";
                    previousAcronym = true;
                }
                else if (part.ToLower() == "a" && (previousAcronym == true || nextPart.Length == 1))
                {
                    authorName     += part + ".";
                    previousAcronym = true;
                }
                else
                {
                    if (previousAcronym)
                    {
                        authorName     += " ";
                        previousAcronym = false;
                    }

                    authorName += part + " ";
                }

                n++;
            }

            authorName = authorName.Trim(' ');

            var result = new ParsedTrackInfo();

            result.Authors = new List <string> {
                authorName
            };

            Logger.Debug("Track Parsed. {0}", result);
            return(result);
        }
Пример #3
0
        public static ParsedTrackInfo ParseMusicPath(string path)
        {
            var fileInfo = new FileInfo(path);

            ParsedTrackInfo result = null;

            Logger.Debug("Attempting to parse book info using directory and file names. {0}", fileInfo.Directory.Name);
            result = ParseTitle(fileInfo.Directory.Name + " " + fileInfo.Name);

            if (result == null)
            {
                Logger.Debug("Attempting to parse book info using directory name. {0}", fileInfo.Directory.Name);
                result = ParseTitle(fileInfo.Directory.Name + fileInfo.Extension);
            }

            return(result);
        }
Пример #4
0
        private ParsedTrackInfo ReadEpub(string file)
        {
            _logger.Trace($"Reading {file}");
            var result = new ParsedTrackInfo
            {
                Quality = new QualityModel
                {
                    Quality = Quality.EPUB,
                    QualityDetectionSource = QualityDetectionSource.TagLib
                }
            };

            try
            {
                using (var bookRef = EpubReader.OpenBook(file))
                {
                    result.AuthorTitle = bookRef.AuthorList.FirstOrDefault();
                    result.BookTitle   = bookRef.Title;

                    var meta = bookRef.Schema.Package.Metadata;

                    _logger.Trace(meta.ToJson());

                    result.Isbn           = GetIsbn(meta?.Identifiers);
                    result.Asin           = meta?.Identifiers?.FirstOrDefault(x => x.Scheme?.ToLower().Contains("asin") ?? false)?.Identifier;
                    result.Language       = meta?.Languages?.FirstOrDefault();
                    result.Publisher      = meta?.Publishers?.FirstOrDefault();
                    result.Disambiguation = meta?.Description;

                    result.SeriesTitle = meta?.MetaItems?.FirstOrDefault(x => x.Name == "calibre:series")?.Content;
                    result.SeriesIndex = meta?.MetaItems?.FirstOrDefault(x => x.Name == "calibre:series_index")?.Content;
                }
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error reading epub");
                result.Quality.QualityDetectionSource = QualityDetectionSource.Extension;
            }

            _logger.Trace($"Got:\n{result.ToJson()}");

            return(result);
        }
Пример #5
0
        private ParsedTrackInfo ReadAzw3(string file)
        {
            _logger.Trace($"Reading {file}");
            var result = new ParsedTrackInfo();

            try
            {
                var book = new Azw3File(file);
                result.AuthorTitle    = book.Author;
                result.BookTitle      = book.Title;
                result.Isbn           = StripIsbn(book.Isbn);
                result.Asin           = book.Asin;
                result.Language       = book.Language;
                result.Disambiguation = book.Description;
                result.Publisher      = book.Publisher;
                result.Label          = book.Imprint;
                result.Source         = book.Source;

                result.Quality = new QualityModel
                {
                    Quality = book.Version <= 6 ? Quality.MOBI : Quality.AZW3,
                    QualityDetectionSource = QualityDetectionSource.TagLib
                };
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error reading file");

                result.Quality = new QualityModel
                {
                    Quality = Path.GetExtension(file) == ".mobi" ? Quality.MOBI : Quality.AZW3,
                    QualityDetectionSource = QualityDetectionSource.Extension
                };
            }

            _logger.Trace($"Got {result.ToJson()}");

            return(result);
        }
        private List <ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, Author author, DownloadClientItem downloadClientItem)
        {
            if (_authorService.AuthorPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing author");
                return(new List <ImportResult>());
            }

            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var folderInfo    = Parser.Parser.ParseBookTitle(directoryInfo.Name);
            var trackInfo     = new ParsedTrackInfo {
            };

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

                trackInfo = new ParsedTrackInfo
                {
                    AlbumTitle   = folderInfo.BookTitle,
                    ArtistTitle  = folderInfo.AuthorName,
                    Quality      = folderInfo.Quality,
                    ReleaseGroup = folderInfo.ReleaseGroup,
                    ReleaseHash  = folderInfo.ReleaseHash,
                };
            }
            else
            {
                trackInfo = null;
            }

            var audioFiles = _diskScanService.FilterFiles(directoryInfo.FullName, _diskScanService.GetBookFiles(directoryInfo.FullName));

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

            var idOverrides = new IdentificationOverrides
            {
                Author = author
            };
            var idInfo = new ImportDecisionMakerInfo
            {
                DownloadClientItem = downloadClientItem,
                ParsedTrackInfo    = trackInfo
            };
            var idConfig = new ImportDecisionMakerConfig
            {
                Filter          = FilterFilesType.None,
                NewDownload     = true,
                SingleRelease   = false,
                IncludeExisting = false,
                AddNewAuthors   = false
            };

            var decisions     = _importDecisionMaker.GetImportDecisions(audioFiles, idOverrides, idInfo, idConfig);
            var importResults = _importApprovedTracks.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, author))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
Пример #7
0
        public Tuple <List <LocalTrack>, List <ImportDecision <LocalTrack> > > 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 <LocalTrack>();
            var decisions   = new List <ImportDecision <LocalTrack> >();

            _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count);

            if (!files.Any())
            {
                return(Tuple.Create(localTracks, decisions));
            }

            ParsedAlbumInfo downloadClientItemInfo = null;

            if (downloadClientItem != null)
            {
                downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title);
            }

            int i = 1;

            foreach (var file in files)
            {
                _logger.ProgressInfo($"Reading file {i++}/{files.Count}");

                var localTrack = new LocalTrack
                {
                    DownloadClientAlbumInfo = downloadClientItemInfo,
                    FolderTrackInfo         = folderInfo,
                    Path           = file.FullName,
                    Size           = file.Length,
                    Modified       = file.LastWriteTimeUtc,
                    FileTrackInfo  = _audioTagService.ReadTags(file.FullName),
                    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");

            return(Tuple.Create(localTracks, decisions));
        }
Пример #8
0
        private List <ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, Artist artist, DownloadClientItem downloadClientItem)
        {
            if (_artistService.ArtistPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing artist");
                return(new List <ImportResult>());
            }

            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var folderInfo    = Parser.Parser.ParseAlbumTitle(directoryInfo.Name);
            var trackInfo     = new ParsedTrackInfo {
            };

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

                trackInfo = new ParsedTrackInfo
                {
                    AlbumTitle   = folderInfo.AlbumTitle,
                    ArtistTitle  = folderInfo.ArtistName,
                    Quality      = folderInfo.Quality,
                    ReleaseGroup = folderInfo.ReleaseGroup,
                    ReleaseHash  = folderInfo.ReleaseHash,
                };
            }
            else
            {
                trackInfo = null;
            }

            var audioFiles = _diskScanService.FilterFiles(directoryInfo.FullName, _diskScanService.GetAudioFiles(directoryInfo.FullName));

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

            var decisions     = _importDecisionMaker.GetImportDecisions(audioFiles, artist, trackInfo);
            var importResults = _importApprovedTracks.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, artist))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
Пример #9
0
        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);
        }
Пример #10
0
 public List <ImportDecision <LocalTrack> > GetImportDecisions(List <IFileInfo> musicFiles, Artist artist, ParsedTrackInfo folderInfo)
 {
     return(GetImportDecisions(musicFiles, artist, null, null, null, folderInfo, FilterFilesType.None, true, false, false));
 }