discord_impl.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // SPDX-FileCopyrightText: 2018 Citra Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <chrono>
  4. #include <string>
  5. #include <QNetworkAccessManager>
  6. #include <QNetworkReply>
  7. #include <discord_rpc.h>
  8. #include <fmt/format.h>
  9. #include "common/common_types.h"
  10. #include "common/string_util.h"
  11. #include "core/core.h"
  12. #include "core/loader/loader.h"
  13. #include "yuzu/discord_impl.h"
  14. #include "yuzu/uisettings.h"
  15. namespace DiscordRPC {
  16. DiscordImpl::DiscordImpl(Core::System& system_) : system{system_} {
  17. DiscordEventHandlers handlers{};
  18. // The number is the client ID for yuzu, it's used for images and the
  19. // application name
  20. Discord_Initialize("712465656758665259", &handlers, 1, nullptr);
  21. }
  22. DiscordImpl::~DiscordImpl() {
  23. Discord_ClearPresence();
  24. Discord_Shutdown();
  25. }
  26. void DiscordImpl::Pause() {
  27. Discord_ClearPresence();
  28. }
  29. std::string DiscordImpl::GetGameString(const std::string& title) {
  30. // Convert to lowercase
  31. std::string icon_name = Common::ToLower(title);
  32. // Replace spaces with dashes
  33. std::replace(icon_name.begin(), icon_name.end(), ' ', '-');
  34. // Remove non-alphanumeric characters but keep dashes
  35. std::erase_if(icon_name, [](char c) { return !std::isalnum(c) && c != '-'; });
  36. // Remove dashes from the start and end of the string
  37. icon_name.erase(icon_name.begin(), std::find_if(icon_name.begin(), icon_name.end(),
  38. [](int ch) { return ch != '-'; }));
  39. icon_name.erase(
  40. std::find_if(icon_name.rbegin(), icon_name.rend(), [](int ch) { return ch != '-'; }).base(),
  41. icon_name.end());
  42. // Remove double dashes
  43. icon_name.erase(std::unique(icon_name.begin(), icon_name.end(),
  44. [](char a, char b) { return a == '-' && b == '-'; }),
  45. icon_name.end());
  46. return icon_name;
  47. }
  48. void DiscordImpl::UpdateGameStatus(bool use_default) {
  49. const std::string default_text = "yuzu is an emulator for the Nintendo Switch";
  50. const std::string default_image = "yuzu_logo";
  51. const std::string url = use_default ? default_image : game_url;
  52. s64 start_time = std::chrono::duration_cast<std::chrono::seconds>(
  53. std::chrono::system_clock::now().time_since_epoch())
  54. .count();
  55. DiscordRichPresence presence{};
  56. presence.largeImageKey = url.c_str();
  57. presence.largeImageText = game_title.c_str();
  58. presence.smallImageKey = default_image.c_str();
  59. presence.smallImageText = default_text.c_str();
  60. presence.state = game_title.c_str();
  61. presence.details = "Currently in game";
  62. presence.startTimestamp = start_time;
  63. Discord_UpdatePresence(&presence);
  64. }
  65. void DiscordImpl::Update() {
  66. const std::string default_text = "yuzu is an emulator for the Nintendo Switch";
  67. const std::string default_image = "yuzu_logo";
  68. if (system.IsPoweredOn()) {
  69. system.GetAppLoader().ReadTitle(game_title);
  70. // Used to format Icon URL for yuzu website game compatibility page
  71. std::string icon_name = GetGameString(game_title);
  72. game_url = fmt::format("https://yuzu-emu.org/images/game/boxart/{}.png", icon_name);
  73. QNetworkAccessManager* manager = new QNetworkAccessManager();
  74. QNetworkRequest request;
  75. request.setUrl(QUrl(QString::fromStdString(game_url)));
  76. request.setTransferTimeout(3000);
  77. QNetworkReply* rep = manager->get(request);
  78. QObject::connect(manager, &QNetworkAccessManager::finished,
  79. [this](QNetworkReply* reply) { UpdateGameStatus(reply->error()); });
  80. QObject::connect(manager, &QNetworkAccessManager::finished, manager,
  81. &QNetworkAccessManager::deleteLater);
  82. QObject::connect(manager, &QNetworkAccessManager::finished, rep,
  83. &QNetworkReply::deleteLater);
  84. return;
  85. }
  86. s64 start_time = std::chrono::duration_cast<std::chrono::seconds>(
  87. std::chrono::system_clock::now().time_since_epoch())
  88. .count();
  89. DiscordRichPresence presence{};
  90. presence.largeImageKey = default_image.c_str();
  91. presence.largeImageText = default_text.c_str();
  92. presence.details = "Currently not in game";
  93. presence.startTimestamp = start_time;
  94. Discord_UpdatePresence(&presence);
  95. }
  96. } // namespace DiscordRPC