finished gui and config system
This commit is contained in:
parent
0e0737c53c
commit
1756c9e368
|
@ -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
|
||||||
}
|
}
|
54
src/main.cpp
54
src/main.cpp
|
@ -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);
|
||||||
|
|
139
src/utils.hpp
139
src/utils.hpp
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue