Use TagLib to detect whether a media file has embedded cover or not
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/dhowden/tag"
|
|
||||||
"github.com/navidrome/navidrome/log"
|
"github.com/navidrome/navidrome/log"
|
||||||
"github.com/navidrome/navidrome/scanner/metadata/taglib"
|
"github.com/navidrome/navidrome/scanner/metadata/taglib"
|
||||||
)
|
)
|
||||||
@@ -25,10 +22,6 @@ func (e *taglibExtractor) extractMetadata(filePath string) (*Tags, error) {
|
|||||||
parsedTags, err := taglib.Read(filePath)
|
parsedTags, err := taglib.Read(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Error reading metadata from file. Skipping", "filePath", filePath, err)
|
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{
|
tags := NewTags(filePath, parsedTags, map[string][]string{
|
||||||
@@ -41,25 +34,3 @@ func (e *taglibExtractor) extractMetadata(filePath string) (*Tags, error) {
|
|||||||
|
|
||||||
return tags, nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,13 +3,20 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#define TAGLIB_STATIC
|
#define TAGLIB_STATIC
|
||||||
|
#include <asffile.h>
|
||||||
#include <fileref.h>
|
#include <fileref.h>
|
||||||
|
#include <flacfile.h>
|
||||||
#include <id3v2tag.h>
|
#include <id3v2tag.h>
|
||||||
|
#include <mp4file.h>
|
||||||
#include <mpegfile.h>
|
#include <mpegfile.h>
|
||||||
|
#include <opusfile.h>
|
||||||
#include <tpropertymap.h>
|
#include <tpropertymap.h>
|
||||||
|
#include <vorbisfile.h>
|
||||||
|
|
||||||
#include "taglib_parser.h"
|
#include "taglib_parser.h"
|
||||||
|
|
||||||
|
char has_cover(const TagLib::FileRef f);
|
||||||
|
|
||||||
int taglib_read(const char *filename, unsigned long id) {
|
int taglib_read(const char *filename, unsigned long id) {
|
||||||
TagLib::FileRef f(filename, true, TagLib::AudioProperties::Fast);
|
TagLib::FileRef f(filename, true, TagLib::AudioProperties::Fast);
|
||||||
|
|
||||||
@@ -61,6 +68,10 @@ int taglib_read(const char *filename, unsigned long id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_cover(f)) {
|
||||||
|
go_map_put_str(id, (char *)"has_picture", (char *)"true");
|
||||||
|
}
|
||||||
|
|
||||||
for (TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end();
|
for (TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end();
|
||||||
++i) {
|
++i) {
|
||||||
for (TagLib::StringList::ConstIterator j = i->second.begin();
|
for (TagLib::StringList::ConstIterator j = i->second.begin();
|
||||||
@@ -75,3 +86,45 @@ int taglib_read(const char *filename, unsigned long id) {
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user