diff --git a/ext/libclementine-remote/remotecontrolmessages.proto b/ext/libclementine-remote/remotecontrolmessages.proto index 4a687df77..dc6c63b8a 100644 --- a/ext/libclementine-remote/remotecontrolmessages.proto +++ b/ext/libclementine-remote/remotecontrolmessages.proto @@ -14,6 +14,7 @@ enum MsgType { REMOVE_SONGS = 9; OPEN_PLAYLIST = 10; CLOSE_PLAYLIST = 11; + GET_LYRICS = 14; // Lastfm LOVE = 12; BAN = 13; @@ -42,6 +43,7 @@ enum MsgType { UPDATE_TRACK_POSITION = 46; ACTIVE_PLAYLIST_CHANGED = 47; FIRST_DATA_SENT_COMPLETE = 48; + LYRICS = 49; } // Valid Engine states @@ -212,9 +214,19 @@ message RequestClosePlaylist { optional int32 playlist_id = 1; } +// Message containing lyrics +message ResponseLyrics { + repeated Lyric lyrics = 1; +} +message Lyric { + optional string id = 1; + optional string title = 2; + optional string content = 3; +} + // The message itself message Message { - optional int32 version = 1 [default=7]; + optional int32 version = 1 [default=8]; optional MsgType type = 2 [default=UNKNOWN]; // What data is in the message? optional RequestConnect request_connect = 21; @@ -239,4 +251,5 @@ message Message { optional ResponseUpdateTrackPosition response_update_track_position = 20; optional ResponseDisconnect response_disconnect = 22; optional ResponseActiveChanged response_active_changed = 24; + optional ResponseLyrics response_lyrics = 30; } diff --git a/src/networkremote/incomingdataparser.cpp b/src/networkremote/incomingdataparser.cpp index 110443f25..92c9af677 100644 --- a/src/networkremote/incomingdataparser.cpp +++ b/src/networkremote/incomingdataparser.cpp @@ -142,6 +142,8 @@ void IncomingDataParser::Parse(const pb::remote::Message& msg) { break; case pb::remote::BAN: emit Ban(); break; + case pb::remote::GET_LYRICS: emit GetLyrics(); + break; default: break; } } diff --git a/src/networkremote/incomingdataparser.h b/src/networkremote/incomingdataparser.h index 73a1d6c4f..c8966a2c2 100644 --- a/src/networkremote/incomingdataparser.h +++ b/src/networkremote/incomingdataparser.h @@ -24,6 +24,7 @@ signals: void SendPlaylistSongs(int id); void Open(int id); void Close(int id); + void GetLyrics(); void Love(); void Ban(); diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index b60815616..2a64aa388 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -155,6 +155,9 @@ void NetworkRemote::AcceptConnection() { SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)), outgoing_data_creator_.get(), SLOT(SendShuffleMode(PlaylistSequence::ShuffleMode))); + + connect(incoming_data_parser_.get(), SIGNAL(GetLyrics()), + outgoing_data_creator_.get(), SLOT(GetLyrics())); } QTcpServer* server = qobject_cast(sender()); diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp index bb2180f35..04c3abd02 100644 --- a/src/networkremote/outgoingdatacreator.cpp +++ b/src/networkremote/outgoingdatacreator.cpp @@ -19,21 +19,23 @@ #include +#include +#include +#include + #include "networkremote.h" #include "core/logging.h" #include "core/timeconstants.h" OutgoingDataCreator::OutgoingDataCreator(Application* app) - : app_(app) + : app_(app), + ultimate_reader_(new UltimateLyricsReader(this)), + fetcher_(new SongInfoFetcher(this)) { // Create Keep Alive Timer keep_alive_timer_ = new QTimer(this); connect(keep_alive_timer_, SIGNAL(timeout()), this, SLOT(SendKeepAlive())); keep_alive_timeout_ = 10000; - - // Create the song position timer - track_position_timer_ = new QTimer(this); - connect(track_position_timer_, SIGNAL(timeout()), this, SLOT(UpdateTrackPosition())); } OutgoingDataCreator::~OutgoingDataCreator() { @@ -49,6 +51,22 @@ void OutgoingDataCreator::SetClients(QList* clients) { if (app_->player()->engine()->state() == Engine::Playing) { track_position_timer_->start(1000); } + + // Create the song position timer + track_position_timer_ = new QTimer(this); + connect(track_position_timer_, SIGNAL(timeout()), this, SLOT(UpdateTrackPosition())); + + // Parse the ultimate lyrics xml file + ultimate_reader_->SetThread(this->thread()); + provider_list_ = ultimate_reader_->Parse(":lyrics/ultimate_providers.xml"); + + // Set up the lyrics parser + connect(fetcher_, SIGNAL(ResultReady(int,SongInfoFetcher::Result)), + SLOT(SendLyrics(int,SongInfoFetcher::Result))); + + foreach (SongInfoProvider* provider, provider_list_) { + fetcher_->AddProvider(provider); + } } void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { @@ -428,3 +446,29 @@ void OutgoingDataCreator::DisconnectAllClients() { msg.mutable_response_disconnect()->set_reason_disconnect(pb::remote::Server_Shutdown); SendDataToClients(&msg); } + +void OutgoingDataCreator::GetLyrics() { + fetcher_->FetchInfo(current_song_); +} + +void OutgoingDataCreator::SendLyrics(int id, const SongInfoFetcher::Result& result) { + pb::remote::Message msg; + msg.set_type(pb::remote::LYRICS); + pb::remote::ResponseLyrics* response = msg.mutable_response_lyrics(); + + foreach (const CollapsibleInfoPane::Data& data, result.info_) { + // If the size is zero, do not send the provider + SongInfoTextView* editor = qobject_cast(data.contents_); + if (editor->toPlainText().length() == 0) + continue; + + pb::remote::Lyric* lyric = response->mutable_lyrics()->Add(); + + lyric->set_id(DataCommaSizeFromQString(data.id_)); + lyric->set_title(DataCommaSizeFromQString(data.title_)); + lyric->set_content(DataCommaSizeFromQString(editor->toPlainText())); + } + SendDataToClients(&msg); + + results_.take(id); +} diff --git a/src/networkremote/outgoingdatacreator.h b/src/networkremote/outgoingdatacreator.h index a6d2e04f4..7e2fd2747 100644 --- a/src/networkremote/outgoingdatacreator.h +++ b/src/networkremote/outgoingdatacreator.h @@ -13,8 +13,17 @@ #include "playlist/playlist.h" #include "playlist/playlistmanager.h" #include "playlist/playlistbackend.h" +#include "songinfo/collapsibleinfopane.h" +#include "songinfo/songinfofetcher.h" +#include "songinfo/songinfoprovider.h" +#include "songinfo/songinfotextview.h" +#include "songinfo/ultimatelyricsprovider.h" +#include "songinfo/ultimatelyricsreader.h" #include "remotecontrolmessages.pb.h" #include "remoteclient.h" +#include + +typedef QList ProviderList; class OutgoingDataCreator : public QObject { Q_OBJECT @@ -44,6 +53,8 @@ public slots: void SendShuffleMode(PlaylistSequence::ShuffleMode mode); void UpdateTrackPosition(); void DisconnectAllClients(); + void GetLyrics(); + void SendLyrics(int id, const SongInfoFetcher::Result& result); private: Application* app_; @@ -56,6 +67,11 @@ private: QTimer* track_position_timer_; int keep_alive_timeout_; + boost::scoped_ptr ultimate_reader_; + ProviderList provider_list_; + QMap results_; + SongInfoFetcher* fetcher_; + void SendDataToClients(pb::remote::Message* msg); void SetEngineState(pb::remote::ResponseClementineInfo* msg); void CreateSong( diff --git a/src/songinfo/ultimatelyricsreader.cpp b/src/songinfo/ultimatelyricsreader.cpp index 95ed0f35c..4862e5de3 100644 --- a/src/songinfo/ultimatelyricsreader.cpp +++ b/src/songinfo/ultimatelyricsreader.cpp @@ -24,10 +24,15 @@ #include UltimateLyricsReader::UltimateLyricsReader(QObject* parent) - : QObject(parent) + : QObject(parent), + thread_(qApp->thread()) { } +void UltimateLyricsReader::SetThread(QThread *thread) { + thread_ = thread; +} + QList UltimateLyricsReader::Parse(const QString& filename) const { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { @@ -48,7 +53,7 @@ QList UltimateLyricsReader::ParseDevice(QIODevice* device) co if (reader.name() == "provider") { SongInfoProvider* provider = ParseProvider(&reader); if (provider) { - provider->moveToThread(qApp->thread()); + provider->moveToThread(thread_); ret << provider; } } diff --git a/src/songinfo/ultimatelyricsreader.h b/src/songinfo/ultimatelyricsreader.h index d353ae763..a369ed768 100644 --- a/src/songinfo/ultimatelyricsreader.h +++ b/src/songinfo/ultimatelyricsreader.h @@ -21,6 +21,7 @@ #include "ultimatelyricsprovider.h" #include +#include #include class QIODevice; @@ -34,10 +35,14 @@ public: QList Parse(const QString& filename) const; QList ParseDevice(QIODevice* device) const; + void SetThread(QThread* thread); + private: SongInfoProvider* ParseProvider(QXmlStreamReader* reader) const; UltimateLyricsProvider::Rule ParseRule(QXmlStreamReader* reader) const; QString ParseInvalidIndicator(QXmlStreamReader* reader) const; + + QThread* thread_; }; #endif // ULTIMATELYRICSREADER_H