From 38251861b4df52b99034718a25159d433e3aea03 Mon Sep 17 00:00:00 2001 From: Ossama Jouini Date: Fri, 30 Jan 2026 00:35:30 +0100 Subject: [PATCH 1/2] Added a few screenshot actions --- src/instance.js | 133 ++++++++++++++++++++++++++++++++++++++++++++ src/pluginConfig.js | 63 +++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/src/instance.js b/src/instance.js index ca345d0..a8d09fb 100644 --- a/src/instance.js +++ b/src/instance.js @@ -2302,6 +2302,115 @@ function getInstanceJs(parentClass, addonTriggers, C3) { _TriggerScreenshot = this._TriggerScreenshotBase _TriggerScreenshotSync = this._TriggerScreenshotBase + // Save Screenshot from URL + _SaveScreenshotFromURLBase = this.wrap(super._SaveScreenshotFromURL, async ( + /** @type {string} */ url, + /** @type {Tag} */ tag + ) => { + try { + // Load the image from URL and convert to base64 + const img = new Image(); + img.crossOrigin = 'anonymous'; + + const imageLoaded = new Promise((resolve, reject) => { + img.onload = () => resolve(img); + img.onerror = (e) => reject(new Error('Failed to load image from URL')); + }); + + img.src = url; + await imageLoaded; + + // Get dimensions + const width = img.naturalWidth; + const height = img.naturalHeight; + + // Convert to base64 data URL + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + if (!ctx) { + throw new Error('Failed to get canvas context'); + } + ctx.drawImage(img, 0, 0); + const dataUrl = canvas.toDataURL('image/png'); + + const order = { + url: '/steam/screenshots/save', + body: { + dataUrl, + width, + height, + }, + }; + const answer = await this.ws?.sendAndWaitForResponse(order); + if (answer?.body.success === false) { + throw new Error(answer?.body.error || 'Failed to save screenshot') + } + this._SaveScreenshotFromURLResultValue = answer?.body.data ?? '' + this._SaveScreenshotFromURLErrorValue = '' + + await this.trigger(tag, [ + C3.Plugins.pipelabv2.Cnds.OnSaveScreenshotFromURLSuccess, + C3.Plugins.pipelabv2.Cnds.OnAnySaveScreenshotFromURLSuccess + ]) + } catch (e) { + if (e instanceof Error) { + this._SaveScreenshotFromURLErrorValue = e.message + this._SaveScreenshotFromURLResultValue = '' + await this.trigger(tag, [ + C3.Plugins.pipelabv2.Cnds.OnSaveScreenshotFromURLError, + C3.Plugins.pipelabv2.Cnds.OnAnySaveScreenshotFromURLError + ]) + } + } + }, this.unsupportedEngine) + _SaveScreenshotFromURL = this._SaveScreenshotFromURLBase + _SaveScreenshotFromURLSync = this._SaveScreenshotFromURLBase + + // Add Screenshot to Library + _AddScreenshotToLibraryBase = this.wrap(super._AddScreenshotToLibrary, async ( + /** @type {string} */ filename, + /** @type {string} */ thumbnailFilename, + /** @type {number} */ width, + /** @type {number} */ height, + /** @type {Tag} */ tag + ) => { + try { + /** @type {import('@pipelab/core').MakeInputOutput, 'input'>} */ + const order = { + url: '/steam/raw', + body: { + namespace: 'screenshots', + method: 'addScreenshotToLibrary', + args: [filename, thumbnailFilename || null, width, height], + }, + }; + const answer = await this.ws?.sendAndWaitForResponse(order); + if (answer?.body.success === false) { + throw new Error(answer?.body.error || 'Failed to add screenshot to library') + } + this._AddScreenshotToLibraryResultValue = answer?.body.data ?? -1 + this._AddScreenshotToLibraryErrorValue = '' + + await this.trigger(tag, [ + C3.Plugins.pipelabv2.Cnds.OnAddScreenshotToLibrarySuccess, + C3.Plugins.pipelabv2.Cnds.OnAnyAddScreenshotToLibrarySuccess + ]) + } catch (e) { + if (e instanceof Error) { + this._AddScreenshotToLibraryErrorValue = e.message + this._AddScreenshotToLibraryResultValue = -1 + await this.trigger(tag, [ + C3.Plugins.pipelabv2.Cnds.OnAddScreenshotToLibraryError, + C3.Plugins.pipelabv2.Cnds.OnAnyAddScreenshotToLibraryError + ]) + } + } + }, this.unsupportedEngine) + _AddScreenshotToLibrary = this._AddScreenshotToLibraryBase + _AddScreenshotToLibrarySync = this._AddScreenshotToLibraryBase + // Steam DLC _CheckDLCIsInstalledBase = this.wrap(super._CheckDLCIsInstalled, async ( /** @type {number} */ appId, @@ -3566,6 +3675,16 @@ function getInstanceJs(parentClass, addonTriggers, C3) { _OnTriggerScreenshotError = this.wrap(super._OnTriggerScreenshotError, (/** @type {Tag} */ tag) => this._currentTag === tag) _OnAnyTriggerScreenshotError = this.wrap(super._OnAnyTriggerScreenshotError, () => true) + _OnSaveScreenshotFromURLSuccess = this.wrap(super._OnSaveScreenshotFromURLSuccess, (/** @type {Tag} */ tag) => this._currentTag === tag) + _OnAnySaveScreenshotFromURLSuccess = this.wrap(super._OnAnySaveScreenshotFromURLSuccess, () => true) + _OnSaveScreenshotFromURLError = this.wrap(super._OnSaveScreenshotFromURLError, (/** @type {Tag} */ tag) => this._currentTag === tag) + _OnAnySaveScreenshotFromURLError = this.wrap(super._OnAnySaveScreenshotFromURLError, () => true) + + _OnAddScreenshotToLibrarySuccess = this.wrap(super._OnAddScreenshotToLibrarySuccess, (/** @type {Tag} */ tag) => this._currentTag === tag) + _OnAnyAddScreenshotToLibrarySuccess = this.wrap(super._OnAnyAddScreenshotToLibrarySuccess, () => true) + _OnAddScreenshotToLibraryError = this.wrap(super._OnAddScreenshotToLibraryError, (/** @type {Tag} */ tag) => this._currentTag === tag) + _OnAnyAddScreenshotToLibraryError = this.wrap(super._OnAnyAddScreenshotToLibraryError, () => true) + _OnCheckDLCIsInstalledSuccess = this.wrap(super._OnCheckDLCIsInstalledSuccess, (/** @type {Tag} */ tag) => this._currentTag === tag) _OnAnyCheckDLCIsInstalledSuccess = this.wrap(super._OnAnyCheckDLCIsInstalledSuccess, () => true) _OnCheckDLCIsInstalledError = this.wrap(super._OnCheckDLCIsInstalledError, (/** @type {Tag} */ tag) => this._currentTag === tag) @@ -4130,6 +4249,20 @@ function getInstanceJs(parentClass, addonTriggers, C3) { return this._TriggerScreenshotResultValue }) + _SaveScreenshotFromURLError = this.exprs(super._SaveScreenshotFromURLError, () => { + return this._SaveScreenshotFromURLErrorValue + }) + _SaveScreenshotFromURLResult = this.exprs(super._SaveScreenshotFromURLResult, () => { + return this._SaveScreenshotFromURLResultValue + }) + + _AddScreenshotToLibraryError = this.exprs(super._AddScreenshotToLibraryError, () => { + return this._AddScreenshotToLibraryErrorValue + }) + _AddScreenshotToLibraryResult = this.exprs(super._AddScreenshotToLibraryResult, () => { + return this._AddScreenshotToLibraryResultValue + }) + _CheckDLCIsInstalledError = this.exprs(super._CheckDLCIsInstalledError, () => { return this._CheckDLCIsInstalledErrorValue }) diff --git a/src/pluginConfig.js b/src/pluginConfig.js index e33f9e0..0c4039b 100644 --- a/src/pluginConfig.js +++ b/src/pluginConfig.js @@ -1223,6 +1223,63 @@ const TriggerScreenshot = ACEGenerator("TriggerScreenshot", /** @type {const} */ description: "Captures the current screen and saves to Steam screenshot library", })) +const SaveScreenshotFromURL = ACEGenerator("SaveScreenshotFromURL", /** @type {const} */({ + category: "steam", + highlight: false, + deprecated: false, + params: [ + { + id: 'url', + desc: "The URL of the image to save as a screenshot (will be converted to base64)", + name: "URL", + type: 'string', + initialValue: "\"\"", + } + ], + listName: "Save screenshot from URL", + displayText: "Save screenshot from URL [b]{0}[/b]", + description: "Saves an image from a URL as a Steam screenshot. The image will be loaded, converted to base64, and its dimensions calculated automatically.", +})) + +const AddScreenshotToLibrary = ACEGenerator("AddScreenshotToLibrary", /** @type {const} */({ + category: "steam", + highlight: false, + deprecated: false, + params: [ + { + id: 'filename', + desc: "The absolute path to the screenshot file on disk", + name: "Filename", + type: 'string', + initialValue: "\"\"", + }, + { + id: 'thumbnailFilename', + desc: "Optional absolute path to a thumbnail file (leave empty for no thumbnail)", + name: "Thumbnail Filename", + type: 'string', + initialValue: "\"\"", + }, + { + id: 'width', + desc: "The width of the screenshot in pixels", + name: "Width", + type: 'number', + initialValue: "0", + }, + { + id: 'height', + desc: "The height of the screenshot in pixels", + name: "Height", + type: 'number', + initialValue: "0", + } + ], + listName: "Add screenshot to library", + displayText: "Add screenshot [b]{0}[/b] to library (thumbnail: {1}, size: {2}x{3})", + description: "Adds an existing screenshot file to the Steam screenshot library. Returns the handle of the screenshot.", +})) + // Steam DLC const CheckDLCIsInstalled = ACEGenerator("CheckDLCIsInstalled", /** @type {const} */({ category: "steam", @@ -1789,6 +1846,8 @@ const Config = /** @type {const} */({ ...ActivateToWebPage.actions, ...ActivateToStore.actions, ...TriggerScreenshot.actions, + ...SaveScreenshotFromURL.actions, + ...AddScreenshotToLibrary.actions, ...CheckDLCIsInstalled.actions, ...CreateWorkshopItem.actions, ...UpdateWorkshopItem.actions, @@ -1856,6 +1915,8 @@ const Config = /** @type {const} */({ ...ActivateToWebPage.conditions, ...ActivateToStore.conditions, ...TriggerScreenshot.conditions, + ...SaveScreenshotFromURL.conditions, + ...AddScreenshotToLibrary.conditions, ...CheckDLCIsInstalled.conditions, ...CreateWorkshopItem.conditions, ...UpdateWorkshopItem.conditions, @@ -1994,6 +2055,8 @@ const Config = /** @type {const} */({ ...ActivateToWebPage.expressions, ...ActivateToStore.expressions, ...TriggerScreenshot.expressions, + ...SaveScreenshotFromURL.expressions, + ...AddScreenshotToLibrary.expressions, ...CheckDLCIsInstalled.expressions, ...CreateWorkshopItem.expressions, ...UpdateWorkshopItem.expressions, From 937c9c4be5f81765c222ddebe47ee2d81299b918 Mon Sep 17 00:00:00 2001 From: Ossama Jouini Date: Fri, 30 Jan 2026 00:35:39 +0100 Subject: [PATCH 2/2] readme --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index ee2f680..c71caf4 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,10 @@ When Download type is Around the user, the offsets are the amount of entries aro | Activate Steam overlay to store | Activates the Steam Overlay to the Steam store page for the provided app | App ID *(number)*
Flag *(combo)*
| | Trigger screenshot (synchronous) | Captures the current screen and saves to Steam screenshot library (synchronous) | Tag *(string)*
| | Trigger screenshot | Captures the current screen and saves to Steam screenshot library | | +| Save screenshot from URL (synchronous) | Saves an image from a URL as a Steam screenshot. The image will be loaded, converted to base64, and its dimensions calculated automatically. (synchronous) | URL *(string)*
Tag *(string)*
| +| Save screenshot from URL | Saves an image from a URL as a Steam screenshot. The image will be loaded, converted to base64, and its dimensions calculated automatically. | URL *(string)*
| +| Add screenshot to library (synchronous) | Adds an existing screenshot file to the Steam screenshot library. Returns the handle of the screenshot. (synchronous) | Filename *(string)*
Thumbnail Filename *(string)*
Width *(number)*
Height *(number)*
Tag *(string)*
| +| Add screenshot to library | Adds an existing screenshot file to the Steam screenshot library. Returns the handle of the screenshot. | Filename *(string)*
Thumbnail Filename *(string)*
Width *(number)*
Height *(number)*
| | Check DLC is installed (synchronous) | Checks if the user owns and has installed a specific DLC (synchronous) | DLC App ID *(number)*
Tag *(string)*
| | Check DLC is installed | Checks if the user owns and has installed a specific DLC | DLC App ID *(number)*
| | Create workshop item (synchronous) | Creates a new workshop item for the specified Steam App ID and returns its ID (synchronous) | App ID *(number)*
Tag *(string)*
| @@ -385,6 +389,14 @@ When Download type is Around the user, the offsets are the amount of entries aro | On any "TriggerScreenshot" success | Trigger when any of the "TriggerScreenshot" are executed with success. | | | On "TriggerScreenshot" error | Trigger when the "TriggerScreenshot" failed to execute. | Tag *(string)*
| | On any "TriggerScreenshot" error | Trigger when any of the "TriggerScreenshot" failed to execute. | | +| On "SaveScreenshotFromURL" success | Trigger when the "SaveScreenshotFromURL" is executed with success. | Tag *(string)*
| +| On any "SaveScreenshotFromURL" success | Trigger when any of the "SaveScreenshotFromURL" are executed with success. | | +| On "SaveScreenshotFromURL" error | Trigger when the "SaveScreenshotFromURL" failed to execute. | Tag *(string)*
| +| On any "SaveScreenshotFromURL" error | Trigger when any of the "SaveScreenshotFromURL" failed to execute. | | +| On "AddScreenshotToLibrary" success | Trigger when the "AddScreenshotToLibrary" is executed with success. | Tag *(string)*
| +| On any "AddScreenshotToLibrary" success | Trigger when any of the "AddScreenshotToLibrary" are executed with success. | | +| On "AddScreenshotToLibrary" error | Trigger when the "AddScreenshotToLibrary" failed to execute. | Tag *(string)*
| +| On any "AddScreenshotToLibrary" error | Trigger when any of the "AddScreenshotToLibrary" failed to execute. | | | On "CheckDLCIsInstalled" success | Trigger when the "CheckDLCIsInstalled" is executed with success. | Tag *(string)*
| | On any "CheckDLCIsInstalled" success | Trigger when any of the "CheckDLCIsInstalled" are executed with success. | | | On "CheckDLCIsInstalled" error | Trigger when the "CheckDLCIsInstalled" failed to execute. | Tag *(string)*
| @@ -557,6 +569,10 @@ When Download type is Around the user, the offsets are the amount of entries aro | ActivateToStoreResult | The result of the "ActivateToStore last call" | string | | | TriggerScreenshotError | The error of the "TriggerScreenshot last call" | string | | | TriggerScreenshotResult | The result of the "TriggerScreenshot last call" | string | | +| SaveScreenshotFromURLError | The error of the "SaveScreenshotFromURL last call" | string | | +| SaveScreenshotFromURLResult | The result of the "SaveScreenshotFromURL last call" | string | | +| AddScreenshotToLibraryError | The error of the "AddScreenshotToLibrary last call" | string | | +| AddScreenshotToLibraryResult | The result of the "AddScreenshotToLibrary last call" | string | | | CheckDLCIsInstalledError | The error of the "CheckDLCIsInstalled last call" | string | | | CheckDLCIsInstalledResult | The result of the "CheckDLCIsInstalled last call" | string | | | CreateWorkshopItemError | The error of the "CreateWorkshopItem last call" | string | |