From 4875d319dc04524aaab74673f2f232874ed8b302 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Wed, 12 Jun 2019 00:38:52 +0200 Subject: [PATCH] Add love button --- data/icons.qrc | 5 ++ data/icons/128x128/love.png | Bin 0 -> 5862 bytes data/icons/22x22/love.png | Bin 0 -> 1433 bytes data/icons/32x32/love.png | Bin 0 -> 1062 bytes data/icons/48x48/love.png | Bin 0 -> 1874 bytes data/icons/64x64/love.png | Bin 0 -> 2040 bytes src/core/mainwindow.cpp | 46 ++++++++++++-- src/core/mainwindow.h | 2 + src/core/mainwindow.ui | 49 ++++++++++++++- src/core/qtsystemtrayicon.cpp | 15 ++++- src/core/qtsystemtrayicon.h | 5 +- src/core/systemtrayicon.h | 4 +- src/globalshortcuts/globalshortcuts.cpp | 1 + src/globalshortcuts/globalshortcuts.h | 1 + src/scrobbler/audioscrobbler.cpp | 18 ++++-- src/scrobbler/audioscrobbler.h | 6 +- src/scrobbler/listenbrainzscrobbler.cpp | 11 ++-- src/scrobbler/listenbrainzscrobbler.h | 2 +- src/scrobbler/scrobblerservice.cpp | 5 +- src/scrobbler/scrobblerservice.h | 5 +- src/scrobbler/scrobblingapi20.cpp | 77 +++++++++++++++++++++--- src/scrobbler/scrobblingapi20.h | 4 +- src/settings/scrobblersettingspage.cpp | 2 + src/settings/scrobblersettingspage.ui | 7 +++ 24 files changed, 233 insertions(+), 32 deletions(-) create mode 100644 data/icons/128x128/love.png create mode 100644 data/icons/22x22/love.png create mode 100644 data/icons/32x32/love.png create mode 100644 data/icons/48x48/love.png create mode 100644 data/icons/64x64/love.png diff --git a/data/icons.qrc b/data/icons.qrc index bafe558fb..99068a035 100644 --- a/data/icons.qrc +++ b/data/icons.qrc @@ -87,6 +87,7 @@ icons/128x128/scrobble.png icons/128x128/scrobble-disabled.png icons/128x128/moodbar.png + icons/128x128/love.png icons/64x64/albums.png icons/64x64/alsa.png icons/64x64/application-exit.png @@ -174,6 +175,7 @@ icons/64x64/scrobble.png icons/64x64/scrobble-disabled.png icons/64x64/moodbar.png + icons/64x64/love.png icons/48x48/albums.png icons/48x48/alsa.png icons/48x48/application-exit.png @@ -264,6 +266,7 @@ icons/48x48/scrobble.png icons/48x48/scrobble-disabled.png icons/48x48/moodbar.png + icons/48x48/love.png icons/32x32/albums.png icons/32x32/alsa.png icons/32x32/application-exit.png @@ -355,6 +358,7 @@ icons/32x32/scrobble.png icons/32x32/scrobble-disabled.png icons/32x32/moodbar.png + icons/32x32/love.png icons/22x22/albums.png icons/22x22/alsa.png icons/22x22/application-exit.png @@ -446,5 +450,6 @@ icons/22x22/scrobble.png icons/22x22/scrobble-disabled.png icons/22x22/moodbar.png + icons/22x22/love.png diff --git a/data/icons/128x128/love.png b/data/icons/128x128/love.png new file mode 100644 index 0000000000000000000000000000000000000000..4dc1e7d74fb8bec28c9fe221d176cc7998b31e54 GIT binary patch literal 5862 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 F@jp-FF}VN$ literal 0 HcmV?d00001 diff --git a/data/icons/22x22/love.png b/data/icons/22x22/love.png new file mode 100644 index 0000000000000000000000000000000000000000..b6453bf86bba7ea06556c5c2ece7203a89c0fcc7 GIT binary patch literal 1433 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 zwUGx#-Cf$^`waction_toggle_scrobbling->setIcon(IconLoader::Load("scrobble-disabled", 22)); + ui_->action_toggle_scrobbling->setIcon(IconLoader::Load("scrobble-disabled")); + ui_->action_love->setIcon(IconLoader::Load("love")); // File view connections connect(file_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*))); @@ -419,6 +420,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co #endif connect(ui_->action_toggle_scrobbling, SIGNAL(triggered()), app_->scrobbler(), SLOT(ToggleScrobbling())); + connect(ui_->action_love, SIGNAL(triggered()), SLOT(Love())); connect(app_->scrobbler(), SIGNAL(ErrorMessage(QString)), SLOT(ShowErrorDialog(QString))); // Playlist view actions @@ -435,6 +437,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co ui_->pause_play_button->setDefaultAction(ui_->action_play_pause); ui_->stop_button->setDefaultAction(ui_->action_stop); ui_->button_scrobble->setDefaultAction(ui_->action_toggle_scrobbling); + ui_->button_love->setDefaultAction(ui_->action_love); ui_->playlist->SetActions(ui_->action_new_playlist, ui_->action_load_playlist, ui_->action_save_playlist, ui_->action_clear_playlist, ui_->action_next_playlist, /* These two actions aren't associated */ ui_->action_previous_playlist /* to a button but to the main window */ ); @@ -615,13 +618,14 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co connect(app_->scrobbler(), SIGNAL(ScrobblingEnabledChanged(bool)), SLOT(ScrobblingEnabledChanged(bool))); connect(app_->scrobbler(), SIGNAL(ScrobbleButtonVisibilityChanged(bool)), SLOT(ScrobbleButtonVisibilityChanged(bool))); + connect(app_->scrobbler(), SIGNAL(LoveButtonVisibilityChanged(bool)), SLOT(LoveButtonVisibilityChanged(bool))); #ifdef Q_OS_MACOS mac::SetApplicationHandler(this); #endif // Tray icon if (tray_icon_) { - tray_icon_->SetupMenu(ui_->action_previous_track, ui_->action_play_pause, ui_->action_stop, ui_->action_stop_after_this_track, ui_->action_next_track, ui_->action_mute, ui_->action_quit); + tray_icon_->SetupMenu(ui_->action_previous_track, ui_->action_play_pause, ui_->action_stop, ui_->action_stop_after_this_track, ui_->action_next_track, ui_->action_mute, ui_->action_love, ui_->action_quit); connect(tray_icon_, SIGNAL(PlayPause()), app_->player(), SLOT(PlayPause())); connect(tray_icon_, SIGNAL(SeekForward()), app_->player(), SLOT(SeekForward())); connect(tray_icon_, SIGNAL(SeekBackward()), app_->player(), SLOT(SeekBackward())); @@ -632,7 +636,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co } // Windows 7 thumbbar buttons - thumbbar_->SetActions(QList() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr); // spacer + thumbbar_->SetActions(QList() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love); #if (defined(Q_OS_MACOS) && defined(HAVE_SPARKLE)) // Add check for updates item to application menu. @@ -659,6 +663,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co connect(global_shortcuts_, SIGNAL(ShowOSD()), app_->player(), SLOT(ShowOSD())); connect(global_shortcuts_, SIGNAL(TogglePrettyOSD()), app_->player(), SLOT(TogglePrettyOSD())); connect(global_shortcuts_, SIGNAL(ToggleScrobbling()), app_->scrobbler(), SLOT(ToggleScrobbling())); + connect(global_shortcuts_, SIGNAL(Love()), app_->scrobbler(), SLOT(Love())); #endif // Fancy tabs @@ -725,6 +730,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co connect(app_->playlist_manager()->sequence(), SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)), osd_, SLOT(ShuffleModeChanged(PlaylistSequence::ShuffleMode))); ScrobbleButtonVisibilityChanged(app_->scrobbler()->ScrobbleButton()); + LoveButtonVisibilityChanged(app_->scrobbler()->LoveButton()); ScrobblingEnabledChanged(app_->scrobbler()->IsEnabled()); // Load settings @@ -913,6 +919,10 @@ void MainWindow::MediaStopped() { ui_->action_play_pause->setEnabled(true); + ui_->action_love->setEnabled(false); + ui_->button_love->setEnabled(false); + if (tray_icon_) tray_icon_->LoveStateChanged(false); + track_position_timer_->stop(); track_slider_timer_->stop(); ui_->track_slider->SetStopped(); @@ -925,6 +935,8 @@ void MainWindow::MediaStopped() { song_ = Song(); image_original_ = QImage(); + app_->scrobbler()->ClearPlaying(); + } void MainWindow::MediaPaused() { @@ -939,7 +951,9 @@ void MainWindow::MediaPaused() { track_position_timer_->stop(); track_slider_timer_->stop(); - if (tray_icon_) tray_icon_->SetPaused(); + if (tray_icon_) { + tray_icon_->SetPaused(); + } } @@ -971,6 +985,9 @@ void MainWindow::MediaPlaying() { if (app_->scrobbler()->IsEnabled() && playlist && !playlist->nowplaying() && item->Metadata().is_metadata_good() && item->Metadata().length_nanosec() > 0) { app_->scrobbler()->UpdateNowPlaying(item->Metadata()); playlist->set_nowplaying(true); + ui_->action_love->setEnabled(true); + ui_->button_love->setEnabled(true); + if (tray_icon_) tray_icon_->LoveStateChanged(true); } } @@ -2409,12 +2426,24 @@ void MainWindow::ScrobblingEnabledChanged(bool value) { } void MainWindow::ScrobbleButtonVisibilityChanged(bool value) { + ui_->button_scrobble->setVisible(value); ui_->action_toggle_scrobbling->setVisible(value); if (value) SetToggleScrobblingIcon(app_->scrobbler()->IsEnabled()); } +void MainWindow::LoveButtonVisibilityChanged(bool value) { + + if (value) + ui_->widget_love->show(); + else + ui_->widget_love->hide(); + + if (tray_icon_) tray_icon_->LoveVisibilityChanged(value); + +} + void MainWindow::SetToggleScrobblingIcon(bool value) { if (value) { @@ -2428,3 +2457,12 @@ void MainWindow::SetToggleScrobblingIcon(bool value) { } } + +void MainWindow::Love() { + + app_->scrobbler()->Love(); + ui_->button_love->setEnabled(false); + ui_->action_love->setEnabled(false); + if (tray_icon_) tray_icon_->LoveStateChanged(false); + +} diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index efacbbe78..f44b31600 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -255,6 +255,8 @@ signals: void ScrobblingEnabledChanged(bool value); void ScrobbleButtonVisibilityChanged(bool value); + void LoveButtonVisibilityChanged(bool value); + void Love(); private: diff --git a/src/core/mainwindow.ui b/src/core/mainwindow.ui index 712f19ee6..2dc57359a 100644 --- a/src/core/mainwindow.ui +++ b/src/core/mainwindow.ui @@ -178,6 +178,41 @@ + + + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + + + + true + + + + + + @@ -407,7 +442,7 @@ 0 0 1131 - 27 + 24 @@ -424,6 +459,7 @@ + @@ -528,6 +564,17 @@ Ctrl+Alt+V + + + false + + + Love + + + Ctrl+L + + &Clear playlist diff --git a/src/core/qtsystemtrayicon.cpp b/src/core/qtsystemtrayicon.cpp index ad63188b1..30750300c 100644 --- a/src/core/qtsystemtrayicon.cpp +++ b/src/core/qtsystemtrayicon.cpp @@ -131,7 +131,7 @@ bool QtSystemTrayIcon::eventFilter(QObject *object, QEvent *event) { } -void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit) { +void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *love, QAction *quit) { // Creating new actions and connecting them to old ones. // This allows us to use old actions without displaying shortcuts that can not be used when Strawberry's window is hidden @@ -147,6 +147,9 @@ void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop action_mute_->setChecked(mute->isChecked()); menu_->addSeparator(); + action_love_ = menu_->addAction(love->icon(), love->text(), love, SLOT(trigger())); + action_love_->setVisible(love->isVisible()); + action_love_->setEnabled(love->isEnabled()); menu_->addSeparator(); menu_->addAction(quit->icon(), quit->text(), quit, SLOT(trigger())); @@ -216,6 +219,8 @@ void QtSystemTrayIcon::SetStopped() { action_play_pause_->setEnabled(true); + action_love_->setEnabled(false); + } void QtSystemTrayIcon::MuteButtonStateChanged(bool value) { @@ -278,3 +283,11 @@ void QtSystemTrayIcon::SetNowPlaying(const Song &song, const QString &image_path void QtSystemTrayIcon::ClearNowPlaying() { tray_->setToolTip(app_name_); } + +void QtSystemTrayIcon::LoveVisibilityChanged(bool value) { + action_love_->setVisible(value); +} + +void QtSystemTrayIcon::LoveStateChanged(bool value) { + action_love_->setEnabled(value); +} diff --git a/src/core/qtsystemtrayicon.h b/src/core/qtsystemtrayicon.h index b2f914715..c6ab4ce5c 100644 --- a/src/core/qtsystemtrayicon.h +++ b/src/core/qtsystemtrayicon.h @@ -46,7 +46,7 @@ class QtSystemTrayIcon : public SystemTrayIcon { QtSystemTrayIcon(QObject *parent = nullptr); ~QtSystemTrayIcon(); - void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit); + void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *love, QAction *quit); bool IsVisible() const; void SetVisible(bool visible); @@ -65,6 +65,8 @@ class QtSystemTrayIcon : public SystemTrayIcon { void SetPlaying(bool enable_play_pause = false); void SetStopped(); void MuteButtonStateChanged(bool value); + void LoveVisibilityChanged(bool value); + void LoveStateChanged(bool value); // QObject bool eventFilter(QObject *, QEvent *); @@ -84,6 +86,7 @@ class QtSystemTrayIcon : public SystemTrayIcon { QAction *action_stop_; QAction *action_stop_after_this_track_; QAction *action_mute_; + QAction *action_love_; #ifndef Q_OS_WIN QString de_; diff --git a/src/core/systemtrayicon.h b/src/core/systemtrayicon.h index 1d432daaf..a53a452a8 100644 --- a/src/core/systemtrayicon.h +++ b/src/core/systemtrayicon.h @@ -39,7 +39,7 @@ class SystemTrayIcon : public QObject { SystemTrayIcon(QObject *parent = nullptr); // Called once to create the icon's context menu - virtual void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit) = 0; + virtual void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *love, QAction *quit) = 0; virtual bool IsVisible() const { return true; } virtual void SetVisible(bool visible) {} @@ -60,6 +60,8 @@ class SystemTrayIcon : public QObject { virtual void SetPaused(); virtual void SetPlaying(bool enable_play_pause = false); virtual void SetStopped(); + virtual void LoveVisibilityChanged(bool value) {} + virtual void LoveStateChanged(bool value) {} virtual void MuteButtonStateChanged(bool value) {} signals: diff --git a/src/globalshortcuts/globalshortcuts.cpp b/src/globalshortcuts/globalshortcuts.cpp index 09bcf3cfe..ca83bbadc 100644 --- a/src/globalshortcuts/globalshortcuts.cpp +++ b/src/globalshortcuts/globalshortcuts.cpp @@ -80,6 +80,7 @@ GlobalShortcuts::GlobalShortcuts(QWidget *parent) AddShortcut("shuffle_mode", "Change shuffle mode", SIGNAL(CycleShuffleMode())); AddShortcut("repeat_mode", "Change repeat mode", SIGNAL(CycleRepeatMode())); AddShortcut("toggle_scrobbling", "Enable/disable scrobbling", SIGNAL(ToggleScrobbling())); + AddShortcut("love", "Love", SIGNAL(Love())); // Create backends - these do the actual shortcut registration #ifdef HAVE_DBUS diff --git a/src/globalshortcuts/globalshortcuts.h b/src/globalshortcuts/globalshortcuts.h index 104abc45d..aba480d82 100644 --- a/src/globalshortcuts/globalshortcuts.h +++ b/src/globalshortcuts/globalshortcuts.h @@ -85,6 +85,7 @@ class GlobalShortcuts : public QWidget { void CycleRepeatMode(); void RemoveCurrentSong(); void ToggleScrobbling(); + void Love(); private: void AddShortcut(const QString &id, const QString &name, const char *signal, const QKeySequence &default_key = QKeySequence(0)); diff --git a/src/scrobbler/audioscrobbler.cpp b/src/scrobbler/audioscrobbler.cpp index 5a54571a9..99ef30062 100644 --- a/src/scrobbler/audioscrobbler.cpp +++ b/src/scrobbler/audioscrobbler.cpp @@ -49,6 +49,7 @@ AudioScrobbler::AudioScrobbler(Application *app, QObject *parent) : enabled_(false), offline_(false), scrobble_button_(false), + love_button_(false), submit_delay_(0) { @@ -69,11 +70,13 @@ void AudioScrobbler::ReloadSettings() { enabled_ = s.value("enabled", false).toBool(); offline_ = s.value("offline", false).toBool(); scrobble_button_ = s.value("scrobble_button", false).toBool(); + love_button_ = s.value("love_button", false).toBool(); submit_delay_ = s.value("submit", 0).toInt(); s.endGroup(); emit ScrobblingEnabledChanged(enabled_); emit ScrobbleButtonVisibilityChanged(scrobble_button_); + emit LoveButtonVisibilityChanged(love_button_); for (ScrobblerService *service : scrobbler_services_->List()) { service->ReloadSettings(); @@ -116,25 +119,32 @@ void AudioScrobbler::ShowConfig() { } void AudioScrobbler::UpdateNowPlaying(const Song &song) { - qLog(Debug) << "Sending now playing for song" << song.title(); + qLog(Debug) << "Sending now playing for song" << song.artist() << song.album() << song.title(); for (ScrobblerService *service : scrobbler_services_->List()) { if (!service->IsEnabled()) continue; service->UpdateNowPlaying(song); } } +void AudioScrobbler::ClearPlaying() { + for (ScrobblerService *service : scrobbler_services_->List()) { + if (!service->IsEnabled()) continue; + service->ClearPlaying(); + } +} + void AudioScrobbler::Scrobble(const Song &song, const int scrobble_point) { - qLog(Debug) << "Scrobbling song" << QString("") + song.title() + QString("") << "at" << scrobble_point; + qLog(Debug) << "Scrobbling song" << song.artist() << song.album() << song.title() << "at" << scrobble_point; for (ScrobblerService *service : scrobbler_services_->List()) { if (!service->IsEnabled()) continue; service->Scrobble(song); } } -void AudioScrobbler::Love(const Song &song) { +void AudioScrobbler::Love() { for (ScrobblerService *service : scrobbler_services_->List()) { if (!service->IsEnabled() || !service->IsAuthenticated()) continue; - service->Love(song); + service->Love(); } } diff --git a/src/scrobbler/audioscrobbler.h b/src/scrobbler/audioscrobbler.h index 38b691410..ed0c6ef44 100644 --- a/src/scrobbler/audioscrobbler.h +++ b/src/scrobbler/audioscrobbler.h @@ -46,11 +46,12 @@ class AudioScrobbler : public QObject { bool IsEnabled() const { return enabled_; } bool IsOffline() const { return offline_; } bool ScrobbleButton() const { return scrobble_button_; } + bool LoveButton() const { return love_button_; } int SubmitDelay() const { return submit_delay_; } void UpdateNowPlaying(const Song &song); + void ClearPlaying(); void Scrobble(const Song &song, const int scrobble_point); - void Love(const Song &song); void ShowConfig(); void ConnectError(); @@ -65,6 +66,7 @@ class AudioScrobbler : public QObject { void ToggleScrobbling(); void ToggleOffline(); void Submit(); + void Love(); void WriteCache(); void ErrorReceived(QString); @@ -73,6 +75,7 @@ class AudioScrobbler : public QObject { void ScrobblingEnabledChanged(bool value); void ScrobblingOfflineChanged(bool value); void ScrobbleButtonVisibilityChanged(bool value); + void LoveButtonVisibilityChanged(bool value); private: @@ -82,6 +85,7 @@ class AudioScrobbler : public QObject { bool enabled_; bool offline_; bool scrobble_button_; + bool love_button_; int submit_delay_; }; diff --git a/src/scrobbler/listenbrainzscrobbler.cpp b/src/scrobbler/listenbrainzscrobbler.cpp index e83497f55..3868174a0 100644 --- a/src/scrobbler/listenbrainzscrobbler.cpp +++ b/src/scrobbler/listenbrainzscrobbler.cpp @@ -340,7 +340,7 @@ void ListenBrainzScrobbler::UpdateNowPlaying(const Song &song) { album = album.remove(Song::kAlbumRemoveMisc); QJsonObject object_track_metadata; - object_track_metadata.insert("artist_name", QJsonValue::fromVariant(song.artist())); + object_track_metadata.insert("artist_name", QJsonValue::fromVariant(song.effective_albumartist())); object_track_metadata.insert("release_name", QJsonValue::fromVariant(album)); object_track_metadata.insert("track_name", QJsonValue::fromVariant(song.title())); @@ -394,6 +394,10 @@ void ListenBrainzScrobbler::UpdateNowPlayingRequestFinished(QNetworkReply *reply } +void ListenBrainzScrobbler::ClearPlaying() { + song_playing_ = Song(); +} + void ListenBrainzScrobbler::Scrobble(const Song &song) { if (song.id() != song_playing_.id() || song.url() != song_playing_.url() || !song.is_metadata_good()) return; @@ -450,7 +454,8 @@ void ListenBrainzScrobbler::Submit() { QJsonObject object_listen; object_listen.insert("listened_at", QJsonValue::fromVariant(item->timestamp_)); QJsonObject object_track_metadata; - object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->artist_)); + if (item->albumartist_.isEmpty()) object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->artist_)); + else object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->albumartist_)); object_track_metadata.insert("release_name", QJsonValue::fromVariant(item->album_)); object_track_metadata.insert("track_name", QJsonValue::fromVariant(item->song_)); object_listen.insert("track_metadata", object_track_metadata); @@ -508,8 +513,6 @@ void ListenBrainzScrobbler::ScrobbleRequestFinished(QNetworkReply *reply, QList< } -void ListenBrainzScrobbler::Love(const Song &song) {} - void ListenBrainzScrobbler::AuthError(QString error) { emit AuthenticationComplete(false, error); } diff --git a/src/scrobbler/listenbrainzscrobbler.h b/src/scrobbler/listenbrainzscrobbler.h index b776dee5c..ee0246126 100644 --- a/src/scrobbler/listenbrainzscrobbler.h +++ b/src/scrobbler/listenbrainzscrobbler.h @@ -65,8 +65,8 @@ class ListenBrainzScrobbler : public ScrobblerService { void ShowConfig(); void Submit(); void UpdateNowPlaying(const Song &song); + void ClearPlaying(); void Scrobble(const Song &song); - void Love(const Song &song); signals: void AuthenticationComplete(bool success, QString error = QString()); diff --git a/src/scrobbler/scrobblerservice.cpp b/src/scrobbler/scrobblerservice.cpp index 482214dd5..6a6a82ef6 100644 --- a/src/scrobbler/scrobblerservice.cpp +++ b/src/scrobbler/scrobblerservice.cpp @@ -30,7 +30,7 @@ ScrobblerService::ScrobblerService(const QString &name, Application *app, QObject *parent) : QObject(parent), name_(name) {} -QJsonObject ScrobblerService::ExtractJsonObj(const QByteArray &data) { +QJsonObject ScrobblerService::ExtractJsonObj(const QByteArray &data, const bool ignore_empty) { QJsonParseError error; QJsonDocument json_doc = QJsonDocument::fromJson(data, &error); @@ -49,7 +49,8 @@ QJsonObject ScrobblerService::ExtractJsonObj(const QByteArray &data) { } QJsonObject json_obj = json_doc.object(); if (json_obj.isEmpty()) { - Error("Received empty Json object.", json_doc); + if (!ignore_empty) + Error("Received empty Json object.", json_doc); return QJsonObject(); } diff --git a/src/scrobbler/scrobblerservice.h b/src/scrobbler/scrobblerservice.h index 2b59c31b4..838600859 100644 --- a/src/scrobbler/scrobblerservice.h +++ b/src/scrobbler/scrobblerservice.h @@ -49,8 +49,9 @@ class ScrobblerService : public QObject { virtual bool IsAuthenticated() const { return false; } virtual void UpdateNowPlaying(const Song &song) = 0; + virtual void ClearPlaying() = 0; virtual void Scrobble(const Song &song) = 0; - virtual void Love(const Song &song) = 0; + virtual void Love() {} virtual void Error(QString error, QVariant debug = QVariant()) = 0; virtual void DoSubmit() = 0; @@ -61,7 +62,7 @@ class ScrobblerService : public QObject { typedef QPair EncodedParam; typedef QList ParamList; - QJsonObject ExtractJsonObj(const QByteArray &data); + QJsonObject ExtractJsonObj(const QByteArray &data, const bool ignore_empty = false); public slots: virtual void Submit() = 0; diff --git a/src/scrobbler/scrobblingapi20.cpp b/src/scrobbler/scrobblingapi20.cpp index 7b74a37d3..1795215e5 100644 --- a/src/scrobbler/scrobblingapi20.cpp +++ b/src/scrobbler/scrobblingapi20.cpp @@ -414,6 +414,7 @@ void ScrobblingAPI20::UpdateNowPlaying(const Song &song) { << Param("artist", song.artist()) << Param("track", song.title()) << Param("album", album); + if (!song.albumartist().isEmpty()) params << Param("albumArtist", song.albumartist()); QNetworkReply *reply = CreateRequest(params); NewClosure(reply, SIGNAL(finished()), this, SLOT(UpdateNowPlayingRequestFinished(QNetworkReply*)), reply); @@ -449,6 +450,10 @@ void ScrobblingAPI20::UpdateNowPlayingRequestFinished(QNetworkReply *reply) { } +void ScrobblingAPI20::ClearPlaying() { + song_playing_ = Song(); +} + void ScrobblingAPI20::Scrobble(const Song &song) { if (song.id() != song_playing_.id() || song.url() != song_playing_.url() || !song.is_metadata_good()) return; @@ -488,14 +493,13 @@ void ScrobblingAPI20::DoSubmit() { void ScrobblingAPI20::Submit() { - qLog(Debug) << __PRETTY_FUNCTION__ << name_; - submitted_ = false; if (!IsEnabled() || !IsAuthenticated() || app_->scrobbler()->IsOffline()) return; - ParamList params = ParamList() - << Param("method", "track.scrobble"); + qLog(Debug) << name_ << "Submitting scrobbles."; + + ParamList params = ParamList() << Param("method", "track.scrobble"); int i(0); QList list; @@ -820,18 +824,73 @@ void ScrobblingAPI20::SingleScrobbleRequestFinished(QNetworkReply *reply, quint6 } -void ScrobblingAPI20::Love(const Song &song) { +void ScrobblingAPI20::Love() { + + if (!song_playing_.is_valid() || !song_playing_.is_metadata_good()) return; if (!IsAuthenticated()) app_->scrobbler()->ShowConfig(); + qLog(Debug) << name_ << "Sending love for song" << song_playing_.artist() << song_playing_.album() << song_playing_.title(); + ParamList params = ParamList() << Param("method", "track.love") - << Param("artist", song.artist()) - << Param("track", song.title()) - << Param("album", song.album()); + << Param("artist", song_playing_.artist()) + << Param("track", song_playing_.title()) + << Param("album", song_playing_.album()); + if (!song_playing_.albumartist().isEmpty()) params << Param("albumArtist", song_playing_.albumartist()); QNetworkReply *reply = CreateRequest(params); - NewClosure(reply, SIGNAL(finished()), this, SLOT(RequestFinished(QNetworkReply*)), reply); + NewClosure(reply, SIGNAL(finished()), this, SLOT(LoveRequestFinished(QNetworkReply*)), reply); + +} + +void ScrobblingAPI20::LoveRequestFinished(QNetworkReply *reply) { + + reply->deleteLater(); + + QByteArray data = GetReplyData(reply); + if (data.isEmpty()) { + return; + } + + QJsonObject json_obj = ExtractJsonObj(data, true); + if (json_obj.isEmpty()) { + return; + } + + if (json_obj.contains("error")) { + QJsonValue json_value = json_obj["error"]; + if (!json_value.isObject()) { + Error("Error is not on object."); + return; + } + QJsonObject json_obj_error = json_value.toObject(); + if (json_obj_error.isEmpty()) { + Error("Received empty json error object.", json_obj); + return; + } + if (json_obj_error.contains("code") && json_obj_error.contains("#text")) { + int code = json_obj_error["code"].toInt(); + QString text = json_obj_error["#text"].toString(); + QString error_reason = QString("%1 (%2)").arg(text).arg(code); + Error(error_reason); + return; + } + } + + if (json_obj.contains("lfm")) { + QJsonValue json_value = json_obj["lfm"]; + if (json_value.isObject()) { + QJsonObject json_obj_lfm = json_value.toObject(); + if (json_obj_lfm.contains("status")) { + QString status = json_obj_lfm["status"].toString(); + qLog(Debug) << name_ << "Received love status:" << status; + return; + } + } + } + + qLog(Debug) << name_ << json_obj; } diff --git a/src/scrobbler/scrobblingapi20.h b/src/scrobbler/scrobblingapi20.h index 9748278e5..7ecffbcb1 100644 --- a/src/scrobbler/scrobblingapi20.h +++ b/src/scrobbler/scrobblingapi20.h @@ -69,9 +69,10 @@ class ScrobblingAPI20 : public ScrobblerService { void Authenticate(const bool https = false); void Logout(); void UpdateNowPlaying(const Song &song); + void ClearPlaying(); void Scrobble(const Song &song); void Submit(); - void Love(const Song &song); + void Love(); signals: void AuthenticationComplete(bool success, QString error = QString()); @@ -85,6 +86,7 @@ class ScrobblingAPI20 : public ScrobblerService { void UpdateNowPlayingRequestFinished(QNetworkReply *reply); void ScrobbleRequestFinished(QNetworkReply *reply, QList); void SingleScrobbleRequestFinished(QNetworkReply *reply, quint64 timestamp); + void LoveRequestFinished(QNetworkReply *reply); private: diff --git a/src/settings/scrobblersettingspage.cpp b/src/settings/scrobblersettingspage.cpp index 46a46072d..37911089c 100644 --- a/src/settings/scrobblersettingspage.cpp +++ b/src/settings/scrobblersettingspage.cpp @@ -81,6 +81,7 @@ void ScrobblerSettingsPage::Load() { ui_->checkbox_enable->setChecked(scrobbler_->IsEnabled()); ui_->checkbox_scrobble_button->setChecked(scrobbler_->ScrobbleButton()); + ui_->checkbox_love_button->setChecked(scrobbler_->LoveButton()); ui_->checkbox_offline->setChecked(scrobbler_->IsOffline()); ui_->spinbox_submit->setValue(scrobbler_->SubmitDelay()); @@ -104,6 +105,7 @@ void ScrobblerSettingsPage::Save() { s.beginGroup(kSettingsGroup); s.setValue("enabled", ui_->checkbox_enable->isChecked()); s.setValue("scrobble_button", ui_->checkbox_scrobble_button->isChecked()); + s.setValue("love_button", ui_->checkbox_love_button->isChecked()); s.setValue("offline", ui_->checkbox_offline->isChecked()); s.setValue("submit", ui_->spinbox_submit->value()); s.endGroup(); diff --git a/src/settings/scrobblersettingspage.ui b/src/settings/scrobblersettingspage.ui index 24da14013..cb937a416 100644 --- a/src/settings/scrobblersettingspage.ui +++ b/src/settings/scrobblersettingspage.ui @@ -51,6 +51,13 @@ + + + + Show love button + + +