diff --git a/src/libs/metadata/impl/AudioFileParser.cpp b/src/libs/metadata/impl/AudioFileParser.cpp index 54eaf31e..b0549595 100644 --- a/src/libs/metadata/impl/AudioFileParser.cpp +++ b/src/libs/metadata/impl/AudioFileParser.cpp @@ -151,15 +151,14 @@ namespace lms::metadata std::initializer_list artistTagNames, std::initializer_list artistSortTagNames, std::initializer_list artistMBIDTagNames, - std::span artistTagDelimiters, - std::span defaultTagDelimiters) + const AudioFileParserParameters& params) { - std::vector artistNames{ getTagValuesFirstMatchAs(tagReader, artistTagNames, artistTagDelimiters) }; + std::vector artistNames{ getTagValuesFirstMatchAs(tagReader, artistTagNames, params.artistTagDelimiters) }; if (artistNames.empty()) return {}; - std::vector artistSortNames{ getTagValuesFirstMatchAs(tagReader, artistSortTagNames, artistTagDelimiters) }; - std::vector artistMBIDs{ getTagValuesFirstMatchAs(tagReader, artistMBIDTagNames, defaultTagDelimiters) }; + std::vector artistSortNames{ getTagValuesFirstMatchAs(tagReader, artistSortTagNames, params.artistTagDelimiters) }; + std::vector artistMBIDs{ getTagValuesFirstMatchAs(tagReader, artistMBIDTagNames, params.defaultTagDelimiters) }; std::vector artists; artists.reserve(artistNames.size()); @@ -224,7 +223,7 @@ namespace lms::metadata return std::any_of(std::cbegin(subStrs), std::cend(subStrs), [&str](const std::string& subStr) { return str.find(subStr) != std::string_view::npos; }); } - std::string computeArtistDisplayName(std::span artists, const std::optional artistTag, std::span artistTagDelimiters) + std::string computeArtistDisplayName(std::span artists, const std::optional& artistTag, std::span artistTagDelimiters) { std::string artistDisplayName; @@ -479,15 +478,15 @@ namespace lms::metadata std::vector artistDelimiters{}; track.medium = getMedium(tagReader); - track.artists = getArtists(tagReader, { TagType::Artists, TagType::Artist }, { TagType::ArtistSortOrder }, { TagType::MusicBrainzArtistID }, _params.artistTagDelimiters, _params.defaultTagDelimiters); + track.artists = getArtists(tagReader, { TagType::Artists, TagType::Artist }, { TagType::ArtistSortOrder }, { TagType::MusicBrainzArtistID }, _params); track.artistDisplayName = computeArtistDisplayName(track.artists, getTagValueAs(tagReader, TagType::Artist), _params.artistTagDelimiters); - track.conductorArtists = getArtists(tagReader, { TagType::Conductors, TagType::Conductor }, { TagType::ConductorsSortOrder, TagType::ConductorSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); - track.composerArtists = getArtists(tagReader, { TagType::Composers, TagType::Composer }, { TagType::ComposersSortOrder, TagType::ComposerSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); - track.lyricistArtists = getArtists(tagReader, { TagType::Lyricists, TagType::Lyricist }, { TagType::LyricistsSortOrder, TagType::LyricistSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); - track.mixerArtists = getArtists(tagReader, { TagType::Mixers, TagType::Mixer }, { TagType::MixersSortOrder, TagType::MixerSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); - track.producerArtists = getArtists(tagReader, { TagType::Producers, TagType::Producer }, { TagType::ProducersSortOrder, TagType::ProducerSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); - track.remixerArtists = getArtists(tagReader, { TagType::Remixers, TagType::Remixer }, { TagType::RemixersSortOrder, TagType::RemixerSortOrder }, {}, _params.artistTagDelimiters, _params.defaultTagDelimiters); + track.conductorArtists = getArtists(tagReader, { TagType::Conductors, TagType::Conductor }, { TagType::ConductorsSortOrder, TagType::ConductorSortOrder }, {}, _params); + track.composerArtists = getArtists(tagReader, { TagType::Composers, TagType::Composer }, { TagType::ComposersSortOrder, TagType::ComposerSortOrder }, {}, _params); + track.lyricistArtists = getArtists(tagReader, { TagType::Lyricists, TagType::Lyricist }, { TagType::LyricistsSortOrder, TagType::LyricistSortOrder }, {}, _params); + track.mixerArtists = getArtists(tagReader, { TagType::Mixers, TagType::Mixer }, { TagType::MixersSortOrder, TagType::MixerSortOrder }, {}, _params); + track.producerArtists = getArtists(tagReader, { TagType::Producers, TagType::Producer }, { TagType::ProducersSortOrder, TagType::ProducerSortOrder }, {}, _params); + track.remixerArtists = getArtists(tagReader, { TagType::Remixers, TagType::Remixer }, { TagType::RemixersSortOrder, TagType::RemixerSortOrder }, {}, _params); track.performerArtists = getPerformerArtists(tagReader); // artistDelimiters not supported fillMissingMbids(track); @@ -538,7 +537,7 @@ namespace lms::metadata release.emplace(); release->name = std::move(*releaseName); release->sortName = getTagValueAs(tagReader, TagType::AlbumSortOrder).value_or(release->name); - release->artists = getArtists(tagReader, { TagType::AlbumArtists, TagType::AlbumArtist }, { TagType::AlbumArtistsSortOrder, TagType::AlbumArtistSortOrder }, { TagType::MusicBrainzReleaseArtistID }, _params.artistTagDelimiters, _params.defaultTagDelimiters); + release->artists = getArtists(tagReader, { TagType::AlbumArtists, TagType::AlbumArtist }, { TagType::AlbumArtistsSortOrder, TagType::AlbumArtistSortOrder }, { TagType::MusicBrainzReleaseArtistID }, _params); release->artistDisplayName = computeArtistDisplayName(release->artists, getTagValueAs(tagReader, TagType::AlbumArtist), _params.artistTagDelimiters); release->mbid = getTagValueAs(tagReader, TagType::MusicBrainzReleaseID); release->groupMBID = getTagValueAs(tagReader, TagType::MusicBrainzReleaseGroupID); diff --git a/src/libs/metadata/impl/AudioFileParser.hpp b/src/libs/metadata/impl/AudioFileParser.hpp index 7c8e1376..e7f8edf5 100644 --- a/src/libs/metadata/impl/AudioFileParser.hpp +++ b/src/libs/metadata/impl/AudioFileParser.hpp @@ -31,7 +31,7 @@ namespace lms::metadata class AudioFileParser : public IAudioFileParser { public: - AudioFileParser(const AudioFileParserParameters& parameters = {}); + AudioFileParser(const AudioFileParserParameters& params = {}); ~AudioFileParser() override = default; AudioFileParser(const AudioFileParser&) = delete; AudioFileParser& operator=(const AudioFileParser&) = delete; @@ -39,7 +39,7 @@ namespace lms::metadata protected: std::unique_ptr parseMetaData(const std::filesystem::path& p) override; std::unique_ptr parseMetaData(const ITagReader& reader); - void parseImages(const IImageReader& reader, ImageVisitor visitor); + static void parseImages(const IImageReader& reader, ImageVisitor visitor); private: void parseImages(const std::filesystem::path& p, ImageVisitor visitor) override; diff --git a/src/libs/metadata/include/metadata/IAudioFileParser.hpp b/src/libs/metadata/include/metadata/IAudioFileParser.hpp index f95d84b5..0d375556 100644 --- a/src/libs/metadata/include/metadata/IAudioFileParser.hpp +++ b/src/libs/metadata/include/metadata/IAudioFileParser.hpp @@ -41,5 +41,5 @@ namespace lms::metadata virtual std::span getSupportedExtensions() const = 0; }; - std::unique_ptr createAudioFileParser(const AudioFileParserParameters& parameters); + std::unique_ptr createAudioFileParser(const AudioFileParserParameters& params); } // namespace lms::metadata diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index 18d34bd0..8405d9ca 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -83,71 +83,81 @@ namespace lms::scanner return image; } + db::Image::pointer getImageFromMbid(SearchImageContext& searchContext, const core::UUID& mbid) + { + db::Image::pointer image; + + // Find anywhere, since it is supposed to be unique! + db::Image::find(searchContext.session, db::Image::FindParameters{}.setFileStem(mbid.getAsString()), [&](const db::Image::pointer foundImg) { + if (!image) + image = foundImg; + }); + + return image; + } + + db::Image::pointer searchImageInDirectories(SearchImageContext& searchContext, db::ArtistId artistId) + { + db::Image::pointer image; + + std::set releasePaths; + db::Directory::FindParameters params; + params.setArtist(artistId, { db::TrackArtistLinkType::ReleaseArtist }); + + db::Directory::find(searchContext.session, params, [&](const db::Directory::pointer& directory) { + releasePaths.insert(directory->getAbsolutePath()); + }); + + if (!releasePaths.empty()) + { + // Expect layout like this: + // ReleaseArtist/Release/Tracks' + // /artist.jpg + // /someOtherUserConfiguredArtistFile.jpg + // + // Or: + // ReleaseArtist/SomeGrouping/Release/Tracks' + // /artist.jpg + // /someOtherUserConfiguredArtistFile.jpg + // + std::filesystem::path directoryToInspect{ core::pathUtils::getLongestCommonPath(std::cbegin(releasePaths), std::cend(releasePaths)) }; + while (true) + { + image = findImageInDirectory(searchContext, directoryToInspect); + if (image) + return image; + + std::filesystem::path parentPath{ directoryToInspect.parent_path() }; + if (parentPath == directoryToInspect) + break; + + directoryToInspect = parentPath; + } + + // Expect layout like this: + // ReleaseArtist/Release/Tracks' + // /artist.jpg + // /someOtherUserConfiguredArtistFile.jpg + for (const std::filesystem::path& releasePath : releasePaths) + { + image = findImageInDirectory(searchContext, releasePath); + if (image) + return image; + } + } + + return image; + } + db::Image::pointer computeBestArtistImage(SearchImageContext& searchContext, const db::Artist::pointer& artist) { db::Image::pointer image; - const auto mbid{ artist->getMBID() }; - if (mbid) - { - // Find anywhere, since it is suppoed to be unique! - db::Image::find(searchContext.session, db::Image::FindParameters{}.setFileStem(mbid->getAsString()), [&](const db::Image::pointer foundImg) { - if (!image) - image = foundImg; - }); - } + if (const auto mbid{ artist->getMBID() }) + image = getImageFromMbid(searchContext, *mbid); if (!image) - { - std::set releasePaths; - db::Directory::FindParameters params; - params.setArtist(artist->getId(), { db::TrackArtistLinkType::ReleaseArtist }); - - db::Directory::find(searchContext.session, params, [&](const db::Directory::pointer& directory) { - releasePaths.insert(directory->getAbsolutePath()); - }); - - if (!releasePaths.empty()) - { - // Expect layout like this: - // ReleaseArtist/Release/Tracks' - // /artist.jpg - // /someOtherUserConfiguredArtistFile.jpg - // - // Or: - // ReleaseArtist/SomeGrouping/Release/Tracks' - // /artist.jpg - // /someOtherUserConfiguredArtistFile.jpg - // - std::filesystem::path directoryToInspect{ core::pathUtils::getLongestCommonPath(std::cbegin(releasePaths), std::cend(releasePaths)) }; - while (true) - { - image = findImageInDirectory(searchContext, directoryToInspect); - if (image) - break; - - std::filesystem::path parentPath{ directoryToInspect.parent_path() }; - if (parentPath == directoryToInspect) - break; - - directoryToInspect = parentPath; - } - - if (!image) - { - // Expect layout like this: - // ReleaseArtist/Release/Tracks' - // /artist.jpg - // /someOtherUserConfiguredArtistFile.jpg - for (const std::filesystem::path& releasePath : releasePaths) - { - image = findImageInDirectory(searchContext, releasePath); - if (image) - break; - } - } - } - } + image = searchImageInDirectories(searchContext, artist->getId()); return image; }