Add template config vars to Discord Presence plugin (#300)

* Add templated config strings to Discord Presence

* Fix sub/small tag on README.md
This commit is contained in:
dopepump
2024-05-11 13:11:51 +01:00
committed by GitHub
parent e2ce4b04de
commit 0a2c783081
3 changed files with 146 additions and 24 deletions

View File

@@ -0,0 +1,52 @@
# Presence
A plugin which shows the metadata of the currently playing scene as your Discord presence
## Setup
### Prerequisites to get the plugin working
- Download and run [Discord RPC Server](https://github.com/lolamtisch/Discord-RPC-Extension/releases). You **do not** need any browser extensions.
- Install [`StashUserscriptLibrary`](https://github.com/stashapp/CommunityScripts/tree/main/plugins/stashUserscriptLibrary) from your Stash plugin menu (if you don't already have it)
#### Why the desktop app?
<sub>
This plugin relies on a separate desktop app (Discord RPC Server) running in the background. This is required because only a local app can talk to your Discord client to set a custom presence. The ability to do so from a website/browser is whitelisted by Discord (otherwise any website you visit could change your Discord client presence). Discord RPC Server is an open source application which exposes a websocket connection, so that other browser scripts and extensions (i.e. this plugin) can send presence updates to it, which it then forwards to your Discord client.
</sub>
## Configuration
You can customize almost any part of the activity presence with the plugin options.
| Presence element | Default value (if empty; reverts to: ) | Plugin setting name | Configuration |
| --------------------- | --------------------------------------- | ----------------------------- | ------------- |
| Activity name | `1236860180407521341` (displays "Stash") | Custom Discord application ID | Create a new application under your [Discord developer portal](https://discord.com/developers/applications). <sub>The name of the application will be the name of the activity being shown as "Playing". Copy the `APPLICATION ID` (20 digit number) from the Developer Portal, and set it in the plugin options.</sub> |
| Details (first line) | `{title}` | Presence details text | Custom text and variables |
| State (second line) | `from {studio_name}` | Presence state text | Custom text and variables |
| Show activity image | Off | Show presence image | Toggle switch |
| Custom activity image | `stashbox` | Custom presence image key | After creating a Discord app (see first config option), go to your application settings > Rich Presence > Art Assets. Upload your custom image, give it a key name, and put this in the plugin option (takes a short while for the asset to appear after uploading). |
| Activity hover text | Empty | Custom image text | Custom text and variables |
| Show URL button | Off | Show scene URL button | Toggle switch |
| Custom button text | `Watch` | Custom button text | Custom text and variables |
## String variables
You can insert metadata from the currently playing scene into configurable elements, by enclosing variables in curly braces.
For example, if you were watching a scene called "Kittens" and wanted to display "Watching Kittens" under the presence details, you would set the config option to `Watching {title}`.
Below are a list of available variable names:
- `{id}`
- `{title}`
- `{code}`
- `{details}`
- `{director}`
- `{date}`
- `{rating100}`
- `{o_counter}`
- `{organized}`
- `{interactive}`
- `{interactive_speed}`
- `{created_at}`
- `{updated_at}`
- `{resume_time}`
- `{last_played_at}`
- `{play_duration}`
- `{play_count}`
- `{url}`
- `{studio_name}`
- `{file_duration}`

View File

@@ -2,8 +2,11 @@
/**
* @typedef {{
* discordClientId?: string;
* discordLargeImageKey?: string;
* discordDetailsText?: string;
* discordStateText?: string;
* discordShowImage?: boolean;
* discordLargeImageKey?: string;
* discordLargeImageText?: string;
* discordShowUrlButton?: boolean;
* discordUrlButtonText?: string;
* }} PluginConfig
@@ -11,11 +14,18 @@
/**
* @typedef {{
* id, title, urls?: string[], date,
* files: {duration:number}[], studio?: {id, name}
* id, title, code, details, director, urls?: string[], date, rating100, o_counter,
* organized, interactive, interactive_speed, created_at, updated_at, resume_time,
* last_played_at, play_duration, play_count, files: {duration:number}[], studio?: {id, name}
* }} SceneData
*/
/**
* @typedef {{ studio_name: string, url: string, file_duration: string }
* & Omit<SceneData, ['urls', 'files', 'studio']>
* } FlattenedSceneData
*/
/**
* @typedef {{ data: { findScene: SceneData | null } }} GQLSceneDataResponse
*/
@@ -31,8 +41,22 @@
fragment SceneData on Scene {
id
title
code
details
director
urls
date
rating100
o_counter
organized
interactive
interactive_speed
created_at
updated_at
resume_time
last_played_at
play_duration
play_count
files {
duration
__typename
@@ -68,11 +92,16 @@
/** @type {Required<PluginConfig>} */
const CONFIG = {
// DEFAULTS
discordClientId: "1236860180407521341",
discordDetailsText: "{title}",
discordStateText: "from {studio_name}",
discordShowImage: false,
discordLargeImageKey: "stashbox",
discordShowImage: true,
discordLargeImageText: "Stashapp",
discordShowUrlButton: false,
discordUrlButtonText: "Watch",
...userConfig,
};
@@ -124,6 +153,7 @@
return data.data.configuration.plugins[PLUGIN_ID];
}
/** @return {Promise<FlattenedSceneData | null>} */
async function getSceneData(sceneId) {
if (!sceneId) {
return { sceneData: null, duration: 0 };
@@ -136,11 +166,23 @@
/** @type {GQLSceneDataResponse} */
const data = await stash.callGQL(reqData);
const sceneData = data.data.findScene;
return {
sceneData: data.data.findScene,
duration: data.data.findScene?.files[0]?.duration ?? 0,
if (sceneData === null) {
return null;
}
const newProps = {
studio_name: sceneData.studio?.name ?? "Unknown Studio",
url: sceneData.urls?.length ? sceneData.urls[0] : "",
file_duration: sceneData.files?.length ? sceneData.files[0].duration : 0,
};
delete sceneData.urls;
delete sceneData.studio;
delete sceneData.files;
return { ...sceneData, ...newProps };
}
function clearDiscordActivity() {
@@ -153,29 +195,34 @@
}
async function setDiscordActivity() {
const { sceneData, duration } = await getSceneData(SCENE_ID);
const sceneData = await getSceneData(SCENE_ID);
const url =
CONFIG.discordShowUrlButton && sceneData?.urls.length > 0
? sceneData?.urls[0]
: undefined;
const studio = sceneData?.studio?.name;
if (!sceneData) {
return;
}
const currentTime = getCurrentVideoTime() ?? 0;
const endTimestamp = Date.now() + (duration - currentTime) * 1000;
const endTimestamp =
Date.now() + (sceneData.file_duration - currentTime) * 1000;
let body = {};
if (sceneData !== null) {
body = {
details: sceneData.title,
state: studio ? `by ${studio}` : undefined,
details: replaceVars(CONFIG.discordDetailsText, sceneData),
state: replaceVars(CONFIG.discordStateText, sceneData),
largeImageKey: CONFIG.discordShowImage
? CONFIG.discordLargeImageKey
: undefined,
endTimestamp,
buttons: url
? [{ label: CONFIG.discordUrlButtonText, url }]
largeImageText: replaceVars(CONFIG.discordLargeImageText, sceneData),
endTimestamp: sceneData.file_duration > 0 ? endTimestamp : undefined,
buttons: CONFIG.discordShowUrlButton
? [
{
label: replaceVars(CONFIG.discordUrlButtonText, sceneData),
url: sceneData.url,
},
]
: undefined,
instance: true,
};
@@ -203,4 +250,14 @@
return videoElem.currentTime;
}
/**
* Performs string replacement on templated config vars with scene data
* @param {string} templateStr
* @param {FlattenedSceneData} sceneData
*/
function replaceVars(templateStr, sceneData) {
const pattern = /{\s*(\w+?)\s*}/g;
return templateStr.replace(pattern, (_, token) => sceneData[token] ?? "");
}
})();

View File

@@ -1,19 +1,32 @@
name: Discord Presence
description: Sets currently playing scene data as your Discord status. You need to have the app running on your desktop (https://github.com/lolamtisch/Discord-RPC-Extension/releases). You DO NOT need any browser extensions. Requires Stash Userscript Library.
version: 0.1
description: Sets currently playing scene data as your Discord status. See README for prerequisites and config options (blue link button next to enable/disable button)
url: https://github.com/stashapp/CommunityScripts/tree/main/plugins/discordPresence
version: 0.2
settings:
discordClientId:
displayName: Custom Discord application ID
description: Set a custom client ID, found here https://discord.com/developers/applications
type: STRING
discordLargeImageKey:
displayName: Custom presence image key
description: If using a custom client ID, set a presence image key from https://discord.com/developers/applications/{clientId}/rich-presence/assets
discordDetailsText:
displayName: Presence details text
description: Formats the first line of your presence.
type: STRING
discordStateText:
displayName: Presence state text
description: Formats the second line of your presence.
type: STRING
discordShowImage:
displayName: Show presence image
description: Show the large presence image in your Discord profile (shows Stash logo when using default clientId/imageKey)
type: BOOLEAN
discordLargeImageKey:
displayName: Custom presence image key
description: If using a custom client ID, set a presence image key from https://discord.com/developers/applications/{clientId}/rich-presence/assets
type: STRING
discordLargeImageText:
displayName: Custom image text
description: The text which is shown if a user hover over the activity image (leave blank to disable)
type: STRING
discordShowUrlButton:
displayName: Show scene URL button
description: Show a presence button which links to first scene URL