From 9c27eec846dad65f60875792b80bc66a0c8abc76 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Tue, 3 Sep 2024 03:15:09 +0200 Subject: [PATCH] Add support for fetching lyrics from tags Adaptation of https://github.com/ncmpcpp/ncmpcpp/pull/482. --- CHANGELOG.md | 1 + doc/config | 2 +- src/configuration.cpp | 2 +- src/lyrics_fetcher.cpp | 66 +++++++++++++++++++++++++++++++++++++----- src/lyrics_fetcher.h | 20 +++++++++++-- src/screens/lyrics.cpp | 2 +- src/settings.cpp | 3 ++ 7 files changed, 83 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c8884d1..456eee0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * Add `visualizer_spectrum_smooth_look_legacy_chars` option (enabled by default) for potentially improved bottom part of the spectrum visualizer in terminals with transparent background. +* Add support for fetching lyrics from tags. # ncmpcpp-0.9.2 (2021-01-24) * Revert suppression of output of all external commands as that makes e.g album diff --git a/doc/config b/doc/config index cc6d2913..791f2084 100644 --- a/doc/config +++ b/doc/config @@ -422,7 +422,7 @@ # #cyclic_scrolling = no # -#lyrics_fetchers = genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet +#lyrics_fetchers = tags, genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet # #follow_now_playing_lyrics = no # diff --git a/src/configuration.cpp b/src/configuration.cpp index c1e26913..455bce5e 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -171,7 +171,7 @@ bool configure(int argc, char **argv) << fetcher->name() << " : " << std::flush; - auto result = fetcher->fetch(std::get<1>(data), std::get<2>(data)); + auto result = fetcher->fetch(std::get<1>(data), std::get<2>(data), {}); std::cout << (result.first ? "ok" : "failed") << "\n"; } diff --git a/src/lyrics_fetcher.cpp b/src/lyrics_fetcher.cpp index 8a7d2f51..c27e6702 100644 --- a/src/lyrics_fetcher.cpp +++ b/src/lyrics_fetcher.cpp @@ -19,7 +19,6 @@ ***************************************************************************/ #include "config.h" -#include "curl_handle.h" #include #include @@ -29,8 +28,15 @@ #include #include +#ifdef HAVE_TAGLIB_H +#include +#include +#endif // HAVE_TAGLIB_H + #include "charset.h" +#include "curl_handle.h" #include "lyrics_fetcher.h" +#include "settings.h" #include "utility/html.h" #include "utility/string.h" @@ -52,6 +58,10 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher) fetcher = std::make_unique(); else if (s == "internet") fetcher = std::make_unique(); +#ifdef HAVE_TAGLIB_H + else if (s == "tags") + fetcher = std::make_unique(); +#endif // HAVE_TAGLIB_H else is.setstate(std::ios::failbit); return is; @@ -60,7 +70,8 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher) const char LyricsFetcher::msgNotFound[] = "Not found"; LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist, - const std::string &title) + const std::string &title, + [[maybe_unused]] const MPD::Song &song) { Result result; result.first = false; @@ -131,7 +142,7 @@ void LyricsFetcher::postProcess(std::string &data) const stripHtmlTags(data); // Remove indentation from each line and collapse multiple newlines into one. std::vector lines; - boost::split(lines, data, boost::is_any_of("\n")); + boost::split(lines, data, boost::is_any_of("\r\n")); for (auto &line : lines) boost::trim(line); auto last = std::unique( @@ -146,7 +157,8 @@ void LyricsFetcher::postProcess(std::string &data) const /**********************************************************************/ LyricsFetcher::Result GoogleLyricsFetcher::fetch(const std::string &artist, - const std::string &title) + const std::string &title, + const MPD::Song &song) { Result result; result.first = false; @@ -188,7 +200,7 @@ LyricsFetcher::Result GoogleLyricsFetcher::fetch(const std::string &artist, data = unescapeHtmlUtf8(urls[0]); URL = data.c_str(); - return LyricsFetcher::fetch("", ""); + return LyricsFetcher::fetch("", "", song); } bool GoogleLyricsFetcher::isURLOk(const std::string &url) @@ -199,9 +211,10 @@ bool GoogleLyricsFetcher::isURLOk(const std::string &url) /**********************************************************************/ LyricsFetcher::Result InternetLyricsFetcher::fetch(const std::string &artist, - const std::string &title) + const std::string &title, + const MPD::Song &song) { - GoogleLyricsFetcher::fetch(artist, title); + GoogleLyricsFetcher::fetch(artist, title, song); LyricsFetcher::Result result; result.first = false; result.second = "The following site may contain lyrics for this song: "; @@ -214,3 +227,42 @@ bool InternetLyricsFetcher::isURLOk(const std::string &url) URL = url; return false; } + +#ifdef HAVE_TAGLIB_H +LyricsFetcher::Result TagsLyricsFetcher::fetch([[maybe_unused]] const std::string &artist, + [[maybe_unused]] const std::string &title, + const MPD::Song &song) +{ + LyricsFetcher::Result result; + result.first = false; + + std::string path; + if (song.isFromDatabase()) + path += Config.mpd_music_dir; + path += song.getURI(); + + TagLib::FileRef f(path.c_str()); + if (f.isNull()) + { + result.second = "Could not open file"; + return result; + } + + TagLib::PropertyMap properties = f.file()->properties(); + + if (properties.contains("LYRICS")) + { + result.first = true; + result.second = properties["LYRICS"].toString("\n\n").to8Bit(true); + } + else if (properties.contains("UNSYNCEDLYRICS")) + { + result.first = true; + result.second = properties["UNSYNCEDLYRICS"].toString("\n\n").to8Bit(true); + } + else + result.second = "No lyrics in tags"; + + return result; +} +#endif // HAVE_TAGLIB_H diff --git a/src/lyrics_fetcher.h b/src/lyrics_fetcher.h index f4cfc0b2..dc1b3f48 100644 --- a/src/lyrics_fetcher.h +++ b/src/lyrics_fetcher.h @@ -26,6 +26,8 @@ #include #include +#include "song.h" + struct LyricsFetcher { typedef std::pair Result; @@ -33,7 +35,7 @@ struct LyricsFetcher virtual ~LyricsFetcher() { } virtual const char *name() const = 0; - virtual Result fetch(const std::string &artist, const std::string &title); + virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song); protected: virtual const char *urlTemplate() const = 0; @@ -57,7 +59,7 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher); struct GoogleLyricsFetcher : public LyricsFetcher { - virtual Result fetch(const std::string &artist, const std::string &title); + virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song); protected: virtual const char *urlTemplate() const { return URL; } @@ -120,7 +122,7 @@ protected: struct InternetLyricsFetcher : public GoogleLyricsFetcher { virtual const char *name() const override { return "the Internet"; } - virtual Result fetch(const std::string &artist, const std::string &title) override; + virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song) override; protected: virtual const char *siteKeyword() const override { return nullptr; } @@ -132,4 +134,16 @@ private: std::string URL; }; +#ifdef HAVE_TAGLIB_H +struct TagsLyricsFetcher : public LyricsFetcher +{ + virtual const char *name() const override { return "tags"; } + virtual Result fetch(const std::string &artist, const std::string &title, const MPD::Song &song) override; + +protected: + virtual const char *urlTemplate() const override { return ""; } + virtual const char *regex() const override { return ""; } +}; +#endif // HAVE_TAGLIB_H + #endif // NCMPCPP_LYRICS_FETCHER_H diff --git a/src/screens/lyrics.cpp b/src/screens/lyrics.cpp index 5ca42869..70ea26cb 100644 --- a/src/screens/lyrics.cpp +++ b/src/screens/lyrics.cpp @@ -151,7 +151,7 @@ boost::optional downloadLyrics( << NC::Format::NoBold << "... "; } } - auto result_ = fetcher_->fetch(s_artist, s_title); + auto result_ = fetcher_->fetch(s_artist, s_title, s); if (result_.first == false) { if (shared_buffer) diff --git a/src/settings.cpp b/src/settings.cpp index d3c94b73..ddde73e0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -462,6 +462,9 @@ bool Configuration::read(const std::vector &config_paths, bool igno p.add("header_text_scrolling", &header_text_scrolling, "yes", yes_no); p.add("cyclic_scrolling", &use_cyclic_scrolling, "no", yes_no); p.add("lyrics_fetchers", nullptr, +#ifdef HAVE_TAGLIB_H + "tags, " +#endif "genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet", [this](std::string v) { lyrics_fetchers = list_of(v, [](std::string s) { LyricsFetcher_ fetcher;