Add support for fetching lyrics from tags

Adaptation of https://github.com/ncmpcpp/ncmpcpp/pull/482.
This commit is contained in:
Andrzej Rybczak
2024-09-03 03:15:09 +02:00
parent 510e28c65a
commit 9c27eec846
7 changed files with 83 additions and 13 deletions

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,6 @@
***************************************************************************/
#include "config.h"
#include "curl_handle.h"
#include <cstdlib>
#include <cstring>
@@ -29,8 +28,15 @@
#include <boost/algorithm/string/trim.hpp>
#include <boost/regex.hpp>
#ifdef HAVE_TAGLIB_H
#include <fileref.h>
#include <tpropertymap.h>
#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<ZeneszovegFetcher>();
else if (s == "internet")
fetcher = std::make_unique<InternetLyricsFetcher>();
#ifdef HAVE_TAGLIB_H
else if (s == "tags")
fetcher = std::make_unique<TagsLyricsFetcher>();
#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<std::string> 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

View File

@@ -26,6 +26,8 @@
#include <memory>
#include <string>
#include "song.h"
struct LyricsFetcher
{
typedef std::pair<bool, std::string> 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

View File

@@ -151,7 +151,7 @@ boost::optional<std::string> 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)

View File

@@ -462,6 +462,9 @@ bool Configuration::read(const std::vector<std::string> &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<void>("lyrics_fetchers", nullptr,
#ifdef HAVE_TAGLIB_H
"tags, "
#endif
"genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet", [this](std::string v) {
lyrics_fetchers = list_of<LyricsFetcher_>(v, [](std::string s) {
LyricsFetcher_ fetcher;