From 6fc25d3fd83f9f6d963ebb08f3a14c8d90debe58 Mon Sep 17 00:00:00 2001 From: Dennis Rijsdijk <70665154+dennisrijsdijk@users.noreply.github.com> Date: Mon, 29 May 2023 23:25:57 +0200 Subject: [PATCH 01/21] Update $arrayElement to return as string --- src/backend/variables/builtin/array-element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/variables/builtin/array-element.js b/src/backend/variables/builtin/array-element.js index de74f482a..0bdb15fec 100644 --- a/src/backend/variables/builtin/array-element.js +++ b/src/backend/variables/builtin/array-element.js @@ -15,11 +15,11 @@ const model = { if (jsonArray) { const array = utils.jsonParse(jsonArray); if (Array.isArray(array)) { - return array[index]; + return JSON.stringify(array[index]); } } return null; } }; -module.exports = model; \ No newline at end of file +module.exports = model; From 7d48c33b2a72fcfed7823fe3980535d544e63c74 Mon Sep 17 00:00:00 2001 From: Raimen <84481540+raimen-ttv@users.noreply.github.com> Date: Wed, 31 May 2023 02:03:09 -0400 Subject: [PATCH 02/21] Added F13-F24 keys to dropdown in key emulation --- src/backend/effects/builtin/control-emulation.js | 12 ++++++++++++ src/gui/js/plugins/select.js | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/backend/effects/builtin/control-emulation.js b/src/backend/effects/builtin/control-emulation.js index b68a499a7..d8a3e0ffe 100644 --- a/src/backend/effects/builtin/control-emulation.js +++ b/src/backend/effects/builtin/control-emulation.js @@ -125,6 +125,18 @@ const effect = { "f10", "f11", "f12", + "f13", + "f14", + "f15", + "f16", + "f17", + "f18", + "f19", + "f20", + "f21", + "f22", + "f23", + "f24", "alt", "control", "shift", diff --git a/src/gui/js/plugins/select.js b/src/gui/js/plugins/select.js index 13af545dc..c1b4605e5 100644 --- a/src/gui/js/plugins/select.js +++ b/src/gui/js/plugins/select.js @@ -28,7 +28,7 @@ var KEY = { DELETE: 46, COMMAND: 91, - MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'" + MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 124: "F13" , 125 : "F14" , 126 : "F15" , 127 : "F16" , 128 : "F17" , 129 : "F18" , 130 : "F19" , 131 : "F20" , 132 : "F21" , 133 : "F22" , 134 : "F23" , 135 : "F24" , 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'" }, isControl: function (e) { From 99a1a62b8dac5ddd277357b844531ddd71194dc5 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sat, 3 Jun 2023 23:16:34 +0100 Subject: [PATCH 03/21] Add Video Metadata Variable and frontendCommunicator callback --- .../variables/builtin-variable-loader.js | 1 + .../variables/builtin/video-metadata.js | 27 ++++++++++ src/gui/app/app-main.js | 5 +- src/gui/app/services/videoDurationService.js | 51 +++++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/backend/variables/builtin/video-metadata.js create mode 100644 src/gui/app/services/videoDurationService.js diff --git a/src/backend/variables/builtin-variable-loader.js b/src/backend/variables/builtin-variable-loader.js index d4fc49cb4..c01be02b7 100644 --- a/src/backend/variables/builtin-variable-loader.js +++ b/src/backend/variables/builtin-variable-loader.js @@ -203,6 +203,7 @@ exports.loadReplaceVariables = () => { 'username-array-raw', 'username-array', 'username', + 'video-metadata', 'view-time', 'whisper-message', 'word' diff --git a/src/backend/variables/builtin/video-metadata.js b/src/backend/variables/builtin/video-metadata.js new file mode 100644 index 000000000..28051db2b --- /dev/null +++ b/src/backend/variables/builtin/video-metadata.js @@ -0,0 +1,27 @@ +"use strict"; + +const { OutputDataType, VariableCategory } = require("../../../shared/variable-constants"); + +const frontendCommunicator = require("../../common/frontend-communicator"); + +const model = { + definition: { + handle: "videoMetadata", + usage: "videoMetadata[filePathOrUrl]", + description: "Attempts to retrieve video metadata.", + categories: [VariableCategory.ADVANCED], + possibleDataOutput: [OutputDataType.NUMBER] + }, + evaluator: async (trigger, url) => { + if (url == null) { + return "[NO URL PROVIDED]"; + } + try { + return JSON.stringify(await frontendCommunicator.fireEventAsync("getVideoMetadata", {url: url})); + } catch (err) { + return "[ERROR FETCHING METADATA]"; + } + } +}; + +module.exports = model; diff --git a/src/gui/app/app-main.js b/src/gui/app/app-main.js index 0414afa88..aead197b7 100644 --- a/src/gui/app/app-main.js +++ b/src/gui/app/app-main.js @@ -121,9 +121,10 @@ scheduledTaskService, channelRewardsService, sortTagsService, - iconsService + iconsService, + videoService ) { - // 'chatMessagesService' is included so its instantiated on app start + // 'chatMessagesService' and 'videoService' are included so they're instantiated on app start connectionService.loadProfiles(); diff --git a/src/gui/app/services/videoDurationService.js b/src/gui/app/services/videoDurationService.js new file mode 100644 index 000000000..9caa53587 --- /dev/null +++ b/src/gui/app/services/videoDurationService.js @@ -0,0 +1,51 @@ +"use strict"; + +(function() { + + const uuid = require("uuid"); + + // This provides methods for playing sounds + + angular + .module("firebotApp") + .factory("videoService", function(backendCommunicator) { + const service = {}; + + service.getVideoMetadata = function (path) { + return new Promise((resolve) => { + const id = "videometadata-" + uuid(); + const videoElement = ``; + $(document.documentElement).append(videoElement); + const video = document.getElementById(id); + video.onloadedmetadata = () => { + const result = { + success: true, + duration: video.duration, + height: video.videoHeight, + width: video.videoWidth + }; + video.remove(); + resolve(result); + }; + + video.onerror = () => { + const result = { + success: false, + error: video.error.message, + path: video.src + }; + video.remove(); + resolve(result); + }; + + video.src = path; + }); + }; + + backendCommunicator.onAsync("getVideoMetadata", async (data) => { + return await service.getVideoMetadata(data.url); + }); + + return service; + }); +}(window.angular)); From 4d2464a4e092c3ee3eac19fe34e996b692990e2b Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sat, 3 Jun 2023 23:17:15 +0100 Subject: [PATCH 04/21] Add Audio Duration variable --- .../variables/builtin-variable-loader.js | 1 + .../variables/builtin/audio-duration.js | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/backend/variables/builtin/audio-duration.js diff --git a/src/backend/variables/builtin-variable-loader.js b/src/backend/variables/builtin-variable-loader.js index c01be02b7..7198dbd3a 100644 --- a/src/backend/variables/builtin-variable-loader.js +++ b/src/backend/variables/builtin-variable-loader.js @@ -31,6 +31,7 @@ exports.loadReplaceVariables = () => { 'array-reverse', 'array-shuffle-raw', 'array-shuffle', + 'audio-duration', 'bits-badge-tier', 'bits-badge-unlocked-message', 'bits-cheered', diff --git a/src/backend/variables/builtin/audio-duration.js b/src/backend/variables/builtin/audio-duration.js new file mode 100644 index 000000000..ebd9d7c5f --- /dev/null +++ b/src/backend/variables/builtin/audio-duration.js @@ -0,0 +1,29 @@ +"use strict"; + +const { OutputDataType, VariableCategory } = require("../../../shared/variable-constants"); + +const frontendCommunicator = require("../../common/frontend-communicator"); + +const model = { + definition: { + handle: "audioDuration", + usage: "audioDuration[filePathOrUrl]", + description: "Attempts to retrieve audio duration.", + categories: [VariableCategory.ADVANCED], + possibleDataOutput: [OutputDataType.NUMBER] + }, + evaluator: async (trigger, url) => { + if (url == null) { + return "[NO URL PROVIDED]"; + } + try { + return await frontendCommunicator.fireEventAsync("getSoundDuration", { + path: url + }); + } catch (err) { + return "[ERROR FETCHING METADATA]"; + } + } +}; + +module.exports = model; From b6b22558d79a2ff27f0e53911b4d37431a69a5a5 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sat, 3 Jun 2023 23:37:15 +0100 Subject: [PATCH 05/21] Remove overlay-dependent retrieval of video duration. --- src/backend/effects/builtin/play-video.js | 28 +++-------------------- src/resources/overlay/js/main.js | 16 ------------- 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index e41ac2bed..6ca56db9e 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -10,6 +10,7 @@ const accountAccess = require("../../common/account-access"); const util = require("../../utility"); const fs = require('fs-extra'); const path = require("path"); +const frontendCommunicator = require('../../common/frontend-communicator'); /** * The Play Video effect @@ -442,31 +443,8 @@ const playVideo = { if (effect.videoType === "YouTube Video") { resourceToken = resourceTokenManager.storeResourcePath(data.filepath, effect.length); } else { - const durationToken = resourceTokenManager.storeResourcePath(data.filepath, 5); - - const durationPromise = new Promise(async (resolve, reject) => { - const listener = (event) => { - try { - if (event.name === "video-duration" && event.data.resourceToken === durationToken) { - webServer.removeListener("overlay-event", listener); - resolve(event.data.duration); - } - } catch (err) { - logger.error("Error while trying to process overlay-event for getVideoDuration: ", err); - reject(err); - } - }; - webServer.on("overlay-event", listener); - }); - - webServer.sendToOverlay("getVideoDuration", { - resourceToken: durationToken, - overlayInstance: data.overlayInstance - }); - - const duration = await durationPromise; - resourceToken = resourceTokenManager.storeResourcePath(data.filepath, duration + 5); - logger.info(`Retrieved duration for video: ${duration}`); + resourceToken = resourceTokenManager.storeResourcePath(data.filepath, + await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath})); } data.resourceToken = resourceToken; diff --git a/src/resources/overlay/js/main.js b/src/resources/overlay/js/main.js index 191d6800c..82fdfa915 100644 --- a/src/resources/overlay/js/main.js +++ b/src/resources/overlay/js/main.js @@ -49,22 +49,6 @@ function overlaySocketConnect(){ return; } - if(event == "getVideoDuration") { - const token = encodeURIComponent(data.meta.resourceToken); - const url = `http://${window.location.hostname}:7472/resource/${token}`; - const videoElement = ` - - `; - $(".wrapper").append(videoElement); - const video = document.getElementById(token); - video.oncanplay = () => { - sendWebsocketEvent("video-duration", {resourceToken: token, duration: Math.ceil(video.duration)}); - video.remove(); - } - } - firebotOverlay.emit(event, data.meta); }; From c011f28172eb6810d3265b654484edb8b06ed02b Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sun, 4 Jun 2023 00:06:59 +0100 Subject: [PATCH 06/21] Return local video to simple wait with new duration --- src/backend/effects/builtin/play-video.js | 16 +++++++++++++--- src/backend/variables/builtin/video-metadata.js | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index 6ca56db9e..6c0f3a709 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -11,6 +11,7 @@ const util = require("../../utility"); const fs = require('fs-extra'); const path = require("path"); const frontendCommunicator = require('../../common/frontend-communicator'); +const { wait } = require("../../utility"); /** * The Play Video effect @@ -440,17 +441,20 @@ const playVideo = { } let resourceToken; + let duration; if (effect.videoType === "YouTube Video") { resourceToken = resourceTokenManager.storeResourcePath(data.filepath, effect.length); } else { - resourceToken = resourceTokenManager.storeResourcePath(data.filepath, - await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath})); + duration = await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath}); + resourceToken = resourceTokenManager.storeResourcePath(data.filepath, duration); } data.resourceToken = resourceToken; webServer.sendToOverlay("video", data); - if (effect.wait) { + if (effect.wait && effect.videoType === "YouTube Video") { + // Use overlay callback for youtube video, needs local way to get duration for production. + // If effect is ran with "Wait for video to finish" while overlay is not open, it may freeze an effect queue. await new Promise(async (resolve, reject) => { const listener = (event) => { try { @@ -465,6 +469,12 @@ const playVideo = { }; webServer.on("overlay-event", listener); }); + } else if (effect.wait && data.videoType === "Local Video") { + let internalDuration = data.videoDuration; + if (internalDuration == null || duration > internalDuration) { + internalDuration = duration; + } + await wait(internalDuration * 1000); } return true; }, diff --git a/src/backend/variables/builtin/video-metadata.js b/src/backend/variables/builtin/video-metadata.js index 28051db2b..ad5a7d2d8 100644 --- a/src/backend/variables/builtin/video-metadata.js +++ b/src/backend/variables/builtin/video-metadata.js @@ -10,7 +10,7 @@ const model = { usage: "videoMetadata[filePathOrUrl]", description: "Attempts to retrieve video metadata.", categories: [VariableCategory.ADVANCED], - possibleDataOutput: [OutputDataType.NUMBER] + possibleDataOutput: [OutputDataType.TEXT] }, evaluator: async (trigger, url) => { if (url == null) { From 8b0fbcbeef6c128d0bb718091a66f0671fe217b4 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sun, 4 Jun 2023 14:46:45 +0100 Subject: [PATCH 07/21] Local Video: proper null/zero check effect duration --- src/backend/effects/builtin/play-video.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index 6c0f3a709..76648cd4d 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -471,7 +471,7 @@ const playVideo = { }); } else if (effect.wait && data.videoType === "Local Video") { let internalDuration = data.videoDuration; - if (internalDuration == null || duration > internalDuration) { + if (internalDuration == null || internalDuration === 0 || internalDuration === "") { internalDuration = duration; } await wait(internalDuration * 1000); From 8480141339eab3546a55b74f6263963ac6acab6f Mon Sep 17 00:00:00 2001 From: CKY- Date: Sun, 4 Jun 2023 22:06:13 -0600 Subject: [PATCH 08/21] feat: Steam Discription, #2176 --- src/backend/chat/commands/builtin/steam/steam-access.js | 4 ++++ src/backend/chat/commands/builtin/steam/steam.js | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/backend/chat/commands/builtin/steam/steam-access.js b/src/backend/chat/commands/builtin/steam/steam-access.js index 1dbc00934..9c2d06a10 100644 --- a/src/backend/chat/commands/builtin/steam/steam-access.js +++ b/src/backend/chat/commands/builtin/steam/steam-access.js @@ -108,6 +108,10 @@ const getSteamGameDetails = async (requestedGame) => { gameDetails.releaseDate = foundGame.release_date.date; } + if (foundGame.short_description) { + gameDetails.shortDescription = foundGame.short_description; + } + return gameDetails; }; diff --git a/src/backend/chat/commands/builtin/steam/steam.js b/src/backend/chat/commands/builtin/steam/steam.js index f4fc324a0..c7eaa57c0 100644 --- a/src/backend/chat/commands/builtin/steam/steam.js +++ b/src/backend/chat/commands/builtin/steam/steam.js @@ -22,7 +22,7 @@ const steam = { outputTemplate: { type: "string", title: "Output Template", - tip: "Variables: {gameName}, {price}, {releaseDate}, {metaCriticScore}, {steamUrl}", + tip: "Variables: {gameName}, {price}, {releaseDate}, {metaCriticScore}, {steamUrl}, {steamShortDescription}", default: `{gameName} (Price: {price} - Released: {releaseDate} - Metacritic: {metaCriticScore}) {steamUrl}`, useTextArea: true } @@ -49,7 +49,8 @@ const steam = { .replace("{price}", gameDetails.price || "Unknown") .replace("{releaseDate}", gameDetails.releaseDate || "Unknown") .replace("{metaCriticScore}", gameDetails.score || "Unknown") - .replace("{steamUrl}", gameDetails.url); + .replace("{steamUrl}", gameDetails.url) + .replace("{steamShortDescription}", gameDetails.shortDescription || "Unknown"); } } From e1cc67c9c61682a8a7d9266032ffbd681f4c68ee Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Mon, 5 Jun 2023 22:58:02 +0100 Subject: [PATCH 09/21] Fix retrieving duration for video play effect --- src/backend/effects/builtin/play-video.js | 4 ++-- src/gui/app/services/videoDurationService.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index 76648cd4d..2e4a715a1 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -445,8 +445,8 @@ const playVideo = { if (effect.videoType === "YouTube Video") { resourceToken = resourceTokenManager.storeResourcePath(data.filepath, effect.length); } else { - duration = await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath}); - resourceToken = resourceTokenManager.storeResourcePath(data.filepath, duration); + const meta = await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath}); + resourceToken = resourceTokenManager.storeResourcePath(data.filepath, meta.duration); } data.resourceToken = resourceToken; diff --git a/src/gui/app/services/videoDurationService.js b/src/gui/app/services/videoDurationService.js index 9caa53587..2e242c2d0 100644 --- a/src/gui/app/services/videoDurationService.js +++ b/src/gui/app/services/videoDurationService.js @@ -43,7 +43,7 @@ }; backendCommunicator.onAsync("getVideoMetadata", async (data) => { - return await service.getVideoMetadata(data.url); + return await service.getVideoMetadata(data.path); }); return service; From d123ba3c9b2b11196c9aad3b8519e3b70c21dbce Mon Sep 17 00:00:00 2001 From: CKY- Date: Mon, 5 Jun 2023 16:49:29 -0600 Subject: [PATCH 10/21] Fix-BTTV-Wide-Emote --- src/gui/app/directives/chat/feed items/chat-message.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/app/directives/chat/feed items/chat-message.js b/src/gui/app/directives/chat/feed items/chat-message.js index 0373ed58e..fd9c780c1 100644 --- a/src/gui/app/directives/chat/feed items/chat-message.js +++ b/src/gui/app/directives/chat/feed items/chat-message.js @@ -126,6 +126,7 @@ class="chatEmoticon" uib-tooltip="{{part.origin}}: {{part.name}}" tooltip-append-to-body="true" + style="width: unset;" > From 0d09901d4da93ea510d22c23feaf715b1fd1e941 Mon Sep 17 00:00:00 2001 From: Dennis Rijsdijk <70665154+dennisrijsdijk@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:19:09 +0200 Subject: [PATCH 11/21] Fix non-object and non-array being stringified --- src/backend/variables/builtin/array-element.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/backend/variables/builtin/array-element.js b/src/backend/variables/builtin/array-element.js index 0bdb15fec..9f7562ddb 100644 --- a/src/backend/variables/builtin/array-element.js +++ b/src/backend/variables/builtin/array-element.js @@ -15,7 +15,12 @@ const model = { if (jsonArray) { const array = utils.jsonParse(jsonArray); if (Array.isArray(array)) { - return JSON.stringify(array[index]); + // Check value for being array or object, otherwise return raw value + if (Array.isArray(array[index]) || Object.prototype.toString.call(array[index]) == "[object Object]") + { + return JSON.stringify(array[index]); + } + return array[index]; } } return null; From df740d74e3567fcd09e1c30d89ce071f0df6d7c2 Mon Sep 17 00:00:00 2001 From: CKY- Date: Tue, 6 Jun 2023 13:45:14 -0600 Subject: [PATCH 12/21] Fix-BidGame-ChatMessages --- src/backend/games/builtin/bid/bid-command.js | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/backend/games/builtin/bid/bid-command.js b/src/backend/games/builtin/bid/bid-command.js index f09e893ab..ee669a372 100644 --- a/src/backend/games/builtin/bid/bid-command.js +++ b/src/backend/games/builtin/bid/bid-command.js @@ -99,7 +99,7 @@ const bidCommand = { ] }, onTriggerEvent: async event => { - const { chatEvent, userCommand } = event; + const { chatMessage, userCommand } = event; const bidSettings = gameManager.getGameSettings("firebot-bid"); const chatter = bidSettings.settings.chatSettings.chatter; @@ -113,17 +113,17 @@ const bidCommand = { const bidAmount = parseInt(triggeredArg); if (isNaN(bidAmount)) { - await twitchChat.sendChatMessage(`Invalid amount. Please enter a number to start bidding.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`Invalid amount. Please enter a number to start bidding.`, null, chatter, chatMessage.id); return; } if (activeBiddingInfo.active !== false) { - await twitchChat.sendChatMessage(`There is already a bid running. Use !bid stop to stop it.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`There is already a bid running. Use !bid stop to stop it.`, null, chatter, chatMessage.id); return; } if (bidAmount < bidSettings.settings.currencySettings.minBid) { - await twitchChat.sendChatMessage(`The opening bid must be more than ${bidSettings.settings.currencySettings.minBid}.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`The opening bid must be more than ${bidSettings.settings.currencySettings.minBid}.`, null, chatter, chatMessage.id); return; } @@ -151,45 +151,45 @@ const bidCommand = { const username = userCommand.commandSender; if (activeBiddingInfo.active === false) { - await twitchChat.sendChatMessage(`There is no active bidding in progress.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`There is no active bidding in progress.`, null, chatter, chatMessage.id); return; } const cooldownExpireTime = cooldownCache.get(username); if (cooldownExpireTime && moment().isBefore(cooldownExpireTime)) { const timeRemainingDisplay = util.secondsForHumans(Math.abs(moment().diff(cooldownExpireTime, 'seconds'))); - await twitchChat.sendChatMessage(`You placed a bid recently! Please wait ${timeRemainingDisplay} before placing another bid.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`You placed a bid recently! Please wait ${timeRemainingDisplay} before placing another bid.`, null, chatter, chatMessage.id); return; } if (activeBiddingInfo.topBidder === username) { - await twitchChat.sendChatMessage("You are already the top bidder. You can't bid against yourself.", null, chatter, chatEvent.id); + await twitchChat.sendChatMessage("You are already the top bidder. You can't bid against yourself.", null, chatter, chatMessage.id); return; } if (bidAmount < 1) { - await twitchChat.sendChatMessage("Bid amount must be more than 0.", null, chatter, chatEvent.id); + await twitchChat.sendChatMessage("Bid amount must be more than 0.", null, chatter, chatMessage.id); return; } const minBid = bidSettings.settings.currencySettings.minBid; if (minBid != null & minBid > 0) { if (bidAmount < minBid) { - await twitchChat.sendChatMessage(`Bid amount must be at least ${minBid} ${currencyName}.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`Bid amount must be at least ${minBid} ${currencyName}.`, null, chatter, chatMessage.id); return; } } const userBalance = await currencyDatabase.getUserCurrencyAmount(username, currencyId); if (userBalance < bidAmount) { - await twitchChat.sendChatMessage(`You don't have enough ${currencyName}!`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`You don't have enough ${currencyName}!`, null, chatter, chatMessage.id); return; } const raiseMinimum = bidSettings.settings.currencySettings.minIncrement; const minimumBidWithRaise = activeBiddingInfo.currentBid + raiseMinimum; if (bidAmount < minimumBidWithRaise) { - await twitchChat.sendChatMessage(`You must bid at least ${minimumBidWithRaise} ${currencyName}.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`You must bid at least ${minimumBidWithRaise} ${currencyName}.`, null, chatter, chatMessage.id); return; } @@ -197,7 +197,7 @@ const bidCommand = { const previousHighBidAmount = activeBiddingInfo.currentBid; if (previousHighBidder != null && previousHighBidder !== "") { await currencyDatabase.adjustCurrencyForUser(previousHighBidder, currencyId, previousHighBidAmount); - await twitchChat.sendChatMessage(`You have been out bid! You've been refunded ${previousHighBidAmount} ${currencyName}.`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`You have been out bid! You've been refunded ${previousHighBidAmount} ${currencyName}.`, null, chatter, chatMessage.id); } await currencyDatabase.adjustCurrencyForUser(username, currencyId, -Math.abs(bidAmount)); @@ -213,7 +213,7 @@ const bidCommand = { cooldownCache.set(username, expireTime, cooldownSecs); } } else { - await twitchChat.sendChatMessage(`Incorrect bid usage: ${userCommand.trigger} [bidAmount]`, null, chatter, chatEvent.id); + await twitchChat.sendChatMessage(`Incorrect bid usage: ${userCommand.trigger} [bidAmount]`, null, chatter, chatMessage.id); } } }; From 34200a174f89f9a19ead111347c447f17aa9f955 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sat, 24 Jun 2023 16:36:07 +0100 Subject: [PATCH 13/21] Expose just video duration, add youtube video duration & improve url handling --- src/backend/effects/builtin/play-video.js | 50 ++++------- .../variables/builtin-variable-loader.js | 5 +- .../{video-metadata.js => video-duration.js} | 17 ++-- .../builtin/youtube-video-duration.js | 30 +++++++ src/gui/app/index.html | 2 + src/gui/app/services/video.service.js | 87 +++++++++++++++++++ src/gui/app/services/videoDurationService.js | 51 ----------- src/shared/youtube-url-parser.js | 44 ++++++++++ 8 files changed, 191 insertions(+), 95 deletions(-) rename src/backend/variables/builtin/{video-metadata.js => video-duration.js} (51%) create mode 100644 src/backend/variables/builtin/youtube-video-duration.js create mode 100644 src/gui/app/services/video.service.js delete mode 100644 src/gui/app/services/videoDurationService.js create mode 100644 src/shared/youtube-url-parser.js diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index 2e4a715a1..59c838098 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -12,6 +12,7 @@ const fs = require('fs-extra'); const path = require("path"); const frontendCommunicator = require('../../common/frontend-communicator'); const { wait } = require("../../utility"); +const { parseYoutubeId } = require("../../../shared/youtube-url-parser"); /** * The Play Video effect @@ -443,10 +444,21 @@ const playVideo = { let resourceToken; let duration; if (effect.videoType === "YouTube Video") { - resourceToken = resourceTokenManager.storeResourcePath(data.filepath, effect.length); + const youtubeData = parseYoutubeId(data.youtubeId); + data.youtubeId = youtubeData.id; + const result = await frontendCommunicator.fireEventAsync("getYoutubeVideoDuration", data.youtubeId); + if (!isNaN(result)) { + duration = result; + } + if (data.videoStarttime == null || data.videoStarttime == "" || data.videoStarttime == 0) { + data.videoStarttime = youtubeData.startTime; + } } else { - const meta = await frontendCommunicator.fireEventAsync("getVideoMetadata", {path: data.filepath}); - resourceToken = resourceTokenManager.storeResourcePath(data.filepath, meta.duration); + const result = await frontendCommunicator.fireEventAsync("getVideoDuration", data.filepath); + if (!isNaN(result)) { + duration = result; + } + resourceToken = resourceTokenManager.storeResourcePath(data.filepath, duration); } data.resourceToken = resourceToken; @@ -625,9 +637,6 @@ const playVideo = { const exitVideo = () => { delete startedVidCache[this.id]; // eslint-disable-line no-undef animateVideoExit(`#${wrapperId}`, exitAnimation, exitDuration, inbetweenAnimation); - setTimeout(function(){ - sendWebsocketEvent("video-end", {resourceToken: token}); // eslint-disable-line no-undef - }, millisecondsFromString(exitDuration)); }; // Remove div after X time. @@ -657,29 +666,6 @@ const playVideo = { $(".wrapper").append(wrappedHtml); - try { - const url = new URL(youtubeId); - if (url.hostname.includes("www.youtube.com")) { - for (const [key, value] of url.searchParams) { - if (key === "v") { - youtubeId = value; - } else if (key === "t") { - videoStarttime = value; - } - } - } - if (url.hostname.includes("youtu.be")) { - youtubeId = url.pathname.replace("/", ""); - for (const [key, value] of url.searchParams) { - if (key === "t") { - videoStarttime = value; - } - } - } - } catch (error) { - //failed to convert url - } - // Add iframe. const playerVars = { @@ -725,9 +711,6 @@ const playVideo = { onStateChange: (event) => { if (event.data === 0 && !videoDuration) { animateVideoExit(`#${wrapperId}`, exitAnimation, exitDuration, inbetweenAnimation); - setTimeout(function(){ - sendWebsocketEvent("video-end", {resourceToken: token}); // eslint-disable-line no-undef - }, millisecondsFromString(exitDuration)); } } } @@ -745,9 +728,6 @@ const playVideo = { if (videoDuration) { setTimeout(function () { animateVideoExit(`#${wrapperId}`, exitAnimation, exitDuration, inbetweenAnimation); - setTimeout(function(){ - sendWebsocketEvent("video-end", {resourceToken: token}); // eslint-disable-line no-undef - }, millisecondsFromString(exitDuration)); }, videoDuration); } } diff --git a/src/backend/variables/builtin-variable-loader.js b/src/backend/variables/builtin-variable-loader.js index 7198dbd3a..874754ed6 100644 --- a/src/backend/variables/builtin-variable-loader.js +++ b/src/backend/variables/builtin-variable-loader.js @@ -204,10 +204,11 @@ exports.loadReplaceVariables = () => { 'username-array-raw', 'username-array', 'username', - 'video-metadata', + 'video-duration', 'view-time', 'whisper-message', - 'word' + 'word', + 'youtube-video-duration' ].forEach(filename => { const definition = require(`./builtin/${filename}`); replaceVariableManager.registerReplaceVariable(definition); diff --git a/src/backend/variables/builtin/video-metadata.js b/src/backend/variables/builtin/video-duration.js similarity index 51% rename from src/backend/variables/builtin/video-metadata.js rename to src/backend/variables/builtin/video-duration.js index ad5a7d2d8..ce05d3681 100644 --- a/src/backend/variables/builtin/video-metadata.js +++ b/src/backend/variables/builtin/video-duration.js @@ -3,12 +3,13 @@ const { OutputDataType, VariableCategory } = require("../../../shared/variable-constants"); const frontendCommunicator = require("../../common/frontend-communicator"); +const logger = require("../../logwrapper"); const model = { definition: { - handle: "videoMetadata", - usage: "videoMetadata[filePathOrUrl]", - description: "Attempts to retrieve video metadata.", + handle: "videoDuration", + usage: "videoDuration[filePathOrUrl]", + description: "Attempts to retrieve video duration.", categories: [VariableCategory.ADVANCED], possibleDataOutput: [OutputDataType.TEXT] }, @@ -16,11 +17,13 @@ const model = { if (url == null) { return "[NO URL PROVIDED]"; } - try { - return JSON.stringify(await frontendCommunicator.fireEventAsync("getVideoMetadata", {url: url})); - } catch (err) { - return "[ERROR FETCHING METADATA]"; + const result = await frontendCommunicator.fireEventAsync("getVideoDuration", url); + + if (isNaN(result)) { + logger.error("Error while retrieving video duration", result); + return "[ERROR FETCHING DURATION]"; } + return result; } }; diff --git a/src/backend/variables/builtin/youtube-video-duration.js b/src/backend/variables/builtin/youtube-video-duration.js new file mode 100644 index 000000000..9c032ebc0 --- /dev/null +++ b/src/backend/variables/builtin/youtube-video-duration.js @@ -0,0 +1,30 @@ +"use strict"; + +const { OutputDataType, VariableCategory } = require("../../../shared/variable-constants"); +const logger = require("../../logwrapper"); +const frontendCommunicator = require("../../common/frontend-communicator"); +const { parseYoutubeId } = require("../../../shared/youtube-url-parser"); + +const model = { + definition: { + handle: "youtubeVideoDuration", + usage: "youtubeVideoDuration[urlOrId]", + description: "Attempts to retrieve youtube video duration.", + categories: [VariableCategory.ADVANCED], + possibleDataOutput: [OutputDataType.TEXT] + }, + evaluator: async (trigger, id) => { + if (id == null) { + return "[NO VIDEO ID PROVIDED]"; + } + const result = await frontendCommunicator.fireEventAsync("getYoutubeVideoDuration", parseYoutubeId(id).id); + + if (isNaN(result)) { + logger.error("Error while retrieving youtube video duration", result); + return "[ERROR FETCHING DURATION]"; + } + return result; + } +}; + +module.exports = model; diff --git a/src/gui/app/index.html b/src/gui/app/index.html index 79ce6c0ce..20d5df52a 100644 --- a/src/gui/app/index.html +++ b/src/gui/app/index.html @@ -89,6 +89,8 @@ + + diff --git a/src/gui/app/services/video.service.js b/src/gui/app/services/video.service.js new file mode 100644 index 000000000..dc1f1cc38 --- /dev/null +++ b/src/gui/app/services/video.service.js @@ -0,0 +1,87 @@ +"use strict"; + +(function() { + + const uuid = require("uuid"); + + // This provides methods for playing sounds + + angular + .module("firebotApp") + .factory("videoService", function(backendCommunicator) { + const service = {}; + + service.getVideoDuration = function (path) { + return new Promise((resolve) => { + const id = "video-" + uuid(); + const videoElement = ``; + $(document.documentElement).append(videoElement); + const video = document.getElementById(id); + video.onloadedmetadata = () => { + resolve(video.duration); + video.remove(); + }; + + video.onerror = () => { + const result = { + error: video.error.message, + path: video.src + }; + video.remove(); + resolve(result); + }; + + video.src = path; + }); + }; + + service.getYoutubeVideoDuration = function (videoId) { + return new Promise((resolve) => { + const id = "video-" + uuid(); + $(document.documentElement).append(``); + // eslint-disable-next-line no-undef + const player = new YT.Player(id, { + videoId: videoId, + events: { + onReady: (event) => { + event.target.setVolume(0); + event.target.playVideo(); + resolve(player.getDuration()); + document.getElementById(id).remove(); + }, + onError: (event) => { + const error = { + code: event.data, + youtubeId: videoId + }; + if (event.data === 2) { + error.error = "The request contains an invalid parameter value."; + } + if (event.data === 5) { + error.error = "The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred."; + } + if (event.data === 100) { + error.error = "The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private."; + } + if (event.data === 101 || event.data === 150) { + error.error = "The owner of the requested video does not allow it to be played in embedded players."; + } + resolve(error); + document.getElementById(id).remove(); + } + } + }); + }); + }; + + backendCommunicator.onAsync("getVideoDuration", async (path) => { + return service.getVideoDuration(path); + }); + + backendCommunicator.onAsync("getYoutubeVideoDuration", async (youtubeId) => { + return service.getYoutubeVideoDuration(youtubeId); + }); + + return service; + }); +}(window.angular)); diff --git a/src/gui/app/services/videoDurationService.js b/src/gui/app/services/videoDurationService.js deleted file mode 100644 index 2e242c2d0..000000000 --- a/src/gui/app/services/videoDurationService.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -(function() { - - const uuid = require("uuid"); - - // This provides methods for playing sounds - - angular - .module("firebotApp") - .factory("videoService", function(backendCommunicator) { - const service = {}; - - service.getVideoMetadata = function (path) { - return new Promise((resolve) => { - const id = "videometadata-" + uuid(); - const videoElement = ``; - $(document.documentElement).append(videoElement); - const video = document.getElementById(id); - video.onloadedmetadata = () => { - const result = { - success: true, - duration: video.duration, - height: video.videoHeight, - width: video.videoWidth - }; - video.remove(); - resolve(result); - }; - - video.onerror = () => { - const result = { - success: false, - error: video.error.message, - path: video.src - }; - video.remove(); - resolve(result); - }; - - video.src = path; - }); - }; - - backendCommunicator.onAsync("getVideoMetadata", async (data) => { - return await service.getVideoMetadata(data.path); - }); - - return service; - }); -}(window.angular)); diff --git a/src/shared/youtube-url-parser.js b/src/shared/youtube-url-parser.js new file mode 100644 index 000000000..a2a7bcc51 --- /dev/null +++ b/src/shared/youtube-url-parser.js @@ -0,0 +1,44 @@ +'use strict'; + +function parseYoutubeId(id) { + if (id.length === 11) { // string is same length as YouTube id + return {id: id}; + } + + let url; + let finalId = id; + let startTime; + + if (!id.startsWith("http")) { + id = "http://" + id; + } + + try { + url = new URL(id); + + if (url.hostname === "youtube.com" || url.hostname === "www.youtube.com") { + if (url.pathname.includes("/shorts/")) { + return {id: url.pathname.replace("/shorts/", "")}; + } + } else if (url.hostname === "youtu.be") { + finalId = url.pathname.replace("/", ""); + } else { + return {id: finalId}; + } + + for (const [key, value] of url.searchParams) { + if (key === "v") { + finalId = value; + } else if (key === "t") { + startTime = value; + } + } + + } catch (error) { + return {id: finalId}; + } + + return {id: finalId, startTime: startTime}; +} + +exports.parseYoutubeId = parseYoutubeId; \ No newline at end of file From 28d48e879a4d6506e6694dd4a235d0df6116da13 Mon Sep 17 00:00:00 2001 From: CKY- Date: Mon, 26 Jun 2023 14:40:41 -0600 Subject: [PATCH 14/21] Feat: create path when wrting file --- src/backend/common/handlers/fileWriterProcessor.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/common/handlers/fileWriterProcessor.js b/src/backend/common/handlers/fileWriterProcessor.js index dad4d7ac4..bdb624a83 100644 --- a/src/backend/common/handlers/fileWriterProcessor.js +++ b/src/backend/common/handlers/fileWriterProcessor.js @@ -1,6 +1,7 @@ "use strict"; const fs = require("fs-extra"); +const path = require("path"); const logger = require("../../logwrapper"); function doesTextExistInFile(filepath, text) { @@ -75,6 +76,7 @@ exports.run = async effect => { fs.appendFileSync(effect.filepath, text + "\n", "utf8"); } } else { + fs.ensureDirSync(path.dirname(effect.filepath)); fs.appendFileSync(effect.filepath, text + "\n", "utf8"); } } else if (effect.writeMode === "delete") { From 90f346b72dff9598ad585896bccdbe2d9340f4cb Mon Sep 17 00:00:00 2001 From: CKY- Date: Fri, 14 Jul 2023 04:10:29 -0600 Subject: [PATCH 15/21] V5-Feat-remove-the-url-for-clip-enpoints --- src/backend/effects/builtin/play-video.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/effects/builtin/play-video.js b/src/backend/effects/builtin/play-video.js index e41ac2bed..52c7f0a95 100644 --- a/src/backend/effects/builtin/play-video.js +++ b/src/backend/effects/builtin/play-video.js @@ -366,7 +366,7 @@ const playVideo = { /**@type {import('@twurple/api').HelixClip} */ let clip; if (effect.videoType === "Twitch Clip") { - clipId = effect.twitchClipUrl.replace("https://clips.twitch.tv/", ""); + clipId = effect.twitchClipUrl.split("/").pop(); try { clip = await client.clips.getClipById(clipId); } catch (error) { From be64e708f3123b13296e0cb1fb381d6dedff3ed2 Mon Sep 17 00:00:00 2001 From: CKY- Date: Fri, 14 Jul 2023 20:26:50 -0600 Subject: [PATCH 16/21] v5-Fix-Heist-maxWager --- src/backend/games/builtin/heist/heist-command.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/games/builtin/heist/heist-command.js b/src/backend/games/builtin/heist/heist-command.js index ed872c850..c11d44008 100644 --- a/src/backend/games/builtin/heist/heist-command.js +++ b/src/backend/games/builtin/heist/heist-command.js @@ -133,7 +133,7 @@ const heistCommand = { if (heistSettings.settings.entryMessages.wagerAmountTooHigh) { const wagerAmountTooHighMsg = heistSettings.settings.entryMessages.wagerAmountTooHigh .replace("{user}", username) - .replace("minWager}", minWager); + .replace("{maxWager}", maxWager); await twitchChat.sendChatMessage(wagerAmountTooHighMsg, null, chatter); } From 3f9c621607ccf5bcdecf2ab09c3e678788216bcd Mon Sep 17 00:00:00 2001 From: CKY- Date: Mon, 17 Jul 2023 06:42:48 -0600 Subject: [PATCH 17/21] v5-feat-reveal-sub-users-array --- .../variables/builtin-variable-loader.js | 6 ++-- src/backend/variables/builtin/sub-users.js | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/backend/variables/builtin/sub-users.js diff --git a/src/backend/variables/builtin-variable-loader.js b/src/backend/variables/builtin-variable-loader.js index d4fc49cb4..df53986e4 100644 --- a/src/backend/variables/builtin-variable-loader.js +++ b/src/backend/variables/builtin-variable-loader.js @@ -1,7 +1,5 @@ "use strict"; - const replaceVariableManager = require("./replace-variable-manager"); - exports.loadReplaceVariables = () => { [ 'account-creation-date', @@ -164,6 +162,7 @@ exports.loadReplaceVariables = () => { 'sub-points', 'sub-streak', 'sub-type', + 'sub-users', 'target', 'text-capitalize', 'text-contains', @@ -210,4 +209,5 @@ exports.loadReplaceVariables = () => { const definition = require(`./builtin/${filename}`); replaceVariableManager.registerReplaceVariable(definition); }); -}; \ No newline at end of file +}; +//# sourceMappingURL=builtin-variable-loader.js.map \ No newline at end of file diff --git a/src/backend/variables/builtin/sub-users.js b/src/backend/variables/builtin/sub-users.js new file mode 100644 index 000000000..121395b8d --- /dev/null +++ b/src/backend/variables/builtin/sub-users.js @@ -0,0 +1,33 @@ +'use strict'; +const { OutputDataType } = require("../../../shared/variable-constants"); +const api = require("../../twitch-api/api"); +const accountAccess = require("../../common/account-access"); +const logger = require("../../logwrapper"); +const model = { + definition: { + handle: "subNames", + description: "Returns an array of user names, of all the subs you currently have. Items contain 'username', 'tier' and 'isGift' properties", + possibleDataOutput: [OutputDataType.TEXT] + }, + evaluator: async () => { + const { streamer } = accountAccess.getAccounts(); + let viewers = []; + try { + const response = await api.streamerClient.subscriptions + .getSubscriptionsPaginated(streamer.channelId).getAll(); + if (response && response.length) { + viewers = response.map(sub => ({ + username: sub.userName, + tier: sub.tier, + isGift: sub.isGift + })); + } + } + catch (err) { + logger.error("Error while fetching streamer subscriptions", err); + } + return JSON.stringify(viewers); + } +}; +module.exports = model; +//# sourceMappingURL=sub-users.js.map \ No newline at end of file From 8e59f2efe79bfa0782c5771b0186c6b0b14e4b59 Mon Sep 17 00:00:00 2001 From: CKY- Date: Mon, 17 Jul 2023 07:01:22 -0600 Subject: [PATCH 18/21] v5-feat-reveal-sub-users-array-fix-broken-file --- src/backend/variables/builtin-variable-loader.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/variables/builtin-variable-loader.js b/src/backend/variables/builtin-variable-loader.js index df53986e4..422b9118f 100644 --- a/src/backend/variables/builtin-variable-loader.js +++ b/src/backend/variables/builtin-variable-loader.js @@ -1,5 +1,7 @@ "use strict"; + const replaceVariableManager = require("./replace-variable-manager"); + exports.loadReplaceVariables = () => { [ 'account-creation-date', @@ -209,5 +211,4 @@ exports.loadReplaceVariables = () => { const definition = require(`./builtin/${filename}`); replaceVariableManager.registerReplaceVariable(definition); }); -}; -//# sourceMappingURL=builtin-variable-loader.js.map \ No newline at end of file +}; \ No newline at end of file From d8ca6f4548c73d1d827ebf153723eaacce740e44 Mon Sep 17 00:00:00 2001 From: CKY- Date: Mon, 17 Jul 2023 07:07:39 -0600 Subject: [PATCH 19/21] more file fix why you VSCODE hate me --- src/backend/variables/builtin/sub-users.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/backend/variables/builtin/sub-users.js b/src/backend/variables/builtin/sub-users.js index 121395b8d..ef5940cbd 100644 --- a/src/backend/variables/builtin/sub-users.js +++ b/src/backend/variables/builtin/sub-users.js @@ -1,12 +1,16 @@ 'use strict'; + const { OutputDataType } = require("../../../shared/variable-constants"); + const api = require("../../twitch-api/api"); const accountAccess = require("../../common/account-access"); const logger = require("../../logwrapper"); + const model = { definition: { handle: "subNames", - description: "Returns an array of user names, of all the subs you currently have. Items contain 'username', 'tier' and 'isGift' properties", + description: "Returns an array of subscriptions you currently have. Items contain 'username', 'tier' and 'isGift' properties", + usage: "Returns: [{username:Firebottle,tier:2000,isGift:false},{username:ebiggz,tier:1000,isGift:true},{username:SReject,tier:3000,isGift:false}]\nTo be used with array or custom variables", possibleDataOutput: [OutputDataType.TEXT] }, evaluator: async () => { @@ -22,12 +26,12 @@ const model = { isGift: sub.isGift })); } - } - catch (err) { + } catch (err) { logger.error("Error while fetching streamer subscriptions", err); } + return JSON.stringify(viewers); } }; -module.exports = model; -//# sourceMappingURL=sub-users.js.map \ No newline at end of file + +module.exports = model; \ No newline at end of file From 3c881ad1d0e5415d1053a315a09f3c3db31b7dff Mon Sep 17 00:00:00 2001 From: CKY- Date: Wed, 19 Jul 2023 04:07:40 -0600 Subject: [PATCH 20/21] fixed the example and usage removed CRLF for LF --- src/backend/variables/builtin/sub-users.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/variables/builtin/sub-users.js b/src/backend/variables/builtin/sub-users.js index ef5940cbd..c5accb8e5 100644 --- a/src/backend/variables/builtin/sub-users.js +++ b/src/backend/variables/builtin/sub-users.js @@ -10,7 +10,13 @@ const model = { definition: { handle: "subNames", description: "Returns an array of subscriptions you currently have. Items contain 'username', 'tier' and 'isGift' properties", - usage: "Returns: [{username:Firebottle,tier:2000,isGift:false},{username:ebiggz,tier:1000,isGift:true},{username:SReject,tier:3000,isGift:false}]\nTo be used with array or custom variables", + usage: "subNames", + examples: [ + { + usage: "subNames", + description: "Returns: [{username:Firebottle,tier:2000,isGift:false},{username:ebiggz,tier:1000,isGift:true},{username:SReject,tier:3000,isGift:false},{username:Perry,tier:1000,isGift:false}] To be used with array or custom variables" + } + ], possibleDataOutput: [OutputDataType.TEXT] }, evaluator: async () => { From b433a7cef4bb0535a32ac9329b0b1edd745754d7 Mon Sep 17 00:00:00 2001 From: Dennis Rijsdijk Date: Sun, 6 Aug 2023 18:52:53 +0200 Subject: [PATCH 21/21] change error output --- src/backend/variables/builtin/audio-duration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/variables/builtin/audio-duration.js b/src/backend/variables/builtin/audio-duration.js index ebd9d7c5f..65642aeba 100644 --- a/src/backend/variables/builtin/audio-duration.js +++ b/src/backend/variables/builtin/audio-duration.js @@ -21,7 +21,7 @@ const model = { path: url }); } catch (err) { - return "[ERROR FETCHING METADATA]"; + return "[ERROR FETCHING DURATION]"; } } };