diff --git a/conf/lms.conf b/conf/lms.conf index ca7dae59..5729eaa9 100644 --- a/conf/lms.conf +++ b/conf/lms.conf @@ -80,3 +80,6 @@ cover-preferred-file-names = ("cover", "front" ); # Set to true if you want to hide duplicate tracks scanner-skip-duplicate-recording-mbid = false; + +# Scanner read style for metadata, maybe be 'fast', 'average' or 'accurate' +scanner-parser-read-style = "accurate"; diff --git a/src/libs/metadata/CMakeLists.txt b/src/libs/metadata/CMakeLists.txt index 90b6fd92..b2502aa3 100644 --- a/src/libs/metadata/CMakeLists.txt +++ b/src/libs/metadata/CMakeLists.txt @@ -5,6 +5,7 @@ endif() add_library(lmsmetadata SHARED impl/AvFormatParser.cpp + impl/Factory.cpp impl/TagLibParser.cpp impl/Utils.cpp ) diff --git a/src/libs/metadata/impl/AvFormatParser.cpp b/src/libs/metadata/impl/AvFormatParser.cpp index e5a472dd..1284ffb7 100644 --- a/src/libs/metadata/impl/AvFormatParser.cpp +++ b/src/libs/metadata/impl/AvFormatParser.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "metadata/AvFormatParser.hpp" +#include "AvFormatParser.hpp" #include #include diff --git a/src/libs/metadata/include/metadata/AvFormatParser.hpp b/src/libs/metadata/impl/AvFormatParser.hpp similarity index 100% rename from src/libs/metadata/include/metadata/AvFormatParser.hpp rename to src/libs/metadata/impl/AvFormatParser.hpp diff --git a/src/libs/metadata/impl/Factory.cpp b/src/libs/metadata/impl/Factory.cpp new file mode 100644 index 00000000..3325693e --- /dev/null +++ b/src/libs/metadata/impl/Factory.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 Emeric Poupon + * + * This file is part of LMS. + * + * LMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LMS. If not, see . + */ + +#include "metadata/IParser.hpp" + +#include "utils/Exception.hpp" +#include "utils/Logger.hpp" + +#include "AvFormatParser.hpp" +#include "TagLibParser.hpp" +#include "Utils.hpp" + +namespace MetaData +{ + std::unique_ptr + createParser(ParserType parserType, ParserReadStyle parserReadStyle) + { + + switch (parserType) + { + case ParserType::TagLib: + LMS_LOG(METADATA, INFO) << "Creating TagLib parser with read style = " << Utils::readStyleToString(parserReadStyle); + return std::make_unique(parserReadStyle); + case ParserType::AvFormat: + LMS_LOG(METADATA, INFO) << "Creating AvFormat parser"; + return std::make_unique(); + } + + throw LmsException {"Unhandled parser type"}; + } +} + diff --git a/src/libs/metadata/impl/TagLibParser.cpp b/src/libs/metadata/impl/TagLibParser.cpp index cad5f258..d5c9ba6c 100644 --- a/src/libs/metadata/impl/TagLibParser.cpp +++ b/src/libs/metadata/impl/TagLibParser.cpp @@ -17,7 +17,7 @@ * along with LMS. If not, see . */ -#include "metadata/TagLibParser.hpp" +#include "TagLibParser.hpp" #include #include @@ -33,7 +33,10 @@ #include #include +#include "utils/IConfig.hpp" +#include "utils/Exception.hpp" #include "utils/Logger.hpp" +#include "utils/Service.hpp" #include "utils/String.hpp" #include "Utils.hpp" @@ -145,6 +148,26 @@ getAlbum(const TagLib::PropertyMap& properties) return Album {std::move(albumName.front()), albumMBID.front()}; } +static +TagLib::AudioProperties::ReadStyle +readStyleToTagLibReadStyle(ParserReadStyle readStyle) +{ + switch (readStyle) + { + case ParserReadStyle::Fast: return TagLib::AudioProperties::ReadStyle::Fast; + case ParserReadStyle::Average: return TagLib::AudioProperties::ReadStyle::Average; + case ParserReadStyle::Accurate: return TagLib::AudioProperties::ReadStyle::Accurate; + } + + throw LmsException {"Cannot convert read style"}; +} + + +TagLibParser::TagLibParser(ParserReadStyle readStyle) + : _readStyle {readStyleToTagLibReadStyle(readStyle)} +{ +} + void TagLibParser::processTag(Track& track, const std::string& tag, const TagLib::StringList& values, bool debug) { @@ -267,7 +290,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug) { TagLib::FileRef f {p.string().c_str(), true, // read audio properties - TagLib::AudioProperties::Fast}; // TODO parametrize this + _readStyle}; if (f.isNull()) { diff --git a/src/libs/metadata/include/metadata/TagLibParser.hpp b/src/libs/metadata/impl/TagLibParser.hpp similarity index 88% rename from src/libs/metadata/include/metadata/TagLibParser.hpp rename to src/libs/metadata/impl/TagLibParser.hpp index ee298f8d..8990fd1c 100644 --- a/src/libs/metadata/include/metadata/TagLibParser.hpp +++ b/src/libs/metadata/impl/TagLibParser.hpp @@ -19,6 +19,7 @@ #pragma once +#include #include "metadata/IParser.hpp" namespace TagLib @@ -32,10 +33,14 @@ namespace MetaData // Parse that makes use of AvFormat class TagLibParser : public IParser { + public: + TagLibParser(ParserReadStyle readStyle); + private: std::optional parse(const std::filesystem::path& p, bool debug = false) override; - void processTag(Track& track, const std::string& tag, const TagLib::StringList& values, bool debug); + + const TagLib::AudioProperties::ReadStyle _readStyle; }; } // namespace MetaData diff --git a/src/libs/metadata/impl/Utils.cpp b/src/libs/metadata/impl/Utils.cpp index 090db19c..7919ca8a 100644 --- a/src/libs/metadata/impl/Utils.cpp +++ b/src/libs/metadata/impl/Utils.cpp @@ -23,6 +23,8 @@ #include #include +#include "utils/Exception.hpp" + namespace MetaData::Utils { Wt::WDate @@ -56,5 +58,18 @@ namespace MetaData::Utils return {}; } + + std::string_view + readStyleToString(ParserReadStyle readStyle) + { + switch (readStyle) + { + case ParserReadStyle::Fast: return "fast"; + case ParserReadStyle::Average: return "average"; + case ParserReadStyle::Accurate: return "accurate"; + } + + throw LmsException {"Unknown read style"}; + } } diff --git a/src/libs/metadata/impl/Utils.hpp b/src/libs/metadata/impl/Utils.hpp index 30025627..0bbd4485 100644 --- a/src/libs/metadata/impl/Utils.hpp +++ b/src/libs/metadata/impl/Utils.hpp @@ -20,8 +20,11 @@ #include +#include "metadata/IParser.hpp" + namespace MetaData::Utils { Wt::WDate parseDate(const std::string& dateStr); + std::string_view readStyleToString(ParserReadStyle readStyle); } diff --git a/src/libs/metadata/include/metadata/IParser.hpp b/src/libs/metadata/include/metadata/IParser.hpp index 18db7f1d..b4555d31 100644 --- a/src/libs/metadata/include/metadata/IParser.hpp +++ b/src/libs/metadata/include/metadata/IParser.hpp @@ -100,5 +100,18 @@ namespace MetaData std::set _clusterTypeNames; }; + enum class ParserType + { + TagLib, + AvFormat, + }; + + enum class ParserReadStyle + { + Fast, + Average, + Accurate, + }; + std::unique_ptr createParser(ParserType parserType, ParserReadStyle parserReadStyle); } // namespace MetaData diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index c970b9d2..dea3c796 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -31,7 +31,7 @@ #include "services/database/Track.hpp" #include "services/database/TrackArtistLink.hpp" #include "services/database/TrackFeatures.hpp" -#include "metadata/TagLibParser.hpp" +#include "metadata/IParser.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "utils/Exception.hpp" #include "utils/IConfig.hpp" @@ -255,16 +255,29 @@ createScannerService(Db& db, Recommendation::IRecommendationService& recommendat return std::make_unique(db, recommendationService); } +MetaData::ParserReadStyle +getParserReadStyle() +{ + std::string_view readStyle {Service::get()->getString("scanner-parser-read-style", "accurate")}; + + if (readStyle == "fast") + return MetaData::ParserReadStyle::Fast; + else if (readStyle == "average") + return MetaData::ParserReadStyle::Average; + else if (readStyle == "accurate") + return MetaData::ParserReadStyle::Accurate; + + throw LmsException {"Invalid value for 'scanner-parser-read-style'"}; +} + ScannerService::ScannerService(Db& db, Recommendation::IRecommendationService& recommendationService) : _recommendationService {recommendationService} , _skipDuplicateRecordingMBID {Service::get()->getBool("scanner-skip-duplicate-recording-mbid", false)} , _dbSession {db} +, _metadataParser {MetaData::createParser(MetaData::ParserType::TagLib, getParserReadStyle())} // For now, always use TagLib { LMS_LOG(DBUPDATER, INFO) << "skipDuplicateRecordingMBID = " << _skipDuplicateRecordingMBID; - // For now, always use TagLib - _metadataParser = std::make_unique(); - _ioService.setThreadCount(1); refreshScanSettings(); diff --git a/src/tools/metadata/LmsMetadata.cpp b/src/tools/metadata/LmsMetadata.cpp index 3d674da9..bfeea1e3 100644 --- a/src/tools/metadata/LmsMetadata.cpp +++ b/src/tools/metadata/LmsMetadata.cpp @@ -25,8 +25,7 @@ #include -#include "metadata/AvFormatParser.hpp" -#include "metadata/TagLibParser.hpp" +#include "metadata/IParser.hpp" #include "utils/StreamLogger.hpp" std::ostream& operator<<(std::ostream& os, const MetaData::Artist& artist) @@ -184,14 +183,14 @@ int main(int argc, char *argv[]) { std::cout << "Using av:" << std::endl; - MetaData::AvFormatParser parser; - parse(parser, file); + auto parser {MetaData::createParser(MetaData::ParserType::AvFormat, MetaData::ParserReadStyle::Accurate)}; + parse(*parser, file); } { std::cout << "Using TagLib:" << std::endl; - MetaData::TagLibParser parser; - parse(parser, file); + auto parser {MetaData::createParser(MetaData::ParserType::TagLib, MetaData::ParserReadStyle::Accurate)}; + parse(*parser, file); } } }