Make the list of lyrics fetchers customizable

This commit is contained in:
Andrzej Rybczak
2016-11-16 09:12:06 +01:00
parent b833818023
commit a2862b9fdf
9 changed files with 120 additions and 49 deletions

1
NEWS
View File

@@ -6,6 +6,7 @@ ncmpcpp-0.8 (????-??-??)
* Lyrics from files containing DOS line endings now load properly on Linux. * Lyrics from files containing DOS line endings now load properly on Linux.
* Added support for fetching lyrics from genius.com. * Added support for fetching lyrics from genius.com.
* Added support for fetching lyrics from tekstowo.pl. * Added support for fetching lyrics from tekstowo.pl.
* The list of lyrics fetchers can now be set via configuration file.
ncmpcpp-0.7.7 (2016-10-31) ncmpcpp-0.7.7 (2016-10-31)
* Fixed compilation on 32bit platforms. * Fixed compilation on 32bit platforms.

View File

@@ -368,6 +368,8 @@
# #
#lines_scrolled = 2 #lines_scrolled = 2
# #
#lyrics_fetchers = lyricwiki, azlyrics, genius, sing365, lyricsmania, metrolyrics, justsomelyrics, tekstowo, internet
#
#follow_now_playing_lyrics = no #follow_now_playing_lyrics = no
# #
#fetch_lyrics_for_current_song_in_background = no #fetch_lyrics_for_current_song_in_background = no

View File

