mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2026-04-17 09:33:01 -05:00
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:
52
plugins/discordPresence/README.md
Normal file
52
plugins/discordPresence/README.md
Normal 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}`
|
||||
@@ -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] ?? "");
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user