mirror of
https://github.com/Zaarrg/stremio-community-v5.git
synced 2026-01-11 12:00:40 +00:00
Added Discord RPC support
- Added Allow debug logs to cmakelist instead of debug runs - Added Discord rpc SDK supporting buttons and type - Added Discord RPC handling - Added Discord RPC Events for each stremio site - Added DiscordRPC settings toggle to disable RPC - Changed App image to a cleaner one
This commit is contained in:
parent
a67eebaf0d
commit
76bbdf64a9
12 changed files with 209 additions and 6 deletions
|
|
@ -5,20 +5,28 @@ project(stremio VERSION "5.0.17")
|
|||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
option(DEBUG_LOG "Allow debug logs" ON)
|
||||
|
||||
# Locate MPV
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# 64-bit architecture
|
||||
set(MPV_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/x86_64/include")
|
||||
set(MPV_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/x86_64/mpv.lib")
|
||||
set(MPV_DLL "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/x86_64/libmpv-2.dll")
|
||||
|
||||
set(DISCORD_LIB "${CMAKE_CURRENT_SOURCE_DIR}/deps/discord-rpc/win64-static/lib/discord-rpc.lib")
|
||||
set(DISCORD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/discord-rpc/win64-static/include")
|
||||
else()
|
||||
# 32-bit architecture
|
||||
set(MPV_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/i686/include")
|
||||
set(MPV_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/i686/mpv.lib")
|
||||
set(MPV_DLL "${CMAKE_CURRENT_SOURCE_DIR}/deps/libmpv/i686/libmpv-2.dll")
|
||||
|
||||
set(DISCORD_LIB "${CMAKE_CURRENT_SOURCE_DIR}/deps/discord-rpc/win32-static/lib/discord-rpc.lib")
|
||||
set(DISCORD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/discord-rpc/win32-static/include")
|
||||
endif()
|
||||
|
||||
|
||||
include_directories(${DISCORD_INCLUDE_DIR})
|
||||
include_directories(${MPV_INCLUDE_DIR})
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
|
@ -54,6 +62,8 @@ set(SOURCES
|
|||
src/resource.h
|
||||
src/utils/extensions.cpp
|
||||
src/utils/extensions.h
|
||||
src/utils/discord.cpp
|
||||
src/utils/discord.h
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} WIN32 ${SOURCES})
|
||||
|
|
@ -72,9 +82,10 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||
OpenSSL::Crypto
|
||||
CURL::libcurl
|
||||
${MPV_LIBRARY}
|
||||
${DISCORD_LIB}
|
||||
)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:DEBUG_BUILD>)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE DEBUG_LOG)
|
||||
|
||||
# Copy MPV DLL
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 9.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 22 KiB |
|
|
@ -67,6 +67,7 @@ HWND g_trayHwnd = nullptr;
|
|||
bool g_pauseOnMinimize = true;
|
||||
bool g_pauseOnLostFocus = false;
|
||||
bool g_allowZoom = false;
|
||||
bool g_isRpcOn = true;
|
||||
|
||||
// Tray sizes
|
||||
int g_tray_itemH = 31;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ extern HWND g_trayHwnd;
|
|||
extern bool g_pauseOnMinimize;
|
||||
extern bool g_pauseOnLostFocus;
|
||||
extern bool g_allowZoom;
|
||||
extern bool g_isRpcOn;
|
||||
|
||||
// Tray sizes
|
||||
extern int g_tray_itemH;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <VersionHelpers.h>
|
||||
#include "discord_rpc.h"
|
||||
|
||||
#include "ui/mainwindow.h"
|
||||
#include "core/globals.h"
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
#include "updater/updater.h"
|
||||
#include "utils/helpers.h"
|
||||
#include "utils/config.h"
|
||||
#include "utils/discord.h"
|
||||
// This started as 1-week project so please don't take the code to seriously
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
|
@ -85,6 +87,9 @@ int main(int argc, char* argv[])
|
|||
// Load config
|
||||
LoadSettings();
|
||||
|
||||
// Initialize Discord RPC
|
||||
InitializeDiscord();
|
||||
|
||||
// Updater
|
||||
g_updaterThread=std::thread(RunAutoUpdaterOnce);
|
||||
g_updaterThread.detach();
|
||||
|
|
@ -154,6 +159,9 @@ int main(int argc, char* argv[])
|
|||
while(GetMessage(&msg, nullptr, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
// Run Discord RPC callbacks
|
||||
Discord_RunCallbacks();
|
||||
}
|
||||
|
||||
if(g_darkBrush){
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "../ui/splash.h"
|
||||
#include "../webview/webview.h"
|
||||
#include "../updater/updater.h"
|
||||
#include "../utils/discord.h"
|
||||
|
||||
// Single-instance
|
||||
bool FocusExistingInstance(const std::wstring &protocolArg)
|
||||
|
|
@ -124,7 +125,7 @@ void SendToJS(const std::string &eventName, const nlohmann::json &eventData)
|
|||
std::wstring wpayload(payload.begin(), payload.end());
|
||||
g_webview->PostWebMessageAsString(wpayload.c_str());
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
#ifdef DEBUG_LOG
|
||||
std::cout << "[Native->JS] " << payload << "\n";
|
||||
#endif
|
||||
}
|
||||
|
|
@ -226,6 +227,8 @@ void HandleEvent(const std::string &ev, std::vector<std::string> &args)
|
|||
} else {
|
||||
g_webview->Navigate(uri.c_str());
|
||||
}
|
||||
} else if (ev == "activity") {
|
||||
SetDiscordPresenceFromArgs(args);
|
||||
} else {
|
||||
std::cout<<"Unknown event="<<ev<<"\n";
|
||||
}
|
||||
|
|
@ -235,7 +238,7 @@ void HandleEvent(const std::string &ev, std::vector<std::string> &args)
|
|||
void HandleInboundJSON(const std::string &msg)
|
||||
{
|
||||
try {
|
||||
#ifdef DEBUG_BUILD
|
||||
#ifdef DEBUG_LOG
|
||||
std::cout << "[JS -> NATIVE]: " << msg << std::endl;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ void LoadSettings()
|
|||
g_allowZoom = GetPrivateProfileIntW(L"General", L"AllowZoom", 0, iniPath.c_str());
|
||||
g_pauseOnMinimize = (GetPrivateProfileIntW(L"General", L"PauseOnMinimize", 1, iniPath.c_str()) == 1);
|
||||
g_pauseOnLostFocus = (GetPrivateProfileIntW(L"General", L"PauseOnLostFocus", 0, iniPath.c_str()) == 1);
|
||||
g_isRpcOn = (GetPrivateProfileIntW(L"General", L"DiscordRPC", 1, iniPath.c_str()) == 1);
|
||||
//Mpv
|
||||
wchar_t voBuffer[32];
|
||||
GetPrivateProfileStringW(L"MPV", L"VideoOutput", L"gpu-next", voBuffer, 32, iniPath.c_str());
|
||||
|
|
@ -47,12 +48,14 @@ void SaveSettings()
|
|||
const wchar_t* pauseMinVal = g_pauseOnMinimize ? L"1" : L"0";
|
||||
const wchar_t* pauseFocVal = g_pauseOnLostFocus ? L"1" : L"0";
|
||||
const wchar_t* allowZoomVal = g_allowZoom ? L"1" : L"0";
|
||||
const wchar_t* rpcVal = g_isRpcOn ? L"1" : L"0";
|
||||
|
||||
WritePrivateProfileStringW(L"General", L"CloseOnExit", closeVal, iniPath.c_str());
|
||||
WritePrivateProfileStringW(L"General", L"UseDarkTheme", darkVal, iniPath.c_str());
|
||||
WritePrivateProfileStringW(L"General", L"PauseOnMinimize", pauseMinVal, iniPath.c_str());
|
||||
WritePrivateProfileStringW(L"General", L"PauseOnLostFocus", pauseFocVal, iniPath.c_str());
|
||||
WritePrivateProfileStringW(L"General", L"AllowZoom", allowZoomVal, iniPath.c_str());
|
||||
WritePrivateProfileStringW(L"General", L"DiscordRPC", rpcVal, iniPath.c_str());
|
||||
WriteIntToIni(L"MPV", L"InitialVolume", g_currentVolume, iniPath);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "../utils/helpers.h"
|
||||
#include <gdiplus.h>
|
||||
#include <sstream>
|
||||
#include "discord_rpc.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -64,4 +65,6 @@ void Cleanup()
|
|||
if(g_gdiplusToken) {
|
||||
Gdiplus::GdiplusShutdown(g_gdiplusToken);
|
||||
}
|
||||
|
||||
Discord_Shutdown();
|
||||
}
|
||||
|
|
|
|||
166
src/utils/discord.cpp
Normal file
166
src/utils/discord.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#include <iostream>
|
||||
#include "../core/globals.h"
|
||||
#include "crashlog.h"
|
||||
#include "discord_rpc.h"
|
||||
|
||||
void Discord_Ready(const DiscordUser* user) {
|
||||
std::cout << "[DISCORD]: Connected to Discord user: " + std::string(user->username);
|
||||
}
|
||||
|
||||
void Discord_Disconnected(int errorCode, const char* message) {
|
||||
std::cout << "[DISCORD]: Disconnected (" + std::to_string(errorCode) + "): " + std::string(message);
|
||||
}
|
||||
|
||||
void Discord_Error(int errorCode, const char* message) {
|
||||
std::cout << "[DISCORD]: Error (" + std::to_string(errorCode) + "): " + std::string(message);
|
||||
AppendToCrashLog("[DISCORD]: Error (" + std::to_string(errorCode) + "): " + std::string(message));
|
||||
}
|
||||
|
||||
void InitializeDiscord()
|
||||
{
|
||||
DiscordEventHandlers handlers{};
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.ready = Discord_Ready;
|
||||
handlers.disconnected = Discord_Disconnected;
|
||||
handlers.errored = Discord_Error;
|
||||
|
||||
Discord_Initialize("1361448446862692492", &handlers, 1, nullptr);
|
||||
}
|
||||
|
||||
// Encapsulated presence setters
|
||||
|
||||
static void SetDiscordWatchingPresence(
|
||||
const std::vector<std::string>& args
|
||||
) {
|
||||
// expects:
|
||||
// 0: generic "watching" identifier
|
||||
// 1: type (movie, series)
|
||||
// 2: title
|
||||
// 3: season
|
||||
// 4: episode
|
||||
// 5: episode name
|
||||
// 6: episode thumbnail (small image) (Optional)
|
||||
// 7: show/movie image (large image)
|
||||
// 8: elapsed seconds
|
||||
// 9: duration seconds
|
||||
// 10: isPaused ("yes" or "no") (Optional)
|
||||
// 11: more detail button link (imdb link) (Optional)
|
||||
// 12: watch on stremio button link (stremio link) (Optional)
|
||||
DiscordRichPresence discordPresence{};
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
|
||||
discordPresence.type = DISCORD_ACTIVITY_TYPE_WATCHING;
|
||||
|
||||
// Common fields (required)
|
||||
discordPresence.details = args[2].c_str(); // Title
|
||||
discordPresence.largeImageKey = args[7].c_str();
|
||||
discordPresence.largeImageText = args[2].c_str();
|
||||
|
||||
// Handle paused state (optional)
|
||||
bool isPaused = (!args[10].empty() && args[10] == "yes");
|
||||
|
||||
if (isPaused) {
|
||||
discordPresence.state = "Paused";
|
||||
discordPresence.startTimestamp = 0;
|
||||
discordPresence.endTimestamp = 0;
|
||||
} else {
|
||||
std::time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
int elapsedSeconds = std::stoi(args[8]);
|
||||
int durationSeconds = std::stoi(args[9]);
|
||||
|
||||
discordPresence.startTimestamp = currentTime - elapsedSeconds;
|
||||
discordPresence.endTimestamp = currentTime + (durationSeconds - elapsedSeconds);
|
||||
|
||||
if (args[1] == "series") {
|
||||
// Series-specific fields
|
||||
std::string state = args[5] + " (S" + args[3] + "-E" + args[4] + ")";
|
||||
discordPresence.state = state.c_str();
|
||||
|
||||
if (!args[6].empty()) {
|
||||
discordPresence.smallImageKey = args[6].c_str();
|
||||
discordPresence.smallImageText = args[5].c_str();
|
||||
}
|
||||
} else {
|
||||
discordPresence.state = "Enjoying a Movie";
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons setup (optional)
|
||||
if (!args[11].empty()) {
|
||||
discordPresence.button1Label = "More Details";
|
||||
discordPresence.button1Url = args[11].c_str();
|
||||
}
|
||||
|
||||
if (!args[12].empty()) {
|
||||
discordPresence.button2Label = "Watch on Stremio";
|
||||
discordPresence.button2Url = args[12].c_str();
|
||||
}
|
||||
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
|
||||
static void SetDiscordMetaDetailPresence(const std::vector<std::string>& args) {
|
||||
// args structure:
|
||||
// 0: embed type ("meta-detail")
|
||||
// 1: type ("movie" or "series")
|
||||
// 2: title
|
||||
// 3: image URL
|
||||
|
||||
DiscordRichPresence discordPresence{};
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
|
||||
discordPresence.type = DISCORD_ACTIVITY_TYPE_WATCHING;
|
||||
discordPresence.details = args[2].c_str(); // Title (show/movie)
|
||||
discordPresence.largeImageKey = args[3].c_str();
|
||||
discordPresence.largeImageText = args[2].c_str();
|
||||
|
||||
// Engaging state
|
||||
discordPresence.state = args[1] == "movie"
|
||||
? "Exploring a Movie"
|
||||
: "Exploring a Series";
|
||||
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
|
||||
static void SetDiscordDiscoverPresence(const char *const details, const char *const state) {
|
||||
std::cout << "[DISCORD]: Setting discover Presence";
|
||||
|
||||
DiscordRichPresence discordPresence{};
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
discordPresence.type = DISCORD_ACTIVITY_TYPE_WATCHING;
|
||||
discordPresence.state = state;
|
||||
discordPresence.details = details;
|
||||
discordPresence.largeImageKey = "https://raw.githubusercontent.com/Stremio/stremio-web/refs/heads/development/images/icon.png";
|
||||
discordPresence.largeImageText = "Stremio";
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
|
||||
void SetDiscordPresenceFromArgs(const std::vector<std::string>& args) {
|
||||
if (!g_isRpcOn || args.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& embedType = args[0];
|
||||
if (embedType == "watching" && args.size() >= 12) {
|
||||
SetDiscordWatchingPresence(args);
|
||||
} else if (embedType == "meta-detail" && args.size() >= 4) {
|
||||
SetDiscordMetaDetailPresence(args);
|
||||
} else if (embedType == "board") {
|
||||
SetDiscordDiscoverPresence("Resuming Favorites", "On Board");
|
||||
} else if (embedType == "discover") {
|
||||
SetDiscordDiscoverPresence("Finding New Gems", "In Discover");
|
||||
} else if (embedType == "library") {
|
||||
SetDiscordDiscoverPresence("Revisiting Old Favorites", "In Library");
|
||||
} else if (embedType == "calendar") {
|
||||
SetDiscordDiscoverPresence("Planning My Next Binge", "On Calendar");
|
||||
} else if (embedType == "addons") {
|
||||
SetDiscordDiscoverPresence("Exploring Add-ons", "In Add-ons");
|
||||
} else if (embedType == "settings") {
|
||||
SetDiscordDiscoverPresence("Tuning Preferences", "In Settings");
|
||||
} else if (embedType == "search") {
|
||||
SetDiscordDiscoverPresence("Searching for Shows & Movies", "In Search");
|
||||
} else if (embedType == "clear") {
|
||||
Discord_ClearPresence();
|
||||
}
|
||||
// Add more presence types here...
|
||||
}
|
||||
7
src/utils/discord.h
Normal file
7
src/utils/discord.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef STREMIO_DISCORD_H
|
||||
#define STREMIO_DISCORD_H
|
||||
|
||||
void InitializeDiscord();
|
||||
void SetDiscordPresenceFromArgs(const std::vector<std::string>& args);
|
||||
|
||||
#endif
|
||||
|
|
@ -267,7 +267,7 @@ void InitWebView2(HWND hWnd)
|
|||
if (!settings) return E_FAIL;
|
||||
|
||||
if(settings) {
|
||||
#ifndef DEBUG_BUILD
|
||||
#ifndef DEBUG_LOG
|
||||
settings->put_AreDevToolsEnabled(FALSE);
|
||||
#endif
|
||||
settings->put_IsStatusBarEnabled(FALSE);
|
||||
|
|
@ -392,7 +392,7 @@ static void SetupWebMessageHandler()
|
|||
HRESULT hr = args->get_MenuItems(&items);
|
||||
if (FAILED(hr) || !items) return hr;
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
#ifdef DEBUG_LOG
|
||||
return S_OK; //DEV TOOLS DEBUG ONLY
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue