Use TagLib to detect whether a media file has embedded cover or not

This commit is contained in:
Deluan 2021-07-24 01:36:04 -04:00
parent 91325071a6
commit 6c550819fd
2 changed files with 54 additions and 30 deletions

View File

@ -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
}

View File

@ -3,13 +3,20 @@
#include <typeinfo>
#define TAGLIB_STATIC
#include <asffile.h>
#include <fileref.h>
#include <flacfile.h>
#include <id3v2tag.h>
#include <mp4file.h>
#include <mpegfile.h>
#include <opusfile.h>
#include <tpropertymap.h>
#include <vorbisfile.h>
#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<TagLib::MPEG::File *>(f.file())}) {
if (mp3File->ID3v2Tag()) {
const auto &frameListMap{mp3File->ID3v2Tag()->frameListMap()};
hasCover = !frameListMap["APIC"].isEmpty();
}
}
// ----- FLAC
else if (TagLib::FLAC::File *
flacFile{dynamic_cast<TagLib::FLAC::File *>(f.file())}) {
hasCover = !flacFile->pictureList().isEmpty();
}
// ----- MP4
else if (TagLib::MP4::File *
mp4File{dynamic_cast<TagLib::MP4::File *>(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<TagLib::Ogg::Vorbis::File *>(f.file())}) {
hasCover = !vorbisFile->tag()->pictureList().isEmpty();
}
// ----- Opus
else if (TagLib::Ogg::Opus::File *
opusFile{dynamic_cast<TagLib::Ogg::Opus::File *>(f.file())}) {
hasCover = !opusFile->tag()->pictureList().isEmpty();
}
// ----- WMA
if (TagLib::ASF::File *
asfFile{dynamic_cast<TagLib::ASF::File *>(f.file())}) {
const TagLib::ASF::Tag *tag{asfFile->tag()};
hasCover = tag && tag->attributeListMap().contains("WM/Picture");
}
return hasCover;
}