From d5f7a4b8837b552a7dc4690c3d4b3e1d89b444b3 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 30 Mar 2025 00:06:05 +0100 Subject: [PATCH] RichPresence: Formatting and add settings reload --- src/core/mainwindow.cpp | 18 +++- src/core/mainwindow.h | 11 +- src/discord/richpresence.cpp | 119 ++++++++++++--------- src/discord/richpresence.h | 19 ++-- src/main.cpp | 2 +- src/settings/notificationssettingspage.cpp | 2 +- 6 files changed, 109 insertions(+), 62 deletions(-) diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index d3faba61f..9b3d6eddf 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -228,6 +228,10 @@ # include #endif // HAVE_QTSPARKLE +#ifdef HAVE_DISCORD_RPC + #include "discord/richpresence.h" +#endif + using std::make_unique; using std::make_shared; using namespace std::chrono_literals; @@ -275,7 +279,13 @@ constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle- } // namespace #endif // HAVE_QTSPARKLE -MainWindow::MainWindow(Application *app, SharedPtr tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent) +MainWindow::MainWindow(Application *app, + SharedPtr tray_icon, OSDBase *osd, +#ifdef HAVE_DISCORD_RPC + discord::RichPresence *discord_rich_presence, +#endif + const CommandlineOptions &options, + QWidget *parent) : QMainWindow(parent), ui_(new Ui_MainWindow), #ifdef Q_OS_WIN32 @@ -284,6 +294,9 @@ MainWindow::MainWindow(Application *app, SharedPtr tray_icon, OS app_(app), tray_icon_(tray_icon), osd_(osd), +#ifdef HAVE_DISCORD_RPC + discord_rich_presence_(discord_rich_presence), +#endif console_([app, this]() { Console *console = new Console(app->database()); QObject::connect(console, &Console::Error, this, &MainWindow::ShowErrorDialog); @@ -1317,6 +1330,9 @@ void MainWindow::ReloadAllSettings() { qobuz_view_->ReloadSettings(); qobuz_view_->search_view()->ReloadSettings(); #endif +#ifdef HAVE_DISCORD_RPC + discord_rich_presence_->ReloadSettings(); +#endif } diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index 406b270fd..77610344a 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -99,11 +99,17 @@ class AddStreamDialog; class LastFMImportDialog; class RadioViewContainer; +#ifdef HAVE_DISCORD_RPC +namespace discord { +class RichPresence; +} +#endif + class MainWindow : public QMainWindow, public PlatformInterface { Q_OBJECT public: - explicit MainWindow(Application *app, SharedPtr tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent = nullptr); + explicit MainWindow(Application *app, SharedPtr tray_icon, OSDBase *osd, discord::RichPresence *discord_rich_presence, const CommandlineOptions &options, QWidget *parent = nullptr); ~MainWindow() override; void SetHiddenInTray(const bool hidden); @@ -296,6 +302,9 @@ class MainWindow : public QMainWindow, public PlatformInterface { Application *app_; SharedPtr tray_icon_; OSDBase *osd_; +#ifdef HAVE_DISCORD_RPC + discord::RichPresence *discord_rich_presence_; +#endif Lazy about_dialog_; Lazy console_; Lazy edit_tag_dialog_; diff --git a/src/discord/richpresence.cpp b/src/discord/richpresence.cpp index 32dbfcf13..4d120bd99 100644 --- a/src/discord/richpresence.cpp +++ b/src/discord/richpresence.cpp @@ -16,23 +16,27 @@ * */ -#include "richpresence.h" - -#include "core/logging.h" -#include "core/player.h" -#include "core/settings.h" -#include "engine/enginebase.h" -#include "constants/notificationssettings.h" - #include -namespace { +#include +#include +#include +#include "constants/timeconstants.h" +#include "constants/notificationssettings.h" +#include "core/logging.h" +#include "core/settings.h" +#include "core/song.h" +#include "core/player.h" +#include "engine/enginebase.h" +#include "playlist/playlistmanager.h" +#include "richpresence.h" + +namespace { constexpr char kDiscordApplicationId[] = "1352351827206733974"; constexpr char kStrawberryIconResourceName[] = "embedded_cover"; constexpr char kStrawberryIconDescription[] = "Strawberry Music Player"; constexpr qint64 kDiscordPresenceUpdateRateLimitMs = 2000; - } // namespace using namespace discord_rpc; @@ -47,74 +51,86 @@ RichPresence::RichPresence(const SharedPtr player, playlist_manager_(playlist_manager), activity_({ {}, {}, {}, 0, 0, 0 }), send_presence_timestamp_(0), - is_enabled_(false) { - Discord_Initialize(kDiscordApplicationId, nullptr, true, nullptr); + enabled_(false) { + + Discord_Initialize(kDiscordApplicationId, nullptr, 1, nullptr); QObject::connect(&*player_->engine(), &EngineBase::StateChanged, this, &RichPresence::EngineStateChanged); QObject::connect(&*playlist_manager_, &PlaylistManager::CurrentSongChanged, this, &RichPresence::CurrentSongChanged); QObject::connect(&*player_, &Player::Seeked, this, &RichPresence::Seeked); + + ReloadSettings(); + } RichPresence::~RichPresence() { Discord_Shutdown(); } -void RichPresence::EngineStateChanged(EngineBase::State newState) { - if (newState == EngineBase::State::Playing) { - SetTimestamp(player_->engine()->position_nanosec() / 1e3); +void RichPresence::ReloadSettings() { + + Settings s; + s.beginGroup(DiscordRPCSettings::kSettingsGroup); + const bool enabled = s.value(DiscordRPCSettings::kEnabled, false).toBool(); + s.endGroup(); + + if (enabled_ && !enabled) { + Discord_ClearPresence(); + } + + enabled_ = enabled; + +} + +void RichPresence::EngineStateChanged(const EngineBase::State state) { + + if (state == EngineBase::State::Playing) { + SetTimestamp(player_->engine()->position_nanosec() / kNsecPerSec); SendPresenceUpdate(); } - else + else { Discord_ClearPresence(); + } + } void RichPresence::CurrentSongChanged(const Song &song) { - SetTimestamp(0); - activity_.length_secs = song.length_nanosec() / 1e9; + + SetTimestamp(0LL); + activity_.length_secs = song.length_nanosec() / kNsecPerSec; activity_.title = song.title(); activity_.artist = song.artist(); activity_.album = song.album(); SendPresenceUpdate(); -} -void RichPresence::CheckEnabled() { - Settings s; - s.beginGroup(DiscordRPCSettings::kSettingsGroup); - - is_enabled_ = s.value(DiscordRPCSettings::kEnabled).toBool(); - - s.endGroup(); - - if (!is_enabled_) - Discord_ClearPresence(); } void RichPresence::SendPresenceUpdate() { - CheckEnabled(); - if (!is_enabled_) - return; - qint64 nowTimestamp = QDateTime::currentMSecsSinceEpoch(); - if (nowTimestamp - send_presence_timestamp_ < kDiscordPresenceUpdateRateLimitMs) { - qLog(Debug) << "Not sending rich presence due to rate limit of " << kDiscordPresenceUpdateRateLimitMs << "ms"; + if (!enabled_) { return; } - send_presence_timestamp_ = nowTimestamp; + const qint64 current_timestamp = QDateTime::currentMSecsSinceEpoch(); + if (current_timestamp - send_presence_timestamp_ < kDiscordPresenceUpdateRateLimitMs) { + qLog(Info) << "Not sending rich presence due to rate limit of" << kDiscordPresenceUpdateRateLimitMs << "ms"; + return; + } - ::DiscordRichPresence presence_data; + send_presence_timestamp_ = current_timestamp; + + ::DiscordRichPresence presence_data{}; memset(&presence_data, 0, sizeof(presence_data)); - QByteArray title; - QByteArray artist; - QByteArray album; - - presence_data.type = 2 /* Listening */; + presence_data.type = 2; // Listening presence_data.largeImageKey = kStrawberryIconResourceName; presence_data.smallImageKey = kStrawberryIconResourceName; presence_data.smallImageText = kStrawberryIconDescription; - presence_data.instance = false; + presence_data.instance = 0; + QByteArray artist; + QByteArray album; + QByteArray title; if (!activity_.artist.isEmpty()) { artist = activity_.artist.toUtf8(); artist.prepend(tr("by ").toUtf8()); @@ -130,21 +146,22 @@ void RichPresence::SendPresenceUpdate() { title = activity_.title.toUtf8(); presence_data.details = title.constData(); - const qint64 startTimestamp = activity_.start_timestamp - activity_.seek_secs; + const qint64 start_timestamp = activity_.start_timestamp - activity_.seek_secs; - presence_data.startTimestamp = startTimestamp; - presence_data.endTimestamp = startTimestamp + activity_.length_secs; + presence_data.startTimestamp = start_timestamp; + presence_data.endTimestamp = start_timestamp + activity_.length_secs; Discord_UpdatePresence(&presence_data); + } -void RichPresence::SetTimestamp(const qint64 seekMicroseconds) { - activity_.start_timestamp = time(nullptr); - activity_.seek_secs = seekMicroseconds / 1e6; +void RichPresence::SetTimestamp(const qint64 seconds) { + activity_.start_timestamp = QDateTime::currentSecsSinceEpoch(); + activity_.seek_secs = seconds; } -void RichPresence::Seeked(const qint64 microseconds) { - SetTimestamp(microseconds); +void RichPresence::Seeked(const qint64 seek_microseconds) { + SetTimestamp(seek_microseconds / 1000LL); SendPresenceUpdate(); } diff --git a/src/discord/richpresence.h b/src/discord/richpresence.h index 58d1e2ed3..56e29a90f 100644 --- a/src/discord/richpresence.h +++ b/src/discord/richpresence.h @@ -22,10 +22,15 @@ #include "config.h" #include +#include -#include "core/player.h" -#include "playlist/playlistmanager.h" #include "includes/shared_ptr.h" +#include "core/player.h" +#include "engine/enginebase.h" + +class Song; +class Player; +class PlaylistManager; namespace discord { @@ -38,17 +43,17 @@ class RichPresence : public QObject { QObject *parent = nullptr); ~RichPresence(); + void ReloadSettings(); void Stop(); private Q_SLOTS: - void EngineStateChanged(EngineBase::State newState); + void EngineStateChanged(const EngineBase::State state); void CurrentSongChanged(const Song &song); - void Seeked(const qint64 microseconds); + void Seeked(const qint64 seek_microseconds); private: - void CheckEnabled(); void SendPresenceUpdate(); - void SetTimestamp(const qint64 seekMicroseconds = 0); + void SetTimestamp(const qint64 seconds = 0); const SharedPtr player_; const SharedPtr playlist_manager_; @@ -62,7 +67,7 @@ class RichPresence : public QObject { qint64 seek_secs; } activity_; qint64 send_presence_timestamp_; - bool is_enabled_; + bool enabled_; }; } // namespace discord diff --git a/src/main.cpp b/src/main.cpp index 5ef538254..326750de6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -323,7 +323,7 @@ int main(int argc, char *argv[]) { #endif // Window - MainWindow w(&app, tray_icon, &osd, options); + MainWindow w(&app, tray_icon, &osd, &discord_rich_presence, options); #ifdef Q_OS_MACOS mac::EnableFullScreen(w); diff --git a/src/settings/notificationssettingspage.cpp b/src/settings/notificationssettingspage.cpp index 37c6ca984..5083b5a11 100644 --- a/src/settings/notificationssettingspage.cpp +++ b/src/settings/notificationssettingspage.cpp @@ -208,7 +208,7 @@ void NotificationsSettingsPage::Load() { // Discord s.beginGroup(DiscordRPCSettings::kSettingsGroup); - ui_->richpresence_enabled->setChecked(s.value(DiscordRPCSettings::kEnabled).toBool()); + ui_->richpresence_enabled->setChecked(s.value(DiscordRPCSettings::kEnabled, false).toBool()); s.endGroup(); UpdatePopupVisible();