@@ -244,6 +244,9 @@ If enabled, cyclic scrolling is used (e.g. if you press down arrow being at the
.B lines_scrolled = NUMBER .B lines_scrolled = NUMBER
Number of lines that are scrolled with mouse wheel. Number of lines that are scrolled with mouse wheel.
.TP .TP
.B lyrics_fetchers = FETCHERS
Comma separated list of lyrics fetchers.
.TP
.B follow_now_playing_lyrics = yes/no .B follow_now_playing_lyrics = yes/no
If enabled, lyrics will be switched at song's change to currently playing one's (Note: this works only if you are viewing lyrics of item from Playlist). If enabled, lyrics will be switched at song's change to currently playing one's (Note: this works only if you are viewing lyrics of item from Playlist).
.TP .TP

View File

@@ -43,7 +43,7 @@ using Global::MainHeight;
using Global::MainStartY; using Global::MainStartY;
#ifdef HAVE_CURL_CURL_H #ifdef HAVE_CURL_CURL_H
LyricsFetcher **Lyrics::itsFetcher = 0; LyricsFetcher *Lyrics::itsFetcher = nullptr;
std::queue<MPD::Song *> Lyrics::itsToDownload; std::queue<MPD::Song *> Lyrics::itsToDownload;
pthread_mutex_t Lyrics::itsDIBLock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t Lyrics::itsDIBLock = PTHREAD_MUTEX_INITIALIZER;
size_t Lyrics::itsWorkersNumber = 0; size_t Lyrics::itsWorkersNumber = 0;
@@ -207,16 +207,20 @@ void Lyrics::DownloadInBackgroundImplHelper(const MPD::Song &s)
std::string title = Curl::escape(s.getTitle()); std::string title = Curl::escape(s.getTitle());
LyricsFetcher::Result result; LyricsFetcher::Result result;
bool fetcher_defined = itsFetcher && *itsFetcher;
for (LyricsFetcher **plugin = fetcher_defined ? itsFetcher : lyricsPlugins; *plugin != 0; ++plugin) if (itsFetcher == nullptr)
{ {
result = (*plugin)->fetch(artist, title); for (auto &fetcher : Config.lyrics_fetchers)
if (result.first) {
break; result = fetcher->fetch(artist, title);
if (fetcher_defined) if (result.first)
break; break;
}
} }
if (result.first == true) else
itsFetcher->fetch(artist, title);
if (result.first)
Save(GenerateFilename(s), result.second); Save(GenerateFilename(s), result.second);
} }
@@ -224,25 +228,38 @@ void *Lyrics::Download()
{ {
std::string artist = Curl::escape(itsSong.getArtist()); std::string artist = Curl::escape(itsSong.getArtist());
std::string title_ = Curl::escape(itsSong.getTitle()); std::string title_ = Curl::escape(itsSong.getTitle());
LyricsFetcher::Result result; auto fetch_lyrics = [&](auto &fetcher) {
w << "Fetching lyrics from "
// if one of plugins is selected, try only this one, << NC::Format::Bold
// otherwise try all of them until one of them succeeds << fetcher->name()
bool fetcher_defined = itsFetcher && *itsFetcher; << NC::Format::NoBold << "... ";
for (LyricsFetcher **plugin = fetcher_defined ? itsFetcher : lyricsPlugins; *plugin != 0; ++plugin) auto result = fetcher->fetch(artist, title_);
{
w << "Fetching lyrics from " << NC::Format::Bold << (*plugin)->name() << NC::Format::NoBold << "... ";
result = (*plugin)->fetch(artist, title_);
if (result.first == false) if (result.first == false)
w << NC::Color::Red << result.second << NC::Color::End << '\n'; {
else w << NC::Color::Red
break; << result.second
if (fetcher_defined) << NC::Color::End
break; << '\n';
}
return result;
};
LyricsFetcher::Result result;
if (itsFetcher == nullptr)
{
for (auto &fetcher : Config.lyrics_fetchers)
{
result = fetch_lyrics(fetcher);
if (result.first)
break;
}
} }
else
if (result.first == true) result = fetch_lyrics(itsFetcher);
if (result.first)
{ {
Save(itsFilename, result.second); Save(itsFilename, result.second);
w.clear(); w.clear();
@@ -401,14 +418,28 @@ void Lyrics::Refetch()
void Lyrics::ToggleFetcher() void Lyrics::ToggleFetcher()
{ {
if (itsFetcher && *itsFetcher) if (itsFetcher != nullptr)
++itsFetcher; {
auto fetcher = std::find_if(Config.lyrics_fetchers.begin(),
Config.lyrics_fetchers.end(),
[](auto &f) { return f.get() == itsFetcher; });
assert(fetcher != Config.lyrics_fetchers.end());
++fetcher;
if (fetcher != Config.lyrics_fetchers.end())
itsFetcher = fetcher->get();
else
itsFetcher = nullptr;
}
else else
itsFetcher = &lyricsPlugins[0]; {
if (*itsFetcher) assert(!Config.lyrics_fetchers.empty());
Statusbar::printf("Using lyrics database: %s", (*itsFetcher)->name()); itsFetcher = Config.lyrics_fetchers[0].get();
}
if (itsFetcher != nullptr)
Statusbar::printf("Using lyrics fetcher: %s", itsFetcher->name());
else else
Statusbar::print("Using all lyrics databases"); Statusbar::print("Using all lyrics fetchers");
} }
void Lyrics::Take() void Lyrics::Take()

View File

@@ -83,7 +83,7 @@ private:
bool isDownloadInProgress; bool isDownloadInProgress;
pthread_t itsDownloader; pthread_t itsDownloader;
static LyricsFetcher **itsFetcher; static LyricsFetcher *itsFetcher;
# endif // HAVE_CURL_CURL_H # endif // HAVE_CURL_CURL_H
size_t itsScrollBegin; size_t itsScrollBegin;

View File

@@ -36,19 +36,28 @@
#include "utility/html.h" #include "utility/html.h"
#include "utility/string.h" #include "utility/string.h"
LyricsFetcher *lyricsPlugins[] = std::unique_ptr<LyricsFetcher> toLyricsFetcher(const std::string &s)
{ {
new LyricwikiFetcher(), if (s == "lyricwiki")
new GeniusLyricsFetcher(), return std::make_unique<LyricwikiFetcher>();
new AzLyricsFetcher(), else if (s == "azlyrics")
new Sing365Fetcher(), return std::make_unique<AzLyricsFetcher>();
new LyricsmaniaFetcher(), else if (s == "genius")
new MetrolyricsFetcher(), return std::make_unique<GeniusFetcher>();
new JustSomeLyricsFetcher(), else if (s == "sing365")
new TekstowoLyricsFetcher(), return std::make_unique<Sing365Fetcher>();
new InternetLyricsFetcher(), else if (s == "lyricsmania")
0 return std::make_unique<LyricsmaniaFetcher>();
}; else if (s == "metrolyrics")
return std::make_unique<MetrolyricsFetcher>();
else if (s == "justsomelyrics")
return std::make_unique<JustSomeLyricsFetcher>();
else if (s == "tekstowo")
return std::make_unique<TekstowoFetcher>();
else if (s == "internet")
return std::make_unique<InternetLyricsFetcher>();
throw std::runtime_error("no lyrics fetcher named '" + s + "'");
}
const char LyricsFetcher::msgNotFound[] = "Not found"; const char LyricsFetcher::msgNotFound[] = "Not found";

View File

@@ -25,6 +25,7 @@
#ifdef HAVE_CURL_CURL_H #ifdef HAVE_CURL_CURL_H
#include <memory>
#include <string> #include <string>
struct LyricsFetcher struct LyricsFetcher
@@ -46,6 +47,12 @@ protected:
static const char msgNotFound[]; static const char msgNotFound[];
}; };
typedef std::vector<std::unique_ptr<LyricsFetcher>> LyricsFetchers;
std::unique_ptr<LyricsFetcher> toLyricsFetcher(const std::string &s);
/**********************************************************************/
struct LyricwikiFetcher : public LyricsFetcher struct LyricwikiFetcher : public LyricsFetcher
{ {
virtual const char *name() const override { return "lyricwiki.com"; } virtual const char *name() const override { return "lyricwiki.com"; }
@@ -116,7 +123,7 @@ protected:
virtual const char *regex() const override { return "<div class=\"lyricsh\">.*?</h2>.*<div>(.*?)</div>"; } virtual const char *regex() const override { return "<div class=\"lyricsh\">.*?</h2>.*<div>(.*?)</div>"; }
}; };
struct GeniusLyricsFetcher : public GoogleLyricsFetcher struct GeniusFetcher : public GoogleLyricsFetcher
{ {
virtual const char *name() const override { return "genius.com"; } virtual const char *name() const override { return "genius.com"; }
@@ -124,7 +131,7 @@ protected:
virtual const char *regex() const override { return "<lyrics.*?>(.*?)</lyrics>"; } virtual const char *regex() const override { return "<lyrics.*?>(.*?)</lyrics>"; }
}; };
struct TekstowoLyricsFetcher : public GoogleLyricsFetcher struct TekstowoFetcher : public GoogleLyricsFetcher
{ {
virtual const char *name() const override { return "tekstowo.pl"; } virtual const char *name() const override { return "tekstowo.pl"; }
@@ -147,8 +154,6 @@ private:
std::string URL; std::string URL;
}; };
extern LyricsFetcher *lyricsPlugins[];
#endif // HAVE_CURL_CURL_H #endif // HAVE_CURL_CURL_H
#endif // NCMPCPP_LYRICS_FETCHER_H #endif // NCMPCPP_LYRICS_FETCHER_H

View File

@@ -503,6 +503,23 @@ bool Configuration::read(const std::vector<std::string> &config_paths, bool igno
p.add("lines_scrolled", assign_default( p.add("lines_scrolled", assign_default(
lines_scrolled, 2 lines_scrolled, 2
)); ));
p.add("lyrics_fetchers", option_parser::worker([this](std::string v) {
boost::sregex_token_iterator fetcher(v.begin(), v.end(), boost::regex("\\w+")), end;
for (; fetcher != end; ++fetcher)
lyrics_fetchers.push_back(toLyricsFetcher(*fetcher));
if (lyrics_fetchers.empty())
throw std::runtime_error("empty list");
}, [this] {
lyrics_fetchers.push_back(std::make_unique<LyricwikiFetcher>());
lyrics_fetchers.push_back(std::make_unique<AzLyricsFetcher>());
lyrics_fetchers.push_back(std::make_unique<GeniusFetcher>());
lyrics_fetchers.push_back(std::make_unique<Sing365Fetcher>());
lyrics_fetchers.push_back(std::make_unique<LyricsmaniaFetcher>());
lyrics_fetchers.push_back(std::make_unique<MetrolyricsFetcher>());
lyrics_fetchers.push_back(std::make_unique<JustSomeLyricsFetcher>());
lyrics_fetchers.push_back(std::make_unique<TekstowoFetcher>());
lyrics_fetchers.push_back(std::make_unique<InternetLyricsFetcher>());
}));
p.add("follow_now_playing_lyrics", yes_no( p.add("follow_now_playing_lyrics", yes_no(
now_playing_lyrics, false now_playing_lyrics, false
)); ));

View File

@@ -30,6 +30,7 @@
#include "enums.h" #include "enums.h"
#include "format.h" #include "format.h"
#include "lyrics_fetcher.h"
#include "screen_type.h" #include "screen_type.h"
#include "strbuffer.h" #include "strbuffer.h"
@@ -195,6 +196,8 @@ struct Configuration
std::list<ScreenType> screen_sequence; std::list<ScreenType> screen_sequence;
SortMode browser_sort_mode; SortMode browser_sort_mode;
LyricsFetchers lyrics_fetchers;
}; };
extern Configuration Config; extern Configuration Config;