discord_impl.cpp 4.1 KB

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