lyrics: add support for showing notifications about fetching lyrics in background

This commit is contained in:
Andrzej Rybczak
2016-11-21 10:47:27 +01:00
parent ba83b9daab
commit 5b56c48c4a
4 changed files with 74 additions and 21 deletions

View File

@@ -317,6 +317,10 @@ void UpdateEnvironment::run(bool update_timer, bool refresh_window)
// update timer, status if necessary etc.
Status::trace(update_timer, true);
// show lyrics consumer notification if appropriate
if (auto message = myLyrics->tryTakeConsumerMessage())
Statusbar::print(*message);
// header stuff
if ((myScreen == myPlaylist || myScreen == myBrowser || myScreen == myLyrics)
&& (Timer - m_past > boost::posix_time::milliseconds(500))

View File

@@ -190,7 +190,6 @@ Lyrics::Lyrics()
, m_refresh_window(false)
, m_scroll_begin(0)
, m_fetcher(nullptr)
, m_shared_queue(std::make_pair(false, std::queue<MPD::Song>{}))
{ }
void Lyrics::resize()
@@ -359,42 +358,62 @@ void Lyrics::toggleFetcher()
Statusbar::print("Using all lyrics fetchers");
}
void Lyrics::fetchInBackground(const MPD::Song &s)
void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_)
{
auto consumer = [this] {
auto consumer_impl = [this] {
std::string lyrics_file;
while (true)
{
MPD::Song qs;
ConsumerState::Song cs;
{
auto queue = m_shared_queue.acquire();
assert(queue->first);
if (queue->second.empty())
auto consumer = m_consumer_state.acquire();
assert(consumer->running);
if (consumer->songs.empty())
{
queue->first = false;
consumer->running = false;
break;
}
lyrics_file = lyricsFilename(queue->second.front());
lyrics_file = lyricsFilename(consumer->songs.front().song());
if (!boost::filesystem::exists(lyrics_file))
qs = queue->second.front();
queue->second.pop();
{
cs = consumer->songs.front();
if (cs.notify())
{
consumer->message = "Fetching lyrics for \""
+ Format::stringify<char>(Config.song_status_format, &cs.song())
+ "\"...";
}
}
consumer->songs.pop();
}
if (!qs.empty())
if (!cs.song().empty())
{
auto lyrics = downloadLyrics(qs, nullptr, m_fetcher);
auto lyrics = downloadLyrics(cs.song(), nullptr, m_fetcher);
if (lyrics)
saveLyrics(lyrics_file, *lyrics);
}
}
};
auto queue = m_shared_queue.acquire();
queue->second.push(s);
auto consumer = m_consumer_state.acquire();
consumer->songs.emplace(s, notify_);
// Start the consumer if it's not running.
if (!queue->first)
if (!consumer->running)
{
std::thread t(consumer);
std::thread t(consumer_impl);
t.detach();
queue->first = true;
consumer->running = true;
}
}
boost::optional<std::string> Lyrics::tryTakeConsumerMessage()
{
boost::optional<std::string> result;
auto consumer = m_consumer_state.acquire();
if (consumer->message)
{
result = std::move(consumer->message);
consumer->message = boost::none;
}
return result;
}

View File

@@ -55,9 +55,39 @@ struct Lyrics: Screen<NC::Scrollpad>, Tabbable
void edit();
void toggleFetcher();
void fetchInBackground(const MPD::Song &s);
void fetchInBackground(const MPD::Song &s, bool notify_);
boost::optional<std::string> tryTakeConsumerMessage();
private:
struct ConsumerState
{
struct Song
{
Song()
: m_notify(false)
{ }
Song(const MPD::Song &s, bool notify_)
: m_song(s), m_notify(notify_)
{ }
const MPD::Song &song() const { return m_song; }
bool notify() const { return m_notify; }
private:
MPD::Song m_song;
bool m_notify;
};
ConsumerState()
: running(false)
{ }
bool running;
std::queue<Song> songs;
boost::optional<std::string> message;
};
bool m_refresh_window;
size_t m_scroll_begin;
@@ -67,7 +97,7 @@ private:
LyricsFetcher *m_fetcher;
std::future<boost::optional<std::string>> m_worker;
Shared<std::pair<bool, std::queue<MPD::Song>>> m_shared_queue;
Shared<ConsumerState> m_consumer_state;
};
extern Lyrics *myLyrics;

View File

@@ -573,7 +573,7 @@ void Status::Changes::songID(int song_id)
res = system(Config.execute_on_song_change.c_str());
if (Config.fetch_lyrics_in_background)
myLyrics->fetchInBackground(s);
myLyrics->fetchInBackground(s, false);
drawTitle(s);