- add support for different activity types
- switch from process naming matching to app user model id matching on windows - updated example settings file - added exception handling to itunes api
This commit is contained in:
parent
cd5656de63
commit
90607d2f5d
|
@ -5,13 +5,34 @@
|
|||
"client_id": "1245257414715113573",
|
||||
"enabled": true,
|
||||
"name": "Spotify",
|
||||
"type": 2,
|
||||
"process_names": [
|
||||
"org.mpris.MediaPlayer2.spotify",
|
||||
"com.spotify.client",
|
||||
"Spotify.exe"
|
||||
],
|
||||
"search_endpoint": "https://open.spotify.com/search/"
|
||||
},
|
||||
{
|
||||
"client_id": "1337188104829665340",
|
||||
"enabled": true,
|
||||
"name": "Apple Music",
|
||||
"type": 2,
|
||||
"process_names": [
|
||||
"com.apple.Music",
|
||||
"AppleInc.AppleMusicWin_nzyj5cx40ttqa!APP",
|
||||
"AppleMusic.exe"
|
||||
],
|
||||
"search_endpoint": "https://open.spotify.com/search/"
|
||||
}
|
||||
],
|
||||
"lastfm": {
|
||||
"api_key": "",
|
||||
"api_secret": "",
|
||||
"enabled": false,
|
||||
"password": "",
|
||||
"username": ""
|
||||
},
|
||||
"odesli": true,
|
||||
"autostart": false
|
||||
}
|
|
@ -35,59 +35,6 @@ std::string toStdString(winrt::hstring& in) {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string getAppModelIdOfProcess(HANDLE hProc) {
|
||||
UINT32 length = 0;
|
||||
LONG rc = GetApplicationUserModelId(hProc, &length, NULL);
|
||||
if (rc != ERROR_INSUFFICIENT_BUFFER)
|
||||
return "";
|
||||
|
||||
PWSTR fullName = (PWSTR)malloc(length * sizeof(*fullName));
|
||||
if (!fullName)
|
||||
return "";
|
||||
|
||||
rc = GetApplicationUserModelId(hProc, &length, fullName);
|
||||
if (rc != ERROR_SUCCESS) {
|
||||
free(fullName);
|
||||
return "";
|
||||
}
|
||||
winrt::hstring wideName = fullName;
|
||||
std::string name = toStdString(wideName);
|
||||
free(fullName);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string getProcessNameFromAppModelId(std::string appModelId) {
|
||||
DWORD processes[1024];
|
||||
DWORD cbNeeded;
|
||||
|
||||
if (!EnumProcesses(processes, sizeof(processes), &cbNeeded))
|
||||
return "";
|
||||
|
||||
unsigned int processCount = cbNeeded / sizeof(DWORD);
|
||||
|
||||
for (DWORD i = 0; i < processCount; i++) {
|
||||
DWORD processID = processes[i];
|
||||
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processID);
|
||||
if (hProcess) {
|
||||
std::string modelid = getAppModelIdOfProcess(hProcess);
|
||||
|
||||
if (modelid != appModelId) {
|
||||
CloseHandle(hProcess);
|
||||
continue;
|
||||
}
|
||||
|
||||
char exeName[MAX_PATH]{};
|
||||
DWORD size = MAX_PATH;
|
||||
QueryFullProcessImageNameA(hProcess, 0, exeName, &size);
|
||||
std::filesystem::path exePath = exeName;
|
||||
CloseHandle(hProcess);
|
||||
return exePath.filename().string();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool CreateShortcut(std::string source, std::string target) {
|
||||
CoInitialize(nullptr);
|
||||
WCHAR src[MAX_PATH];
|
||||
|
@ -185,13 +132,6 @@ std::shared_ptr<MediaInfo> backend::getMediaInformation() {
|
|||
|
||||
std::string modelId = toStdString(currentSession.SourceAppUserModelId());
|
||||
|
||||
// I do know that this is disgusting, but for some reason microsoft decided to switch out the exe name with the
|
||||
// ApplicationUserModelId in some version of windows 11. So we check if it's an exe name, if not we are on some
|
||||
// newer windows version and need to get the exe name from the model id. We cannot directly work with the model id
|
||||
// because it's unique per machine and therefore would mess up configs with preconfigured apps.
|
||||
if (modelId.find(".exe") == std::string::npos)
|
||||
modelId = getProcessNameFromAppModelId(modelId);
|
||||
|
||||
return std::make_shared<MediaInfo>(
|
||||
playbackInfo.PlaybackStatus() == GlobalSystemMediaTransportControlsSessionPlaybackStatus::Paused,
|
||||
toStdString(mediaProperties.Title()), std::move(artist), std::move(albumName), std::move(modelId),
|
||||
|
|
|
@ -110,7 +110,7 @@ void handleMediaTasks() {
|
|||
|
||||
std::string activityState = "by " + mediaInformation->songArtist;
|
||||
DiscordRichPresence activity{};
|
||||
activity.type = ActivityType::LISTENING;
|
||||
activity.type = app.type;
|
||||
activity.details = mediaInformation->songTitle.c_str();
|
||||
activity.state = activityState.c_str();
|
||||
activity.smallImageText = serviceName.c_str();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
namespace utils {
|
||||
struct App {
|
||||
bool enabled;
|
||||
int type;
|
||||
std::string appName;
|
||||
std::string clientId;
|
||||
std::string searchEndpoint;
|
||||
|
@ -68,6 +69,15 @@ namespace utils {
|
|||
return wxNullIcon;
|
||||
}
|
||||
|
||||
inline std::string toLower(const std::string& str) {
|
||||
std::string lowerStr = str;
|
||||
std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return lowerStr;
|
||||
}
|
||||
|
||||
inline bool caseInsensitiveMatch(const std::string& a, const std::string& b) { return toLower(a) == toLower(b); }
|
||||
|
||||
inline std::string ltrim(std::string& s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
|
||||
return s;
|
||||
|
@ -144,6 +154,7 @@ namespace utils {
|
|||
SongInfo ret{};
|
||||
std::string response =
|
||||
httpRequest("https://itunes.apple.com/search?media=music&entity=song&term=" + urlEncode(query));
|
||||
try {
|
||||
nlohmann::json j = nlohmann::json::parse(response);
|
||||
auto results = j["results"];
|
||||
if (results.size() > 0) {
|
||||
|
@ -151,6 +162,9 @@ namespace utils {
|
|||
ret.trackId = results[0]["trackId"].get<int64_t>();
|
||||
}
|
||||
return ret;
|
||||
} catch (...) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string getOdesliURL(SongInfo& song) {
|
||||
|
@ -224,7 +238,7 @@ namespace utils {
|
|||
appJson["client_id"] = app.clientId;
|
||||
appJson["search_endpoint"] = app.searchEndpoint;
|
||||
appJson["enabled"] = app.enabled;
|
||||
|
||||
appJson["type"] = app.type;
|
||||
for (const auto& processName : app.processNames) appJson["process_names"].push_back(processName);
|
||||
|
||||
j["apps"].push_back(appJson);
|
||||
|
@ -269,6 +283,7 @@ namespace utils {
|
|||
a.clientId = app.value("client_id", "");
|
||||
a.searchEndpoint = app.value("search_endpoint", "");
|
||||
a.enabled = app.value("enabled", false);
|
||||
a.type = app.value("type", 2);
|
||||
|
||||
for (const auto& process : app["process_names"]) a.processNames.push_back(process.get<std::string>());
|
||||
|
||||
|
@ -283,7 +298,7 @@ namespace utils {
|
|||
auto settings = getSettings();
|
||||
for (auto app : settings.apps) {
|
||||
for (auto procName : app.processNames) {
|
||||
if (procName == processName)
|
||||
if (caseInsensitiveMatch(procName, processName))
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
@ -291,6 +306,7 @@ namespace utils {
|
|||
a.clientId = DEFAULT_CLIENT_ID;
|
||||
a.appName = DEFAULT_APP_NAME;
|
||||
a.enabled = settings.anyOtherEnabled;
|
||||
a.type = 2; // Default to listening
|
||||
a.searchEndpoint = "";
|
||||
return a;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue