mirror of
https://github.com/Goldenkrew3000/OSSP_OpenSource.git
synced 2025-12-19 00:04:44 +10:00
Added basic local discord RPC functionality
This commit is contained in:
158
src/discordrpc.c
Normal file
158
src/discordrpc.c
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* OpenSubSonicPlayer
|
||||||
|
* Goldenkrew3000 2025
|
||||||
|
* GPL-3.0
|
||||||
|
* Discord Local RPC Handler
|
||||||
|
* Note: This provides server auth creds (encoded) directly to Discord, could use Spotify's API instead??
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "external/discord-rpc/include/discord_rpc.h"
|
||||||
|
#include "discordrpc.h"
|
||||||
|
|
||||||
|
const char* discordrpc_appid = "1407025303779278980";
|
||||||
|
char* discordrpc_osString = NULL;
|
||||||
|
static int rc = 0;
|
||||||
|
|
||||||
|
void discordrpc_struct_init(discordrpc_data** discordrpc_struct) {
|
||||||
|
(*discordrpc_struct) = malloc(sizeof(discordrpc_data));
|
||||||
|
(*discordrpc_struct)->state = 0;
|
||||||
|
(*discordrpc_struct)->songLength = 0;
|
||||||
|
(*discordrpc_struct)->songTitle = NULL;
|
||||||
|
(*discordrpc_struct)->songArtist = NULL;
|
||||||
|
(*discordrpc_struct)->coverArtUrl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void discordrpc_struct_deinit(discordrpc_data** discordrpc_struct) {
|
||||||
|
if ((*discordrpc_struct)->songTitle != NULL) { free((*discordrpc_struct)->songTitle); }
|
||||||
|
if ((*discordrpc_struct)->songArtist != NULL) { free((*discordrpc_struct)->songArtist); }
|
||||||
|
if ((*discordrpc_struct)->coverArtUrl != NULL) { free((*discordrpc_struct)->coverArtUrl); }
|
||||||
|
if (*discordrpc_struct != NULL) { free(*discordrpc_struct); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDiscordReady(const DiscordUser* connectedUser)
|
||||||
|
{
|
||||||
|
printf("\nDiscord: connected to user %s#%s - %s\n",
|
||||||
|
connectedUser->username,
|
||||||
|
connectedUser->discriminator,
|
||||||
|
connectedUser->userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDiscordDisconnected(int errcode, const char* message)
|
||||||
|
{
|
||||||
|
printf("\nDiscord: disconnected (%d: %s)\n", errcode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDiscordError(int errcode, const char* message)
|
||||||
|
{
|
||||||
|
printf("\nDiscord: error (%d: %s)\n", errcode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void discordrpc_init() {
|
||||||
|
printf("[DiscordRPC] Initializing...\n");
|
||||||
|
DiscordEventHandlers handlers;
|
||||||
|
memset(&handlers, 0, sizeof(handlers));
|
||||||
|
handlers.ready = handleDiscordReady;
|
||||||
|
handlers.disconnected = handleDiscordDisconnected;
|
||||||
|
handlers.errored = handleDiscordError;
|
||||||
|
Discord_Initialize(discordrpc_appid, &handlers, 1, NULL);
|
||||||
|
|
||||||
|
// Fetch OS String for RPC (Heap-allocated)
|
||||||
|
// TODO: Check if failed
|
||||||
|
discordrpc_osString = discordrpc_getOS();
|
||||||
|
}
|
||||||
|
|
||||||
|
void discordrpc_update(discordrpc_data** discordrpc_struct) {
|
||||||
|
printf("[DiscordRPC] Updating...\n");
|
||||||
|
DiscordRichPresence presence;
|
||||||
|
char* detailsString = NULL;
|
||||||
|
char* stateString = NULL;
|
||||||
|
memset(&presence, 0, sizeof(presence));
|
||||||
|
|
||||||
|
if ((*discordrpc_struct)->state == DISCORDRPC_STATE_IDLE) {
|
||||||
|
asprintf(&detailsString, "Idle");
|
||||||
|
presence.details = detailsString;
|
||||||
|
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING) {
|
||||||
|
asprintf(&detailsString, "%s", (*discordrpc_struct)->songTitle);
|
||||||
|
asprintf(&stateString, "by %s", (*discordrpc_struct)->songArtist);
|
||||||
|
presence.details = detailsString;
|
||||||
|
presence.state = stateString;
|
||||||
|
// TODO: Discord is currently broken for this rn
|
||||||
|
//presence.largeImageKey = (*discordrpc_struct)->coverArtUrl;
|
||||||
|
presence.largeImageText = discordrpc_osString;
|
||||||
|
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PAUSED) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
presence.activity_type = DISCORD_ACTIVITY_TYPE_LISTENING;
|
||||||
|
Discord_UpdatePresence(&presence);
|
||||||
|
|
||||||
|
free(detailsString);
|
||||||
|
if (stateString != NULL) { free(stateString); }
|
||||||
|
}
|
||||||
|
|
||||||
|
char* discordrpc_getOS() {
|
||||||
|
// NOTE: Could have made a sysctl function, but this is literally only done here, not worth it
|
||||||
|
// TODO: This is ONLY linux compatible at this point
|
||||||
|
|
||||||
|
FILE* fp_ostype = fopen("/proc/sys/kernel/ostype", "r");
|
||||||
|
char buf_ostype[16];
|
||||||
|
if (!fp_ostype) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.ostype sysctl.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* fp_osrelease = fopen("/proc/sys/kernel/osrelease", "r");
|
||||||
|
char buf_osrelease[32];
|
||||||
|
if (!fp_osrelease) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.osrelease sysctl.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* fp_osarch = fopen("/proc/sys/kernel/arch", "r");
|
||||||
|
char buf_osarch[16];
|
||||||
|
if (!fp_osarch) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.arch sysctl.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(buf_ostype, sizeof(buf_ostype), fp_ostype) == NULL) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.ostype sysctl.");
|
||||||
|
fclose(fp_ostype);
|
||||||
|
fclose(fp_osrelease);
|
||||||
|
fclose(fp_osarch);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (fgets(buf_osrelease, sizeof(buf_osrelease), fp_osrelease) == NULL) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.osrelease sysctl.");
|
||||||
|
fclose(fp_ostype);
|
||||||
|
fclose(fp_osrelease);
|
||||||
|
fclose(fp_osarch);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (fgets(buf_osarch, sizeof(buf_osarch), fp_osarch) == NULL) {
|
||||||
|
logger_log_error(__func__, "Could not perform kernel.arch sysctl.");
|
||||||
|
fclose(fp_ostype);
|
||||||
|
fclose(fp_osrelease);
|
||||||
|
fclose(fp_osarch);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fclose(fp_ostype);
|
||||||
|
fclose(fp_osrelease);
|
||||||
|
fclose(fp_osarch);
|
||||||
|
|
||||||
|
// HACK: Since Linux removed the sysctl interface, I have to manually remove newlines from the /proc contents
|
||||||
|
buf_ostype[strcspn(buf_ostype, "\n")] = '\0';
|
||||||
|
buf_osrelease[strcspn(buf_osrelease, "\n")] = '\0';
|
||||||
|
buf_osarch[strcspn(buf_osarch, "\n")] = '\0';
|
||||||
|
|
||||||
|
char* osString = NULL;
|
||||||
|
rc = asprintf(&osString, "on %s %s %s", buf_ostype, buf_osarch, buf_osrelease);
|
||||||
|
if (rc == -1) {
|
||||||
|
logger_log_error(__func__, "asprintf() failed.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return osString;
|
||||||
|
}
|
||||||
23
src/discordrpc.h
Normal file
23
src/discordrpc.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef _DISCORDRPC_H
|
||||||
|
#define _DISCORDRPC_H
|
||||||
|
|
||||||
|
#define DISCORDRPC_STATE_IDLE 0
|
||||||
|
#define DISCORDRPC_STATE_PLAYING 1
|
||||||
|
#define DISCORDRPC_STATE_PAUSED 2
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int state;
|
||||||
|
long songLength;
|
||||||
|
char* songTitle;
|
||||||
|
char* songArtist;
|
||||||
|
char* coverArtUrl;
|
||||||
|
} discordrpc_data;
|
||||||
|
|
||||||
|
|
||||||
|
void discordrpc_struct_init(discordrpc_data** discordrpc_struct);
|
||||||
|
void discordrpc_struct_deinit(discordrpc_data** discordrpc_struct);
|
||||||
|
void discordrpc_init();
|
||||||
|
void discordrpc_update(discordrpc_data** discordrpc_struct);
|
||||||
|
char* discordrpc_getOS();
|
||||||
|
|
||||||
|
#endif
|
||||||
57
src/main.c
57
src/main.c
@@ -2,7 +2,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "external/discord-rpc/include/discord_rpc.h"
|
|
||||||
#include "gui/gui_entry.hpp"
|
#include "gui/gui_entry.hpp"
|
||||||
#include "libopensubsonic/logger.h"
|
#include "libopensubsonic/logger.h"
|
||||||
#include "libopensubsonic/crypto.h"
|
#include "libopensubsonic/crypto.h"
|
||||||
@@ -10,53 +9,7 @@
|
|||||||
#include "libopensubsonic/endpoint_ping.h"
|
#include "libopensubsonic/endpoint_ping.h"
|
||||||
#include "configHandler.h"
|
#include "configHandler.h"
|
||||||
#include "player/player.h"
|
#include "player/player.h"
|
||||||
|
#include "discordrpc.h"
|
||||||
const char* APPID = "1407025303779278980";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void handleDiscordReady(const DiscordUser* connectedUser)
|
|
||||||
{
|
|
||||||
printf("\nDiscord: connected to user %s#%s - %s\n",
|
|
||||||
connectedUser->username,
|
|
||||||
connectedUser->discriminator,
|
|
||||||
connectedUser->userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDiscordDisconnected(int errcode, const char* message)
|
|
||||||
{
|
|
||||||
printf("\nDiscord: disconnected (%d: %s)\n", errcode, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDiscordError(int errcode, const char* message)
|
|
||||||
{
|
|
||||||
printf("\nDiscord: error (%d: %s)\n", errcode, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void discordInit()
|
|
||||||
{
|
|
||||||
DiscordEventHandlers handlers;
|
|
||||||
memset(&handlers, 0, sizeof(handlers));
|
|
||||||
handlers.ready = handleDiscordReady;
|
|
||||||
handlers.disconnected = handleDiscordDisconnected;
|
|
||||||
handlers.errored = handleDiscordError;
|
|
||||||
Discord_Initialize(APPID, &handlers, 1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updatePresence() {
|
|
||||||
char buffer[256];
|
|
||||||
DiscordRichPresence presence;
|
|
||||||
memset(&presence, 0, sizeof(presence));
|
|
||||||
sprintf(buffer, "Idle"); // Change to snprintf
|
|
||||||
presence.details = buffer;
|
|
||||||
presence.activity_type = DISCORD_ACTIVITY_TYPE_LISTENING;
|
|
||||||
Discord_UpdatePresence(&presence);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
configHandler_config_t* configObj = NULL;
|
configHandler_config_t* configObj = NULL;
|
||||||
int checkConfigFile();
|
int checkConfigFile();
|
||||||
@@ -99,8 +52,12 @@ int main(int argc, char** argv) {
|
|||||||
pthread_create(&pthr_player, NULL, OSSPlayer_ThrdInit, NULL);
|
pthread_create(&pthr_player, NULL, OSSPlayer_ThrdInit, NULL);
|
||||||
|
|
||||||
// Launch Discord RPC
|
// Launch Discord RPC
|
||||||
discordInit();
|
discordrpc_data* discordrpc = NULL;
|
||||||
updatePresence();
|
discordrpc_struct_init(&discordrpc);
|
||||||
|
discordrpc->state = DISCORDRPC_STATE_IDLE;
|
||||||
|
discordrpc_init();
|
||||||
|
discordrpc_update(&discordrpc);
|
||||||
|
discordrpc_struct_deinit(&discordrpc);
|
||||||
|
|
||||||
// Launch QT frontend
|
// Launch QT frontend
|
||||||
qt_gui_entry(argc, argv);
|
qt_gui_entry(argc, argv);
|
||||||
|
|||||||
Reference in New Issue
Block a user