finished gui and config system

This commit is contained in:
EinTim23 2024-11-04 16:09:00 +01:00
parent 0e0737c53c
commit 1756c9e368
3 changed files with 157 additions and 58 deletions

View File

@ -1,31 +1,33 @@
{ {
"any_other": false,
"apps": [ "apps": [
{ {
"client_id": "1245257240890310686",
"enabled": true,
"name": "Apple Music", "name": "Apple Music",
"process_names": [ "process_names": [
"AppleMusic.exe" "AppleMusic.exe"
], ],
"enabled": true, "search_endpoint": "https://music.apple.com/search?term="
"search_endpoint": "https://music.apple.com/search?term=",
"client_id": "1245257240890310686"
}, },
{ {
"client_id": "1245257414715113573",
"enabled": true,
"name": "Spotify", "name": "Spotify",
"process_names": [ "process_names": [
"Spotify.exe" "Spotify.exe"
], ],
"enabled": true, "search_endpoint": "https://open.spotify.com/search/"
"search_endpoint": "https://open.spotify.com/search/",
"client_id": "1245257414715113573"
}, },
{ {
"client_id": "1245257493966225488",
"enabled": true,
"name": "Tidal", "name": "Tidal",
"process_names": [ "process_names": [
"TIDAL.exe" "TIDAL.exe"
], ],
"enabled": true, "search_endpoint": "https://listen.tidal.com/search?q="
"search_endpoint": "https://listen.tidal.com/search?q=",
"client_id": "1245257493966225488"
} }
] ],
"autostart": false
} }

View File

@ -16,11 +16,13 @@
std::string lastPlayingSong = ""; std::string lastPlayingSong = "";
std::string lastMediaSource = ""; std::string lastMediaSource = "";
std::string currentSongTitle = "";
void handleRPCTasks() { void handleRPCTasks() {
while (true) { while (true) {
DiscordEventHandlers discordHandler{}; 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()) if (Discord_IsConnected())
break; break;
} }
@ -39,14 +41,15 @@ void handleMediaTasks() {
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
auto mediaInformation = backend::getMediaInformation(); auto mediaInformation = backend::getMediaInformation();
if (!mediaInformation) { if (!mediaInformation) {
currentSongTitle = "";
Discord_ClearPresence(); // Nothing is playing rn, clear presence Discord_ClearPresence(); // Nothing is playing rn, clear presence
continue; continue;
} }
if (mediaInformation->paused) { if (mediaInformation->paused) {
lastPlayingSong = ""; lastPlayingSong = "";
Discord_ClearPresence(); // TODO: allow user to keep presence when paused(because for currentSongTitle = "";
// some reason some people want this) Discord_ClearPresence();
continue; continue;
} }
@ -57,6 +60,7 @@ void handleMediaTasks() {
continue; continue;
lastPlayingSong = currentlyPlayingSong; lastPlayingSong = currentlyPlayingSong;
currentSongTitle = mediaInformation->songArtist + " - " + mediaInformation->songTitle;
std::string currentMediaSource = mediaInformation->playbackSource; std::string currentMediaSource = mediaInformation->playbackSource;
@ -65,7 +69,13 @@ void handleMediaTasks() {
Discord_Shutdown(); Discord_Shutdown();
} // reinitialize with new client id } // 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; std::string activityState = "by " + mediaInformation->songArtist;
DiscordRichPresence activity{}; DiscordRichPresence activity{};
@ -90,7 +100,7 @@ void handleMediaTasks() {
activity.startTimestamp = time(nullptr) - (mediaInformation->songElapsedTime / 1000); activity.startTimestamp = time(nullptr) - (mediaInformation->songElapsedTime / 1000);
activity.endTimestamp = time(nullptr) + (remainingTime / 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 searchQuery = mediaInformation->songTitle + " " + mediaInformation->songArtist;
std::string buttonName = "Search on " + serviceName; std::string buttonName = "Search on " + serviceName;
@ -115,7 +125,7 @@ public:
protected: protected:
virtual wxMenu* CreatePopupMenu() override { virtual wxMenu* CreatePopupMenu() override {
wxMenu* menu = new wxMenu; 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->Enable(10004, false);
menu->AppendSeparator(); menu->AppendSeparator();
menu->Append(10001, _("Settings")); menu->Append(10001, _("Settings"));
@ -168,14 +178,33 @@ public:
wxBoxSizer* appCheckboxContainer; wxBoxSizer* appCheckboxContainer;
appCheckboxContainer = new wxBoxSizer(wxVERTICAL); 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); 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<utils::App*>(checkbox->GetClientData());
appData->enabled = isChecked;
utils::saveSettings(appData);
});
checkbox->Bind(wxEVT_DESTROY, [checkbox](wxWindowDestroyEvent&) {
delete static_cast<utils::App*>(checkbox->GetClientData());
});
appCheckboxContainer->Add(checkbox, 0, wxALL, 5); appCheckboxContainer->Add(checkbox, 0, wxALL, 5);
} }
anyOtherCheckbox = new wxCheckBox(this, wxID_ANY, _("Any other"), wxDefaultPosition, wxDefaultSize, 0); 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); appCheckboxContainer->Add(anyOtherCheckbox, 0, wxALL, 5);
enabledAppsContainer->Add(appCheckboxContainer, 1, wxEXPAND, 5); enabledAppsContainer->Add(appCheckboxContainer, 1, wxEXPAND, 5);
@ -193,8 +222,15 @@ public:
settingsContainer->Add(startupText, 0, wxALL, 5); settingsContainer->Add(startupText, 0, wxALL, 5);
autostartCheckbox = new wxCheckBox(this, wxID_ANY, _("Launch at login"), wxDefaultPosition, wxDefaultSize, 0); 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); mainContainer->Add(settingsContainer, 0, wxEXPAND, 5);
this->SetSizerAndFit(mainContainer); this->SetSizerAndFit(mainContainer);

View File

@ -24,6 +24,12 @@ namespace utils {
std::vector<std::string> processNames; std::vector<std::string> processNames;
}; };
struct Settings {
bool autoStart;
bool anyOtherEnabled;
std::vector<App> apps;
};
inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) { inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) {
wxMemoryInputStream stream(data, size); wxMemoryInputStream stream(data, size);
wxImage img(stream, wxBITMAP_TYPE_PNG); wxImage img(stream, wxBITMAP_TYPE_PNG);
@ -100,38 +106,108 @@ namespace utils {
} }
return ""; return "";
} }
inline void saveSettings(const App* newApp) {
nlohmann::json j;
inline std::vector<App> getAllApps() { if (std::filesystem::exists(CONFIG_FILENAME)) {
std::vector<App> results;
if (!std::filesystem::exists(CONFIG_FILENAME))
return results;
std::ifstream i(CONFIG_FILENAME); std::ifstream i(CONFIG_FILENAME);
std::stringstream s; i >> j;
s << i.rdbuf(); }
i.close();
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 ret;
try { try {
nlohmann::json j = nlohmann::json::parse(s.str()); std::ifstream i(CONFIG_FILENAME);
auto apps = j["apps"]; nlohmann::json j;
for (auto app : apps) { i >> j;
ret.autoStart = j.value("autostart", false);
ret.anyOtherEnabled = j.value("any_other", false);
for (const auto& app : j["apps"]) {
App a; App a;
a.appName = app["name"].get<std::string>(); a.appName = app.value("name", "");
a.clientId = app["client_id"].get<std::string>(); a.clientId = app.value("client_id", "");
a.searchEndpoint = app["search_endpoint"].get<std::string>(); a.searchEndpoint = app.value("search_endpoint", "");
a.enabled = app["enabled"].get<bool>(); a.enabled = app.value("enabled", false);
auto processNames = app["process_names"];
for (auto process : processNames) a.processNames.push_back(process.get<std::string>()); for (const auto& process : app["process_names"]) a.processNames.push_back(process.get<std::string>());
results.push_back(a);
ret.apps.push_back(a);
} }
} catch (nlohmann::json::parse_error& ex) { } catch (const nlohmann::json::parse_error&) {
} // TODO: handle parse errors } // TODO: handle error
return results; return ret;
} }
inline App getApp(std::string processName) { inline App getApp(std::string processName) {
auto apps = getAllApps(); auto settings = getSettings();
for (auto app : apps) { for (auto app : settings.apps) {
for (auto procName : app.processNames) { for (auto procName : app.processNames) {
if (procName == processName) if (procName == processName)
return app; return app;
@ -140,25 +216,10 @@ namespace utils {
App a; App a;
a.clientId = DEFAULT_CLIENT_ID; a.clientId = DEFAULT_CLIENT_ID;
a.appName = DEFAULT_APP_NAME; a.appName = DEFAULT_APP_NAME;
a.enabled = true; a.enabled = settings.anyOtherEnabled;
a.searchEndpoint = ""; a.searchEndpoint = "";
return a; 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 } // namespace utils
#undef DEFAULT_APP_NAME #undef DEFAULT_APP_NAME