From 2893638e6898ebad19cb3b9c0b15d189f9e6d4ef Mon Sep 17 00:00:00 2001 From: ultrasn0w Date: Wed, 22 Nov 2017 01:29:40 +0100 Subject: [PATCH] Initial commit --- LICENSE | 2 +- foo_drpc.sln | 44 ++++++ foo_drpc/Plugin.cpp | 222 ++++++++++++++++++++++++++++++ foo_drpc/Plugin.h | 42 ++++++ foo_drpc/Plugin.rc | Bin 0 -> 1212 bytes foo_drpc/foo_drpc.vcxproj | 120 ++++++++++++++++ foo_drpc/foo_drpc.vcxproj.filters | 46 +++++++ foo_drpc/foo_drpc.vcxproj.user | 4 + foo_drpc/resource.h | 23 ++++ 9 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 foo_drpc.sln create mode 100644 foo_drpc/Plugin.cpp create mode 100644 foo_drpc/Plugin.h create mode 100644 foo_drpc/Plugin.rc create mode 100644 foo_drpc/foo_drpc.vcxproj create mode 100644 foo_drpc/foo_drpc.vcxproj.filters create mode 100644 foo_drpc/foo_drpc.vcxproj.user create mode 100644 foo_drpc/resource.h diff --git a/LICENSE b/LICENSE index 8864d4a..334c4a0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 +Copyright (c) 2017 ultrasn0w Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/foo_drpc.sln b/foo_drpc.sln new file mode 100644 index 0000000..f8ea7c9 --- /dev/null +++ b/foo_drpc.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo_drpc", "foo_drpc\foo_drpc.vcxproj", "{CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_component_client", "..\foobar2000_component_client\foobar2000_component_client.vcxproj", "{71AD2674-065B-48F5-B8B0-E1F9D3892081}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_SDK", "..\SDK\foobar2000_SDK.vcxproj", "{E8091321-D79D-4575-86EF-064EA1A4A20D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pfc", "..\..\pfc\pfc.vcxproj", "{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_sdk_helpers", "..\helpers\foobar2000_sdk_helpers.vcxproj", "{EE47764E-A202-4F85-A767-ABDAB4AFF35F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38}.Debug|Win32.ActiveCfg = Debug|Win32 + {CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38}.Debug|Win32.Build.0 = Debug|Win32 + {CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38}.Release|Win32.ActiveCfg = Release|Win32 + {CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38}.Release|Win32.Build.0 = Release|Win32 + {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|Win32.ActiveCfg = Debug|Win32 + {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|Win32.Build.0 = Debug|Win32 + {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|Win32.ActiveCfg = Release|Win32 + {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|Win32.Build.0 = Release|Win32 + {E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|Win32.Build.0 = Debug|Win32 + {E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|Win32.ActiveCfg = Release|Win32 + {E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|Win32.Build.0 = Release|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|Win32.Build.0 = Debug|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|Win32.ActiveCfg = Release|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|Win32.Build.0 = Release|Win32 + {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|Win32.ActiveCfg = Debug|Win32 + {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|Win32.Build.0 = Debug|Win32 + {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|Win32.ActiveCfg = Release|Win32 + {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/foo_drpc/Plugin.cpp b/foo_drpc/Plugin.cpp new file mode 100644 index 0000000..3a629cb --- /dev/null +++ b/foo_drpc/Plugin.cpp @@ -0,0 +1,222 @@ +#include +#include "Plugin.h" + + +DECLARE_COMPONENT_VERSION( +"foo_drpc", +"0.1", +"© 2017 - ultrasn0w"); + +static initquit_factory_t foo_interface; +static std::chrono::time_point lastT; +static std::chrono::time_point req; +static bool errored; // Still kind of unused +static bool connected; +static bool first; + +foo_drpc::foo_drpc() +{ + errored = false; + connected = true; + first = true; +} + +foo_drpc::~foo_drpc() +{ +} + +void foo_drpc::on_init() +{ + static_api_ptr_t pcm; + pcm->register_callback( + this, + play_callback::flag_on_playback_starting | + play_callback::flag_on_playback_stop | + play_callback::flag_on_playback_pause | + play_callback::flag_on_playback_new_track | + play_callback::flag_on_playback_edited | + play_callback::flag_on_playback_dynamic_info_track, + false); + + discordInit(); + initDiscordPresence(); +} + +void foo_drpc::on_quit() +{ + Discord_Shutdown(); + static_api_ptr_t()->unregister_callback(this); +} + +void foo_drpc::on_playback_starting(play_control::t_track_command command, bool pause) +{ + if (!connected) return; + + if (pause) + { + discordPresence.state = "Paused"; + discordPresence.smallImageKey = "pause"; + } + else + { + switch (command) + { + case play_control::track_command_play: + case play_control::track_command_resume: + case play_control::track_command_settrack: + discordPresence.state = "Listening"; + discordPresence.smallImageKey = "play"; + break; + } + } + + metadb_handle_ptr track; + static_api_ptr_t pbc; + if (pbc->get_now_playing(track)) + { + on_playback_new_track(track); + } + // updateDiscordPresence(); +} + +void foo_drpc::on_playback_stop(play_control::t_stop_reason reason) +{ + if (!connected) return; + + switch (reason) + { + case play_control::stop_reason_user: + case play_control::stop_reason_eof: + case play_control::stop_reason_shutting_down: + discordPresence.state = "Stopped"; + discordPresence.smallImageKey = "stop"; + break; + } + updateDiscordPresence(); +} + +void foo_drpc::on_playback_pause(bool pause) +{ + if (!connected) return; + + discordPresence.state = (pause ? "Paused" : "Listening"); + discordPresence.smallImageKey = (pause ? "pause" : "play"); + updateDiscordPresence(); +} + +void foo_drpc::on_playback_new_track(metadb_handle_ptr track) +{ + if (!connected) return; + + service_ptr_t script; + pfc::string8 format = "%artist% - %title%"; + + if (static_api_ptr_t()->compile(script, format)) + { + static_api_ptr_t pbc; + + pbc->playback_format_title_ex( + track, + nullptr, + format, + script, + nullptr, + playback_control::display_level_titles); + + if (format.get_length() + 1 <= 128) { + static char nya[128]; + size_t destination_size = sizeof(nya); + strncpy_s(nya, format.get_ptr(), destination_size); + nya[destination_size - 1] = '\0'; + + discordPresence.state = "Listening"; + discordPresence.smallImageKey = "play"; + discordPresence.details = nya; + updateDiscordPresence(); + } + } +} + +void foo_drpc::on_playback_dynamic_info_track(const file_info& info) +{ + metadb_handle_ptr track; + static_api_ptr_t pbc; + if (pbc->get_now_playing(track)) + { + on_playback_new_track(track); + } +} + +void foo_drpc::initDiscordPresence() +{ + memset(&discordPresence, 0, sizeof(discordPresence)); + discordPresence.state = "Initialized"; + discordPresence.details = "topkek"; + discordPresence.largeImageKey = "logo"; + discordPresence.smallImageKey = "stop"; + // discordPresence.partyId = "party1234"; + // discordPresence.partySize = 1; + // discordPresence.partyMax = 6; + + updateDiscordPresence(); +} + +void foo_drpc::updateDiscordPresence() +{ + if (first) { + lastT = std::chrono::high_resolution_clock::now(); + first = false; + Discord_UpdatePresence(&discordPresence); + } + else { + req = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = req - lastT; + // spam protection + if (elapsed.count() > 1.0) { + Discord_UpdatePresence(&discordPresence); + lastT = std::chrono::high_resolution_clock::now(); + } + } +} + +void connectedF() +{ + connected = true; +} + +void disconnectedF(int errorCode, const char* message) +{ + connected = false; +} + +void erroredF(int errorCode, const char* message) +{ + errored = true; +} + +void foo_drpc::discordInit() +{ + memset(&handlers, 0, sizeof(handlers)); + handlers.ready = connectedF; + handlers.disconnected = disconnectedF; + handlers.errored = erroredF; + // handlers.joinGame = [](const char* joinSecret) {}; + // handlers.spectateGame = [](const char* spectateSecret) {}; + // handlers.joinRequest = [](const DiscordJoinRequest* request) {}; + Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL); +} + +// thx SuperKoko (unused) +LPSTR foo_drpc::UnicodeToAnsi(LPCWSTR s) +{ + if (s == NULL) return NULL; + int cw = lstrlenW(s); + if (cw == 0) { CHAR *psz = new CHAR[1]; *psz = '\0'; return psz; } + int cc = WideCharToMultiByte(CP_UTF8, 0, s, cw, NULL, 0, NULL, NULL); + if (cc == 0) return NULL; + CHAR *psz = new CHAR[cc + 1]; + cc = WideCharToMultiByte(CP_UTF8, 0, s, cw, psz, cc, NULL, NULL); + if (cc == 0) { delete[] psz; return NULL; } + psz[cc] = '\0'; + return psz; +} diff --git a/foo_drpc/Plugin.h b/foo_drpc/Plugin.h new file mode 100644 index 0000000..632dea0 --- /dev/null +++ b/foo_drpc/Plugin.h @@ -0,0 +1,42 @@ +#ifndef FOODRPC_PLUGIN_H_ +#define FOODRPC_PLUGIN_H_ + +#include "../../SDK/foobar2000.h" +#include "discord-rpc.h" +#include + +class foo_drpc : + public initquit, + public play_callback +{ +public: + foo_drpc(); + ~foo_drpc(); + + DiscordEventHandlers handlers; + DiscordRichPresence discordPresence; + // Censored on GitHub :) + const char* APPLICATION_ID = "FILL_IN_HERE"; + + void on_init(); + void on_quit(); + + void discordInit(); + void initDiscordPresence(); + void updateDiscordPresence(); + + LPSTR UnicodeToAnsi(LPCWSTR s); + + void on_playback_starting(play_control::t_track_command command, bool paused); + void on_playback_stop(play_control::t_stop_reason reason); + void on_playback_pause(bool state); + void on_playback_new_track(metadb_handle_ptr track); + void on_playback_edited(metadb_handle_ptr track) { on_playback_new_track(track); } + void on_playback_dynamic_info_track(const file_info& info); + void on_playback_time(double time) {} + void on_playback_seek(double time) {} + void on_playback_dynamic_info(file_info const& info) {} + void on_volume_change(float p_new_val) {} +}; + +#endif diff --git a/foo_drpc/Plugin.rc b/foo_drpc/Plugin.rc new file mode 100644 index 0000000000000000000000000000000000000000..8338325e86dee2e6ac5c723fc6ffe01a9ac05d21 GIT binary patch literal 1212 zcmezWPnjW;A&()MA%~%qA%!88L4m=BA&eoFp@<=fp_rkFA(=ssA%nq=ftP^`jP)4? zD+IX^U_JIHjjExG`ihK8IT^wj92tBVLc#7=f}0J=L9mpk1Wpl33eCLkTpGLhJ{nGf22Y@{ + + + + Debug + Win32 + + + Release + Win32 + + + + {CC272D9D-8B6A-43D0-AA2E-9F46B0D07C38} + Win32Proj + foo_drpc + foo_drpc + 10.0.16299.0 + + + + true + Unicode + v141 + DynamicLibrary + + + DynamicLibrary + false + true + Unicode + v141_xp + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;FOO_DRPC_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + ..\..\shared\ + shared.lib;Shlwapi.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;FOO_DRPC_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + false + false + false + + + Windows + false + true + true + ..\..\shared\ + shared.lib;Shlwapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + {71ad2674-065b-48f5-b8b0-e1f9d3892081} + + + {ee47764e-a202-4f85-a767-abdab4aff35f} + + + {e8091321-d79d-4575-86ef-064ea1a4a20d} + + + {ebfffb4e-261d-44d3-b89c-957b31a0bf9c} + + + + + + + + + \ No newline at end of file diff --git a/foo_drpc/foo_drpc.vcxproj.filters b/foo_drpc/foo_drpc.vcxproj.filters new file mode 100644 index 0000000..bbe8c16 --- /dev/null +++ b/foo_drpc/foo_drpc.vcxproj.filters @@ -0,0 +1,46 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {694477ed-4bc3-430d-8c5a-53a392832187} + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + lib + + + \ No newline at end of file diff --git a/foo_drpc/foo_drpc.vcxproj.user b/foo_drpc/foo_drpc.vcxproj.user new file mode 100644 index 0000000..6e2aec7 --- /dev/null +++ b/foo_drpc/foo_drpc.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/foo_drpc/resource.h b/foo_drpc/resource.h new file mode 100644 index 0000000..1859967 --- /dev/null +++ b/foo_drpc/resource.h @@ -0,0 +1,23 @@ +//{{NO_DEPENDENCIES}} +// Von Microsoft Visual C++ generierte Includedatei. +// Verwendet durch Plugin.rc +// +#define VS_VERSION_INFO 1 +#define VFFF_ISSHAREDFILE 0x0001 +#define VFF_CURNEDEST 0x0001 +#define VIFF_FORCEINSTALL 0x0001 +#define VFF_FILEINUSE 0x0002 +#define VIFF_DONTDELETEOLD 0x0002 +#define VFF_BUFFTOOSMALL 0x0004 +#define VS_USER_DEFINED 100 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif