Make the list of lyrics fetchers customizable

master
Andrzej Rybczak 9 years ago
parent b833818023
commit a2862b9fdf
  1. 1
      NEWS
  2. 2
      doc/config
  3. 3
      doc/ncmpcpp.1
  4. 93
      src/lyrics.cpp
  5. 2
      src/lyrics.h
  6. 33
      src/lyrics_fetcher.cpp
  7. 13
      src/lyrics_fetcher.h
  8. 17
      src/settings.cpp
  9. 3
      src/settings.h

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

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

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

@ -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());
auto fetch_lyrics = [&](auto &fetcher) {
w << "Fetching lyrics from "
<< NC::Format::Bold
<< fetcher->name()
<< NC::Format::NoBold << "... ";
auto result = fetcher->fetch(artist, title_);
if (result.first == false)
{
w << NC::Color::Red
<< result.second
<< NC::Color::End
<< '\n';
}
return result;
};
LyricsFetcher::Result result; LyricsFetcher::Result result;
// if one of plugins is selected, try only this one, if (itsFetcher == nullptr)
// otherwise try all of them until one of them succeeds
bool fetcher_defined = itsFetcher && *itsFetcher;
for (LyricsFetcher **plugin = fetcher_defined ? itsFetcher : lyricsPlugins; *plugin != 0; ++plugin)
{ {
w << "Fetching lyrics from " << NC::Format::Bold << (*plugin)->name() << NC::Format::NoBold << "... "; for (auto &fetcher : Config.lyrics_fetchers)
result = (*plugin)->fetch(artist, title_); {
if (result.first == false) result = fetch_lyrics(fetcher);
w << NC::Color::Red << result.second << NC::Color::End << '\n'; if (result.first)
else break;
break; }
if (fetcher_defined)
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()

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

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

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

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

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

Loading…
Cancel
Save