diff --git a/src/plugins/taglib_plugin/TaglibMetadataReader.cpp b/src/plugins/taglib_plugin/TaglibMetadataReader.cpp index c2bb208e1..bb4d438a4 100644 --- a/src/plugins/taglib_plugin/TaglibMetadataReader.cpp +++ b/src/plugins/taglib_plugin/TaglibMetadataReader.cpp @@ -52,6 +52,7 @@ #include #include #include + #include #include #include #include @@ -71,6 +72,7 @@ #include #include #include + #include #include #include #include @@ -83,6 +85,7 @@ #include #include #include +#include #ifdef WIN32 #define FFMPEG_DECODER @@ -131,6 +134,37 @@ static inline std::wstring utf8to16(const char* utf8) { } #endif +static TagLib::FileRef resolveOggType(const char* uri) { + try { + #ifdef WIN32 + FILE* file = _wfopen(utf8to16(uri).c_str(), L"rb"); + #else + FILE* file = fopen(uri, "rb"); + #endif + if (file) { + static const char OGG_OPUS_HEADER[8] = {'O','p','u','s','H','e','a','d'}; + + char buffer[512]; + size_t read = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + + if (read == sizeof(buffer)) { + auto it = std::search( + std::begin(buffer), std::end(buffer), + std::begin(OGG_OPUS_HEADER), std::end(OGG_OPUS_HEADER)); + + if (it != std::end(buffer)) { + return TagLib::FileRef(new TagLib::Ogg::Opus::File(uri)); + } + } + } + } + catch (...) { + /* ugh. yay. */ + } + return TagLib::FileRef(); +} + static bool isValidYear(const std::string& year) { return std::stoi(year) > 0; } @@ -206,13 +240,16 @@ bool TaglibMetadataReader::Read(const char* uri, ITagStore *track) { extension = path.substr(lastDot + 1).c_str(); } + /* first, process everything except ID3v2. this logic applies + to everything except ID3v2 (including ID3v1) */ try { - this->ReadGeneric(uri, track); + this->ReadGeneric(uri, extension, track); } catch (...) { std::cerr << "generic tag read for " << uri << "failed!"; } + /* ID3v2 is a trainwreck, so it requires special processing */ if (extension.size()) { if (str::lower(extension) == "mp3") { try { @@ -227,13 +264,22 @@ bool TaglibMetadataReader::Read(const char* uri, ITagStore *track) { return true; } -bool TaglibMetadataReader::ReadGeneric(const char* uri, ITagStore *target) { +bool TaglibMetadataReader::ReadGeneric( + const char* uri, const std::string& extension, ITagStore *target) +{ #ifdef WIN32 TagLib::FileRef file(utf8to16(uri).c_str()); #else TagLib::FileRef file(uri); #endif + /* ogg is a container format, but taglib sees the extension and + assumes it's a vorbis file. in this case, we'll read the header + and try to guess the filetype */ + if (file.isNull() && extension == "ogg") { + file = resolveOggType(uri); + } + if (file.isNull()) { this->SetTagValue("title", uri, target); } diff --git a/src/plugins/taglib_plugin/TaglibMetadataReader.h b/src/plugins/taglib_plugin/TaglibMetadataReader.h index b85cc56a2..64b9668ae 100644 --- a/src/plugins/taglib_plugin/TaglibMetadataReader.h +++ b/src/plugins/taglib_plugin/TaglibMetadataReader.h @@ -133,5 +133,6 @@ class TaglibMetadataReader : public musik::core::sdk::ITagReader { bool ReadGeneric( const char* uri, + const std::string& extension, musik::core::sdk::ITagStore *target); };