diff --git a/settings.json b/settings.json index 8f15c36..f2f3790 100644 --- a/settings.json +++ b/settings.json @@ -1,31 +1,33 @@ { + "any_other": false, "apps": [ { + "client_id": "1245257240890310686", + "enabled": true, "name": "Apple Music", "process_names": [ "AppleMusic.exe" ], - "enabled": true, - "search_endpoint": "https://music.apple.com/search?term=", - "client_id": "1245257240890310686" + "search_endpoint": "https://music.apple.com/search?term=" }, { + "client_id": "1245257414715113573", + "enabled": true, "name": "Spotify", "process_names": [ "Spotify.exe" ], - "enabled": true, - "search_endpoint": "https://open.spotify.com/search/", - "client_id": "1245257414715113573" + "search_endpoint": "https://open.spotify.com/search/" }, { + "client_id": "1245257493966225488", + "enabled": true, "name": "Tidal", "process_names": [ "TIDAL.exe" ], - "enabled": true, - "search_endpoint": "https://listen.tidal.com/search?q=", - "client_id": "1245257493966225488" + "search_endpoint": "https://listen.tidal.com/search?q=" } - ] + ], + "autostart": false } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8b1673c..71c5ad6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,11 +16,13 @@ std::string lastPlayingSong = ""; std::string lastMediaSource = ""; +std::string currentSongTitle = ""; void handleRPCTasks() { while (true) { DiscordEventHandlers discordHandler{}; - Discord_Initialize(utils::getClientID(lastMediaSource).c_str(), &discordHandler); + auto app = utils::getApp(lastMediaSource); + Discord_Initialize(app.clientId.c_str(), &discordHandler); if (Discord_IsConnected()) break; } @@ -39,14 +41,15 @@ void handleMediaTasks() { std::this_thread::sleep_for(std::chrono::seconds(1)); auto mediaInformation = backend::getMediaInformation(); if (!mediaInformation) { + currentSongTitle = ""; Discord_ClearPresence(); // Nothing is playing rn, clear presence continue; } if (mediaInformation->paused) { lastPlayingSong = ""; - Discord_ClearPresence(); // TODO: allow user to keep presence when paused(because for - // some reason some people want this) + currentSongTitle = ""; + Discord_ClearPresence(); continue; } @@ -57,6 +60,7 @@ void handleMediaTasks() { continue; lastPlayingSong = currentlyPlayingSong; + currentSongTitle = mediaInformation->songArtist + " - " + mediaInformation->songTitle; std::string currentMediaSource = mediaInformation->playbackSource; @@ -65,7 +69,13 @@ void handleMediaTasks() { Discord_Shutdown(); } // reinitialize with new client id - std::string serviceName = utils::getAppName(lastMediaSource); + auto app = utils::getApp(lastMediaSource); + + if (!app.enabled) { + Discord_ClearPresence(); + continue; + } + std::string serviceName = app.appName; std::string activityState = "by " + mediaInformation->songArtist; DiscordRichPresence activity{}; @@ -90,7 +100,7 @@ void handleMediaTasks() { activity.startTimestamp = time(nullptr) - (mediaInformation->songElapsedTime / 1000); activity.endTimestamp = time(nullptr) + (remainingTime / 1000); } - std::string endpointURL = utils::getSearchEndpoint(lastMediaSource); + std::string endpointURL = app.searchEndpoint; std::string searchQuery = mediaInformation->songTitle + " " + mediaInformation->songArtist; std::string buttonName = "Search on " + serviceName; @@ -115,7 +125,7 @@ public: protected: virtual wxMenu* CreatePopupMenu() override { wxMenu* menu = new wxMenu; - menu->Append(10004, _("Not Playing")); // TODO: make this dynamic + menu->Append(10004, _(currentSongTitle == "" ? "Not Playing" : currentSongTitle)); // TODO: make this dynamic menu->Enable(10004, false); menu->AppendSeparator(); menu->Append(10001, _("Settings")); @@ -168,14 +178,33 @@ public: wxBoxSizer* appCheckboxContainer; appCheckboxContainer = new wxBoxSizer(wxVERTICAL); - auto apps = utils::getAllApps(); + auto settings = utils::getSettings(); - for (auto app : apps) { + for (auto app : settings.apps) { auto checkbox = new wxCheckBox(this, wxID_ANY, _(app.appName), wxDefaultPosition, wxDefaultSize, 0); + checkbox->SetValue(app.enabled); + checkbox->SetClientData(new utils::App(app)); + checkbox->Bind(wxEVT_CHECKBOX, [checkbox](wxCommandEvent& event) { + bool isChecked = checkbox->IsChecked(); + utils::App* appData = static_cast(checkbox->GetClientData()); + appData->enabled = isChecked; + utils::saveSettings(appData); + }); + checkbox->Bind(wxEVT_DESTROY, [checkbox](wxWindowDestroyEvent&) { + delete static_cast(checkbox->GetClientData()); + }); appCheckboxContainer->Add(checkbox, 0, wxALL, 5); } anyOtherCheckbox = new wxCheckBox(this, wxID_ANY, _("Any other"), wxDefaultPosition, wxDefaultSize, 0); + anyOtherCheckbox->SetValue(settings.anyOtherEnabled); + anyOtherCheckbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { + bool isChecked = this->anyOtherCheckbox->IsChecked(); + auto settings = utils::getSettings(); + settings.anyOtherEnabled = isChecked; + utils::saveSettings(settings); + }); + appCheckboxContainer->Add(anyOtherCheckbox, 0, wxALL, 5); enabledAppsContainer->Add(appCheckboxContainer, 1, wxEXPAND, 5); @@ -193,8 +222,15 @@ public: settingsContainer->Add(startupText, 0, wxALL, 5); autostartCheckbox = new wxCheckBox(this, wxID_ANY, _("Launch at login"), wxDefaultPosition, wxDefaultSize, 0); - settingsContainer->Add(autostartCheckbox, 0, wxALL, 5); + autostartCheckbox->SetValue(settings.autoStart); + autostartCheckbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { + bool isChecked = this->autostartCheckbox->IsChecked(); + auto settings = utils::getSettings(); + settings.autoStart = isChecked; + utils::saveSettings(settings); + }); + settingsContainer->Add(autostartCheckbox, 0, wxALL, 5); mainContainer->Add(settingsContainer, 0, wxEXPAND, 5); this->SetSizerAndFit(mainContainer); diff --git a/src/utils.hpp b/src/utils.hpp index a80ab5a..213b869 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -24,6 +24,12 @@ namespace utils { std::vector processNames; }; + struct Settings { + bool autoStart; + bool anyOtherEnabled; + std::vector apps; + }; + inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) { wxMemoryInputStream stream(data, size); wxImage img(stream, wxBITMAP_TYPE_PNG); @@ -100,38 +106,108 @@ namespace utils { } return ""; } + inline void saveSettings(const App* newApp) { + nlohmann::json j; - inline std::vector getAllApps() { - std::vector results; + if (std::filesystem::exists(CONFIG_FILENAME)) { + std::ifstream i(CONFIG_FILENAME); + i >> j; + } + + if (!j.contains("apps")) { + j["apps"] = nlohmann::json::array(); + } + + bool appFound = false; + + for (auto& appJson : j["apps"]) { + if (appJson["name"] == newApp->appName) { + appJson["client_id"] = newApp->clientId; + appJson["search_endpoint"] = newApp->searchEndpoint; + appJson["enabled"] = newApp->enabled; + + appJson["process_names"].clear(); + for (const auto& processName : newApp->processNames) { + appJson["process_names"].push_back(processName); + } + + appFound = true; + break; + } + } + + if (!appFound) { + nlohmann::json appJson; + appJson["name"] = newApp->appName; + appJson["client_id"] = newApp->clientId; + appJson["search_endpoint"] = newApp->searchEndpoint; + appJson["enabled"] = newApp->enabled; + + for (const auto& processName : newApp->processNames) { + appJson["process_names"].push_back(processName); + } + + j["apps"].push_back(appJson); + } + + std::ofstream o(CONFIG_FILENAME); + o << j.dump(4); + o.close(); + } + + inline void saveSettings(const Settings& settings) { + nlohmann::json j; + j["autostart"] = settings.autoStart; + j["any_other"] = settings.anyOtherEnabled; + + for (const auto& app : settings.apps) { + nlohmann::json appJson; + appJson["name"] = app.appName; + appJson["client_id"] = app.clientId; + appJson["search_endpoint"] = app.searchEndpoint; + appJson["enabled"] = app.enabled; + + for (const auto& processName : app.processNames) appJson["process_names"].push_back(processName); + + j["apps"].push_back(appJson); + } + + std::ofstream o(CONFIG_FILENAME); + o << j.dump(4); + o.close(); + } + inline Settings getSettings() { + Settings ret; if (!std::filesystem::exists(CONFIG_FILENAME)) - return results; - - std::ifstream i(CONFIG_FILENAME); - std::stringstream s; - s << i.rdbuf(); - i.close(); + return ret; try { - nlohmann::json j = nlohmann::json::parse(s.str()); - auto apps = j["apps"]; - for (auto app : apps) { + std::ifstream i(CONFIG_FILENAME); + nlohmann::json j; + i >> j; + + ret.autoStart = j.value("autostart", false); + ret.anyOtherEnabled = j.value("any_other", false); + + for (const auto& app : j["apps"]) { App a; - a.appName = app["name"].get(); - a.clientId = app["client_id"].get(); - a.searchEndpoint = app["search_endpoint"].get(); - a.enabled = app["enabled"].get(); - auto processNames = app["process_names"]; - for (auto process : processNames) a.processNames.push_back(process.get()); - results.push_back(a); + a.appName = app.value("name", ""); + a.clientId = app.value("client_id", ""); + a.searchEndpoint = app.value("search_endpoint", ""); + a.enabled = app.value("enabled", false); + + for (const auto& process : app["process_names"]) a.processNames.push_back(process.get()); + + ret.apps.push_back(a); } - } catch (nlohmann::json::parse_error& ex) { - } // TODO: handle parse errors - return results; + } catch (const nlohmann::json::parse_error&) { + } // TODO: handle error + return ret; } inline App getApp(std::string processName) { - auto apps = getAllApps(); - for (auto app : apps) { + auto settings = getSettings(); + for (auto app : settings.apps) { for (auto procName : app.processNames) { if (procName == processName) return app; @@ -140,25 +216,10 @@ namespace utils { App a; a.clientId = DEFAULT_CLIENT_ID; a.appName = DEFAULT_APP_NAME; - a.enabled = true; + a.enabled = settings.anyOtherEnabled; a.searchEndpoint = ""; return a; } - - inline std::string getClientID(std::string processName) { - auto app = getApp(processName); - return app.clientId; - } - - inline std::string getAppName(std::string processName) { - auto app = getApp(processName); - return app.appName; - } - - inline std::string getSearchEndpoint(std::string processName) { - auto app = getApp(processName); - return app.searchEndpoint; - } } // namespace utils #undef DEFAULT_APP_NAME