1 /* This file is part of Clementine.
2    Copyright 2012, Andreas Muttscheller <asfa194@gmail.com>
3 
4    Clementine is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8 
9    Clementine is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "incomingdataparser.h"
19 
20 #include <algorithm>
21 
22 #include "core/logging.h"
23 #include "core/timeconstants.h"
24 #include "engines/enginebase.h"
25 #include "internet/core/internetmodel.h"
26 #include "playlist/playlistmanager.h"
27 #include "playlist/playlistsequence.h"
28 #include "playlist/playlist.h"
29 
30 #ifdef HAVE_LIBLASTFM
31 #include "internet/lastfm/lastfmservice.h"
32 #endif
33 
IncomingDataParser(Application * app)34 IncomingDataParser::IncomingDataParser(Application* app) : app_(app) {
35   // load settings initially and sign up for updates
36   ReloadSettings();
37   connect(app_, SIGNAL(SettingsChanged()), SLOT(ReloadSettings()));
38 
39   // Connect all the signals
40   // due the player is in a different thread, we cannot access these functions
41   // directly
42   connect(this, SIGNAL(Play()), app_->player(), SLOT(Play()));
43   connect(this, SIGNAL(PlayPause()), app_->player(), SLOT(PlayPause()));
44   connect(this, SIGNAL(Pause()), app_->player(), SLOT(Pause()));
45   connect(this, SIGNAL(Stop()), app_->player(), SLOT(Stop()));
46   connect(this, SIGNAL(StopAfterCurrent()), app_->player(),
47           SLOT(StopAfterCurrent()));
48   connect(this, SIGNAL(Next()), app_->player(), SLOT(Next()));
49   connect(this, SIGNAL(Previous()), app_->player(), SLOT(Previous()));
50   connect(this, SIGNAL(SetVolume(int)), app_->player(), SLOT(SetVolume(int)));
51   connect(this, SIGNAL(PlayAt(int, Engine::TrackChangeFlags, bool)),
52           app_->player(), SLOT(PlayAt(int, Engine::TrackChangeFlags, bool)));
53   connect(this, SIGNAL(SeekTo(int)), app_->player(), SLOT(SeekTo(int)));
54   connect(this, SIGNAL(Enque(int, int)), app_->playlist_manager(),
55           SLOT(Enque(int, int)));
56 
57   connect(this, SIGNAL(SetActivePlaylist(int)), app_->playlist_manager(),
58           SLOT(SetActivePlaylist(int)));
59   connect(this, SIGNAL(ShuffleCurrent()), app_->playlist_manager(),
60           SLOT(ShuffleCurrent()));
61   connect(this, SIGNAL(SetRepeatMode(PlaylistSequence::RepeatMode)),
62           app_->playlist_manager()->sequence(),
63           SLOT(SetRepeatMode(PlaylistSequence::RepeatMode)));
64   connect(this, SIGNAL(SetShuffleMode(PlaylistSequence::ShuffleMode)),
65           app_->playlist_manager()->sequence(),
66           SLOT(SetShuffleMode(PlaylistSequence::ShuffleMode)));
67   connect(this, SIGNAL(InsertUrls(int, const QList<QUrl>&, int, bool, bool)),
68           app_->playlist_manager(),
69           SLOT(InsertUrls(int, const QList<QUrl>&, int, bool, bool)));
70   connect(this, SIGNAL(InsertSongs(int, const SongList&, int, bool, bool)),
71           app_->playlist_manager(),
72           SLOT(InsertSongs(int, const SongList&, int, bool, bool)));
73   connect(this, SIGNAL(RemoveSongs(int, const QList<int>&)),
74           app_->playlist_manager(),
75           SLOT(RemoveItemsWithoutUndo(int, const QList<int>&)));
76   connect(this, SIGNAL(Open(int)), app_->playlist_manager(), SLOT(Open(int)));
77   connect(this, SIGNAL(Close(int)), app_->playlist_manager(), SLOT(Close(int)));
78 
79   connect(this, SIGNAL(RateCurrentSong(double)), app_->playlist_manager(),
80           SLOT(RateCurrentSong(double)));
81 
82 #ifdef HAVE_LIBLASTFM
83   connect(this, SIGNAL(Love()), app_->scrobbler(), SLOT(Love()));
84 #endif
85 }
86 
~IncomingDataParser()87 IncomingDataParser::~IncomingDataParser() {}
88 
ReloadSettings()89 void IncomingDataParser::ReloadSettings() {
90   QSettings s;
91   s.beginGroup(MainWindow::kSettingsGroup);
92   doubleclick_playlist_addmode_ = MainWindow::PlaylistAddBehaviour(
93       s.value("doubleclick_playlist_addmode",
94               MainWindow::PlaylistAddBehaviour_Enqueue)
95           .toInt());
96 }
97 
close_connection()98 bool IncomingDataParser::close_connection() { return close_connection_; }
99 
Parse(const pb::remote::Message & msg)100 void IncomingDataParser::Parse(const pb::remote::Message& msg) {
101   close_connection_ = false;
102 
103   RemoteClient* client = qobject_cast<RemoteClient*>(sender());
104 
105   // Now check what's to do
106   switch (msg.type()) {
107     case pb::remote::CONNECT:
108       ClientConnect(msg, client);
109       break;
110     case pb::remote::DISCONNECT:
111       close_connection_ = true;
112       break;
113     case pb::remote::REQUEST_PLAYLISTS:
114       SendPlaylists(msg);
115       break;
116     case pb::remote::REQUEST_PLAYLIST_SONGS:
117       GetPlaylistSongs(msg);
118       break;
119     case pb::remote::SET_VOLUME:
120       emit SetVolume(msg.request_set_volume().volume());
121       break;
122     case pb::remote::PLAY:
123       emit Play();
124       break;
125     case pb::remote::PLAYPAUSE:
126       emit PlayPause();
127       break;
128     case pb::remote::PAUSE:
129       emit Pause();
130       break;
131     case pb::remote::STOP:
132       emit Stop();
133       break;
134     case pb::remote::STOP_AFTER:
135       emit StopAfterCurrent();
136       break;
137     case pb::remote::NEXT:
138       emit Next();
139       break;
140     case pb::remote::PREVIOUS:
141       emit Previous();
142       break;
143     case pb::remote::CHANGE_SONG:
144       ChangeSong(msg);
145       break;
146     case pb::remote::SHUFFLE_PLAYLIST:
147       emit ShuffleCurrent();
148       break;
149     case pb::remote::REPEAT:
150       SetRepeatMode(msg.repeat());
151       break;
152     case pb::remote::SHUFFLE:
153       SetShuffleMode(msg.shuffle());
154       break;
155     case pb::remote::SET_TRACK_POSITION:
156       emit SeekTo(msg.request_set_track_position().position());
157       break;
158     case pb::remote::INSERT_URLS:
159       InsertUrls(msg);
160       break;
161     case pb::remote::REMOVE_SONGS:
162       RemoveSongs(msg);
163       break;
164     case pb::remote::OPEN_PLAYLIST:
165       OpenPlaylist(msg);
166       break;
167     case pb::remote::CLOSE_PLAYLIST:
168       ClosePlaylist(msg);
169       break;
170     case pb::remote::LOVE:
171       emit Love();
172       break;
173     case pb::remote::BAN:
174       emit Ban();
175       break;
176     case pb::remote::GET_LYRICS:
177       emit GetLyrics();
178       break;
179     case pb::remote::DOWNLOAD_SONGS:
180       client->song_sender()->SendSongs(msg.request_download_songs());
181       break;
182     case pb::remote::SONG_OFFER_RESPONSE:
183       client->song_sender()->ResponseSongOffer(msg.response_song_offer().accepted());
184       break;
185     case pb::remote::GET_LIBRARY:
186       emit SendLibrary(client);
187       break;
188     case pb::remote::RATE_SONG:
189       RateSong(msg);
190       break;
191     case pb::remote::GLOBAL_SEARCH:
192       GlobalSearch(client, msg);
193       break;
194     default:
195       break;
196   }
197 }
198 
GetPlaylistSongs(const pb::remote::Message & msg)199 void IncomingDataParser::GetPlaylistSongs(const pb::remote::Message& msg) {
200   emit SendPlaylistSongs(msg.request_playlist_songs().id());
201 }
202 
ChangeSong(const pb::remote::Message & msg)203 void IncomingDataParser::ChangeSong(const pb::remote::Message& msg) {
204   // Get the first entry and check if there is a song
205   const pb::remote::RequestChangeSong& request = msg.request_change_song();
206 
207   // Check if we need to change the playlist
208   if (request.playlist_id() != app_->playlist_manager()->active_id()) {
209     emit SetActivePlaylist(request.playlist_id());
210   }
211 
212   switch (doubleclick_playlist_addmode_) {
213     // Play the selected song
214     case MainWindow::PlaylistAddBehaviour_Play:
215       emit PlayAt(request.song_index(), Engine::Manual, false);
216       break;
217 
218     // Enque the selected song
219     case MainWindow::PlaylistAddBehaviour_Enqueue:
220       emit Enque(request.playlist_id(), request.song_index());
221       if (app_->player()->GetState() != Engine::Playing) {
222         emit PlayAt(request.song_index(), Engine::Manual, false);
223       }
224 
225       break;
226   }
227 }
228 
SetRepeatMode(const pb::remote::Repeat & repeat)229 void IncomingDataParser::SetRepeatMode(const pb::remote::Repeat& repeat) {
230   switch (repeat.repeat_mode()) {
231     case pb::remote::Repeat_Off:
232       emit SetRepeatMode(PlaylistSequence::Repeat_Off);
233       break;
234     case pb::remote::Repeat_Track:
235       emit SetRepeatMode(PlaylistSequence::Repeat_Track);
236       break;
237     case pb::remote::Repeat_Album:
238       emit SetRepeatMode(PlaylistSequence::Repeat_Album);
239       break;
240     case pb::remote::Repeat_Playlist:
241       emit SetRepeatMode(PlaylistSequence::Repeat_Playlist);
242       break;
243     default:
244       break;
245   }
246 }
247 
SetShuffleMode(const pb::remote::Shuffle & shuffle)248 void IncomingDataParser::SetShuffleMode(const pb::remote::Shuffle& shuffle) {
249   switch (shuffle.shuffle_mode()) {
250     case pb::remote::Shuffle_Off:
251       emit SetShuffleMode(PlaylistSequence::Shuffle_Off);
252       break;
253     case pb::remote::Shuffle_All:
254       emit SetShuffleMode(PlaylistSequence::Shuffle_All);
255       break;
256     case pb::remote::Shuffle_InsideAlbum:
257       emit SetShuffleMode(PlaylistSequence::Shuffle_InsideAlbum);
258       break;
259     case pb::remote::Shuffle_Albums:
260       emit SetShuffleMode(PlaylistSequence::Shuffle_Albums);
261       break;
262     default:
263       break;
264   }
265 }
266 
InsertUrls(const pb::remote::Message & msg)267 void IncomingDataParser::InsertUrls(const pb::remote::Message& msg) {
268   const pb::remote::RequestInsertUrls& request = msg.request_insert_urls();
269 
270   // Insert plain urls without metadata
271   if (!request.urls().empty()) {
272     QList<QUrl> urls;
273     for (auto it = request.urls().begin(); it != request.urls().end(); ++it) {
274       std::string s = *it;
275       urls << QUrl(QStringFromStdString(s));
276     }
277 
278     // Insert the urls
279     emit InsertUrls(request.playlist_id(), urls, request.position(),
280                     request.play_now(), request.enqueue());
281   }
282 
283   // Add songs with metadata if present
284   if (!request.songs().empty()) {
285     SongList songs;
286     for (int i = 0; i < request.songs().size(); i++) {
287       songs << CreateSongFromProtobuf(request.songs(i));
288     }
289     emit InsertSongs(request.playlist_id(), songs, request.position(),
290                      request.play_now(), request.enqueue());
291   }
292 }
293 
RemoveSongs(const pb::remote::Message & msg)294 void IncomingDataParser::RemoveSongs(const pb::remote::Message& msg) {
295   const pb::remote::RequestRemoveSongs& request = msg.request_remove_songs();
296 
297   // Extract urls
298   QList<int> songs;
299   for (int i = 0; i < request.songs().size(); i++) {
300     songs.append(request.songs(i));
301   }
302 
303   // Insert the urls
304   emit RemoveSongs(request.playlist_id(), songs);
305 }
306 
ClientConnect(const pb::remote::Message & msg,RemoteClient * client)307 void IncomingDataParser::ClientConnect(const pb::remote::Message& msg, RemoteClient* client) {
308   // Always sned the Clementine infos
309   emit SendClementineInfo();
310 
311   // Check if we should send the first data
312   if (!client->isDownloader()) {
313     if (!msg.request_connect().has_send_playlist_songs()  // legacy
314         || msg.request_connect().send_playlist_songs()) {
315       emit SendFirstData(true);
316     } else {
317       emit SendFirstData(false);
318     }
319   }
320 }
321 
SendPlaylists(const pb::remote::Message & msg)322 void IncomingDataParser::SendPlaylists(const pb::remote::Message& msg) {
323   if (!msg.has_request_playlists() ||
324       !msg.request_playlists().include_closed()) {
325     emit SendAllActivePlaylists();
326   } else {
327     emit SendAllPlaylists();
328   }
329 }
330 
OpenPlaylist(const pb::remote::Message & msg)331 void IncomingDataParser::OpenPlaylist(const pb::remote::Message& msg) {
332   emit Open(msg.request_open_playlist().playlist_id());
333 }
334 
ClosePlaylist(const pb::remote::Message & msg)335 void IncomingDataParser::ClosePlaylist(const pb::remote::Message& msg) {
336   emit Close(msg.request_close_playlist().playlist_id());
337 }
338 
RateSong(const pb::remote::Message & msg)339 void IncomingDataParser::RateSong(const pb::remote::Message& msg) {
340   double rating = (double)msg.request_rate_song().rating();
341   emit RateCurrentSong(rating);
342 }
343 
GlobalSearch(RemoteClient * client,const pb::remote::Message & msg)344 void IncomingDataParser::GlobalSearch(RemoteClient *client, const pb::remote::Message &msg) {
345   emit DoGlobalSearch(QStringFromStdString(msg.request_global_search().query()),
346                       client);
347 }
348 
CreateSongFromProtobuf(const pb::remote::SongMetadata & pb)349 Song IncomingDataParser::CreateSongFromProtobuf(const pb::remote::SongMetadata& pb){
350   Song song;
351   song.Init(QStringFromStdString(pb.title()),
352             QStringFromStdString(pb.artist()),
353             QStringFromStdString(pb.album()),
354             pb.length() * kNsecPerSec);
355 
356   song.set_albumartist(QStringFromStdString(pb.albumartist()));
357   song.set_genre(QStringFromStdString(pb.genre()));
358   song.set_year(QStringFromStdString(pb.pretty_year()).toInt());
359   song.set_track(pb.track());
360   song.set_disc(pb.disc());
361   song.set_url(QUrl(QStringFromStdString(pb.url())));
362   song.set_filesize(pb.file_size());
363   song.set_rating(pb.rating());
364   song.set_basefilename(QStringFromStdString(pb.filename()));
365   song.set_art_automatic(QStringFromStdString(pb.art_automatic()));
366   song.set_art_manual(QStringFromStdString(pb.art_manual()));
367   song.set_filetype(static_cast<Song::FileType>(pb.type()));
368 
369   return song;
370 }
371