diff --git a/scanner/metadata/taglib.go b/scanner/metadata/taglib.go index e266d768a..796ff2efb 100644 --- a/scanner/metadata/taglib.go +++ b/scanner/metadata/taglib.go @@ -1,9 +1,6 @@ package metadata import ( - "os" - - "github.com/dhowden/tag" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/scanner/metadata/taglib" ) @@ -25,10 +22,6 @@ func (e *taglibExtractor) extractMetadata(filePath string) (*Tags, error) { parsedTags, err := taglib.Read(filePath) if err != nil { log.Warn("Error reading metadata from file. Skipping", "filePath", filePath, err) - } else { - if hasEmbeddedImage(filePath) { - parsedTags["has_picture"] = []string{"true"} - } } tags := NewTags(filePath, parsedTags, map[string][]string{ @@ -41,25 +34,3 @@ func (e *taglibExtractor) extractMetadata(filePath string) (*Tags, error) { return tags, nil } - -func hasEmbeddedImage(path string) bool { - defer func() { - if r := recover(); r != nil { - log.Error("Panic while checking for images. Please report this error with a copy of the file", "path", path, r) - } - }() - f, err := os.Open(path) - if err != nil { - log.Warn("Error opening file", "filePath", path, err) - return false - } - defer f.Close() - - m, err := tag.ReadFrom(f) - if err != nil { - log.Warn("Error reading picture tag from file", "filePath", path, err) - return false - } - - return m.Picture() != nil -} diff --git a/scanner/metadata/taglib/taglib_parser.cpp b/scanner/metadata/taglib/taglib_parser.cpp index e4641f853..e0252eeaf 100644 --- a/scanner/metadata/taglib/taglib_parser.cpp +++ b/scanner/metadata/taglib/taglib_parser.cpp @@ -3,13 +3,20 @@ #include #define TAGLIB_STATIC +#include #include +#include #include +#include #include +#include #include +#include #include "taglib_parser.h" +char has_cover(const TagLib::FileRef f); + int taglib_read(const char *filename, unsigned long id) { TagLib::FileRef f(filename, true, TagLib::AudioProperties::Fast); @@ -54,13 +61,17 @@ int taglib_read(const char *filename, unsigned long id) { if (mp3File->ID3v2Tag()) { const auto &frameListMap(mp3File->ID3v2Tag()->frameListMap()); - for (const auto& kv : frameListMap) { + for (const auto &kv : frameListMap) { if (!kv.second.isEmpty()) tags.insert(kv.first, kv.second.front()->toString()); } } } + if (has_cover(f)) { + go_map_put_str(id, (char *)"has_picture", (char *)"true"); + } + for (TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) { for (TagLib::StringList::ConstIterator j = i->second.begin(); @@ -75,3 +86,45 @@ int taglib_read(const char *filename, unsigned long id) { return 0; } + +char has_cover(const TagLib::FileRef f) { + char hasCover = 0; + // ----- MP3 + if (TagLib::MPEG::File * + mp3File{dynamic_cast(f.file())}) { + if (mp3File->ID3v2Tag()) { + const auto &frameListMap{mp3File->ID3v2Tag()->frameListMap()}; + hasCover = !frameListMap["APIC"].isEmpty(); + } + } + // ----- FLAC + else if (TagLib::FLAC::File * + flacFile{dynamic_cast(f.file())}) { + hasCover = !flacFile->pictureList().isEmpty(); + } + // ----- MP4 + else if (TagLib::MP4::File * + mp4File{dynamic_cast(f.file())}) { + auto &coverItem{mp4File->tag()->itemMap()["covr"]}; + TagLib::MP4::CoverArtList coverArtList{coverItem.toCoverArtList()}; + hasCover = !coverArtList.isEmpty(); + } + // ----- Ogg + else if (TagLib::Ogg::Vorbis::File * + vorbisFile{dynamic_cast(f.file())}) { + hasCover = !vorbisFile->tag()->pictureList().isEmpty(); + } + // ----- Opus + else if (TagLib::Ogg::Opus::File * + opusFile{dynamic_cast(f.file())}) { + hasCover = !opusFile->tag()->pictureList().isEmpty(); + } + // ----- WMA + if (TagLib::ASF::File * + asfFile{dynamic_cast(f.file())}) { + const TagLib::ASF::Tag *tag{asfFile->tag()}; + hasCover = tag && tag->attributeListMap().contains("WM/Picture"); + } + + return hasCover; +}