From 95191a39358f1b1f5b91f599b1f46ddb8e6bd3da Mon Sep 17 00:00:00 2001 From: LordTocs Date: Wed, 7 Aug 2024 13:39:21 -0400 Subject: [PATCH 01/23] Bump Version --- package.json | 2 +- packages/castmate/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d089aa98..b43ae9ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "castmate-monorepo", - "version": "0.5.2", + "version": "0.5.3-beta", "description": "", "private": true, "type": "module", diff --git a/packages/castmate/package.json b/packages/castmate/package.json index 3f6105bc..85d14f3b 100644 --- a/packages/castmate/package.json +++ b/packages/castmate/package.json @@ -1,6 +1,6 @@ { "name": "castmate", - "version": "0.5.2", + "version": "0.5.3-beta", "description": "CastMate", "author": "LordTocs", "scripts": { From f95cf4eee540dead4bf48d48c6a60db5810e6397 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Wed, 7 Aug 2024 13:39:34 -0400 Subject: [PATCH 02/23] Don't brick on update check failure --- libs/castmate-core/src/info/info-manager.ts | 27 +++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/libs/castmate-core/src/info/info-manager.ts b/libs/castmate-core/src/info/info-manager.ts index 2be70a16..e6265527 100644 --- a/libs/castmate-core/src/info/info-manager.ts +++ b/libs/castmate-core/src/info/info-manager.ts @@ -6,7 +6,7 @@ import { defineIPCFunc } from "../util/electron" import electronUpdater, { autoUpdater, UpdateInfo, CancellationToken } from "electron-updater" import { UpdateData } from "castmate-schema" -import { globalLogger } from "../logging/logging" +import { globalLogger, usePluginLogger } from "../logging/logging" import path from "path" import semver from "semver" @@ -15,6 +15,8 @@ interface StartInfo { lastVer: string } +const logger = usePluginLogger("info-manager") + export const InfoService = Service( class { startInfo: StartInfo | undefined @@ -81,18 +83,23 @@ export const InfoService = Service( } async checkUpdate() { - const result = await autoUpdater.checkForUpdates() - if (result != null) { - if (semver.gt(result.updateInfo.version, app.getVersion())) { - globalLogger.log("Update!", result.updateInfo.releaseName, result.updateInfo.version) - this.updateInfo = result.updateInfo - return true + try { + const result = await autoUpdater.checkForUpdates() + if (result != null) { + if (semver.gt(result.updateInfo.version, app.getVersion())) { + globalLogger.log("Update!", result.updateInfo.releaseName, result.updateInfo.version) + this.updateInfo = result.updateInfo + return true + } + return false + } else { + globalLogger.log("No Update :(") } return false - } else { - globalLogger.log("No Update :(") + } catch (err) { + logger.error("Error Checking Update", err) + return false } - return false } async checkInfo() { From 8004dbb248b257832b4b4cdc2ac5830a913dcc5b Mon Sep 17 00:00:00 2001 From: LordTocs Date: Wed, 7 Aug 2024 13:39:52 -0400 Subject: [PATCH 03/23] More timings and don't do follow check for a test --- plugins/twitch/main/src/channelpoints.ts | 68 +++++++++++++----------- plugins/twitch/main/src/follows.ts | 8 ++- plugins/twitch/main/src/hype-train.ts | 8 ++- plugins/twitch/main/src/viewer-cache.ts | 8 ++- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/plugins/twitch/main/src/channelpoints.ts b/plugins/twitch/main/src/channelpoints.ts index bbda4357..1e4a93c0 100644 --- a/plugins/twitch/main/src/channelpoints.ts +++ b/plugins/twitch/main/src/channelpoints.ts @@ -7,6 +7,7 @@ import { onLoad, onProfilesChanged, runOnChange, + startPerfTime, template, templateSchema, usePluginLogger, @@ -444,50 +445,55 @@ export function setupChannelPointRewards() { } async function loadRewards() { - const channelAccount = TwitchAccount.channel + const perf = startPerfTime(`Load Rewards`) + try { + const channelAccount = TwitchAccount.channel - if (!channelAccount.config.isAffiliate) { - logger.log("Not Affiliate Skipping Rewards") - return - } + if (!channelAccount.config.isAffiliate) { + logger.log("Not Affiliate Skipping Rewards") + return + } - const channelId = channelAccount.config.twitchId + const channelId = channelAccount.config.twitchId - await clearNonCastMateRewards() + await clearNonCastMateRewards() - //Unforunately there's no way to query for rewards not controlled by this client id - //We can only query for all rewards and rewards we control - //Query both. - const rewards = await channelAccount.apiClient.channelPoints.getCustomRewards(channelId) - const castMateRewards = await channelAccount.apiClient.channelPoints.getCustomRewards(channelId, true) + //Unforunately there's no way to query for rewards not controlled by this client id + //We can only query for all rewards and rewards we control + //Query both. + const rewards = await channelAccount.apiClient.channelPoints.getCustomRewards(channelId) + const castMateRewards = await channelAccount.apiClient.channelPoints.getCustomRewards(channelId, true) - //Filter for non-castmate controllable rewards - const nonCastMateRewards = rewards.filter((r) => castMateRewards.find((o) => o.id == r.id) == null) + //Filter for non-castmate controllable rewards + const nonCastMateRewards = rewards.filter((r) => castMateRewards.find((o) => o.id == r.id) == null) - //Load all the non-castmate rewards into resources - await Promise.all(nonCastMateRewards.map((r) => ChannelPointReward.createNonCastmateReward(r))) + //Load all the non-castmate rewards into resources + await Promise.all(nonCastMateRewards.map((r) => ChannelPointReward.createNonCastmateReward(r))) - for (const reward of castMateRewards) { - const cpr = ChannelPointReward.getByTwitchId(reward.id) + for (const reward of castMateRewards) { + const cpr = ChannelPointReward.getByTwitchId(reward.id) - //This reward is controllable but doesn't have a locally stored resource, create it now - if (!cpr) { - await ChannelPointReward.recoverLocalReward(reward) - //Add this to the reward list so we handle it properly in the next step + //This reward is controllable but doesn't have a locally stored resource, create it now + if (!cpr) { + await ChannelPointReward.recoverLocalReward(reward) + //Add this to the reward list so we handle it properly in the next step + } } - } - for (const reward of ChannelPointReward.storage) { - if (!reward.config.controllable) continue + for (const reward of ChannelPointReward.storage) { + if (!reward.config.controllable) continue - const twitchReward = castMateRewards.find((r) => r.id == reward.config.twitchId) + const twitchReward = castMateRewards.find((r) => r.id == reward.config.twitchId) - try { - await reward.initializeFromTwurple(twitchReward) - await reward.initializeReactivity() - } catch (err) { - logger.error("Error Initializing Reward", reward.config.name, err) + try { + await reward.initializeFromTwurple(twitchReward) + await reward.initializeReactivity() + } catch (err) { + logger.error("Error Initializing Reward", reward.config.name, err) + } } + } finally { + perf.stop(logger) } } diff --git a/plugins/twitch/main/src/follows.ts b/plugins/twitch/main/src/follows.ts index 8f94e5bf..f382dc77 100644 --- a/plugins/twitch/main/src/follows.ts +++ b/plugins/twitch/main/src/follows.ts @@ -1,4 +1,4 @@ -import { defineState, defineTrigger } from "castmate-core" +import { defineState, defineTrigger, startPerfTime, usePluginLogger } from "castmate-core" import { onChannelAuth } from "./api-harness" import { ViewerCache } from "./viewer-cache" import { TwitchViewer, TwitchViewerGroup } from "castmate-plugin-twitch-shared" @@ -6,6 +6,8 @@ import { inTwitchViewerGroup } from "./group" import { TwitchAccount } from "./twitch-auth" export function setupFollows() { + const logger = usePluginLogger() + const follow = defineTrigger({ id: "follow", name: "Followed", @@ -44,6 +46,8 @@ export function setupFollows() { }) async function updateFollowCount() { + const perf = startPerfTime(`Follow Count Update`) + const followersResp = await TwitchAccount.channel.apiClient.channels.getChannelFollowers( TwitchAccount.channel.twitchId ) @@ -52,6 +56,8 @@ export function setupFollows() { followers.value = followersResp.total lastFollower.value = await ViewerCache.getInstance().getResolvedViewer(followersResp.data[0].userId) + + perf.stop(logger) } onChannelAuth(async (account, service) => { diff --git a/plugins/twitch/main/src/hype-train.ts b/plugins/twitch/main/src/hype-train.ts index 3e3a13de..841b5e5c 100644 --- a/plugins/twitch/main/src/hype-train.ts +++ b/plugins/twitch/main/src/hype-train.ts @@ -1,8 +1,10 @@ -import { defineState, defineTrigger } from "castmate-core" +import { defineState, defineTrigger, startPerfTime, usePluginLogger } from "castmate-core" import { Range } from "castmate-schema" import { onChannelAuth } from "./api-harness" export function setupHypeTrains() { + const logger = usePluginLogger() + const hypeTrainStarted = defineTrigger({ id: "hypeTrainStarted", name: "Hype Train Started", @@ -118,6 +120,8 @@ export function setupHypeTrains() { }) onChannelAuth(async (channel, service) => { + const perf = startPerfTime(`HypeTrains`) + service.eventsub.onChannelHypeTrainBegin(channel.twitchId, (event) => { hypeTrainLevel.value = event.level hypeTrainProgress.value = event.progress @@ -183,5 +187,7 @@ export function setupHypeTrains() { hypeTrainExists.value = true } } + + perf.stop(logger) }) } diff --git a/plugins/twitch/main/src/viewer-cache.ts b/plugins/twitch/main/src/viewer-cache.ts index a423ee53..18261c1b 100644 --- a/plugins/twitch/main/src/viewer-cache.ts +++ b/plugins/twitch/main/src/viewer-cache.ts @@ -521,7 +521,7 @@ export const ViewerCache = Service( } async getResolvedViewers(userIds: string[]): Promise { - const perf = startPerfTime("Resolve Viewer") + const perf = startPerfTime(`Resolve Viewers ${userIds.length}`) try { const neededSubIds: string[] = [] const neededColorIds: string[] = [] @@ -554,18 +554,22 @@ export const ViewerCache = Service( const queryPromises: Promise[] = [] if (neededColorIds.length > 0) { + logger.log("---Querying Colors:", neededColorIds.length) queryPromises.push(this.queryColor(...neededColorIds)) } if (neededFollowerIds.length > 0) { - queryPromises.push(this.queryFollowing(...neededFollowerIds)) + logger.log("---Querying Following:", neededFollowerIds.length) + //queryPromises.push(this.queryFollowing(...neededFollowerIds)) } if (neededSubIds.length > 0) { + logger.log("---Querying Subs:", neededSubIds.length) queryPromises.push(this.querySubInfo(...neededSubIds)) } if (neededUserInfoIds.length > 0) { + logger.log("---Query User Infos:", neededUserInfoIds.length) queryPromises.push(this.queryUserInfo(...neededUserInfoIds)) } From 46b2b87334fff46f2e2546fce0947e9fb54a095a Mon Sep 17 00:00:00 2001 From: LordTocs Date: Sun, 18 Aug 2024 18:04:59 -0400 Subject: [PATCH 04/23] Fix Viewer Cache when you have over 100 unknowns in the cache getNValues() could return more than N values. This is bad! --- plugins/twitch/main/src/viewer-cache.ts | 51 +++++++++++++++++++++---- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/plugins/twitch/main/src/viewer-cache.ts b/plugins/twitch/main/src/viewer-cache.ts index 18261c1b..018b9904 100644 --- a/plugins/twitch/main/src/viewer-cache.ts +++ b/plugins/twitch/main/src/viewer-cache.ts @@ -56,14 +56,12 @@ function getNValues(set: Set, requiredValues: T[], n: number): T[] { return result } - let count = 0 for (const v of set) { if (requiredValues.includes(v)) { continue } result.push(v) - count++ - if (count >= n) { + if (result.length >= n) { break } } @@ -269,17 +267,27 @@ export const ViewerCache = Service( } private async queryColor(...userIds: string[]) { + const perf1 = startPerfTime("Query Color User Gather") const ids = getNValues(this.unknownColors, userIds, 100) + perf1.stop(logger) + try { + const perf2 = startPerfTime(`Run Query Color ${ids.length}`) const colors = await TwitchAccount.channel.apiClient.chat.getColorsForUsers(ids) + perf2.stop(logger) + const perf3 = startPerfTime("Update Colors") for (const [id, color] of colors) { //TODO: Default color for the unchosen this.get(id).color = (color as Color) ?? "default" } removeValues(this.unknownColors, ids) - } catch (err) {} + perf3.stop(logger) + } catch (err) { + logger.error("Error Querying Colors!", err) + logger.error("IDS", ids) + } } async getChatColor(userId: string): Promise { @@ -385,12 +393,17 @@ export const ViewerCache = Service( try { userIds = userIds.filter((id) => id != "anonymous") + const perf1 = startPerfTime("Running Follow Queries") + //Annoyingly check each follow independently const followingPromises = userIds.map((id) => TwitchAccount.channel.apiClient.channels.getChannelFollowers(TwitchAccount.channel.twitchId, id) ) const followingResults = await Promise.all(followingPromises) + perf1.stop(logger) + + const perf2 = startPerfTime("Updating Follows") for (let i = 0; i < userIds.length; ++i) { const cached = this.get(userIds[i]) @@ -407,7 +420,11 @@ export const ViewerCache = Service( cached.following = true //cached.followDate = following.data[0].followDate } - } catch (err) {} + perf2.stop(logger) + } catch (err) { + logger.error("Error Querying Follows", err) + logger.error("IDS", userIds) + } } async getIsFollowing(userId: string): Promise { @@ -443,14 +460,19 @@ export const ViewerCache = Service( } private async querySubInfo(...userIds: string[]) { + const perf1 = startPerfTime("Query Subs Gather Users") const ids = getNValues(this.unknownSubInfo, userIds, 100) + perf1.stop(logger) try { + const perf2 = startPerfTime(`Run Query Subs ${ids.length}`) const subs = await TwitchAccount.channel.apiClient.subscriptions.getSubscriptionsForUsers( TwitchAccount.channel.twitchId, ids ) + perf2.stop(logger) + const perf3 = startPerfTime("Update Subs") const leftOvers = new Set(ids) for (const sub of subs) { @@ -473,7 +495,11 @@ export const ViewerCache = Service( } removeValues(this.unknownSubInfo, ids) - } catch (err) {} + perf3.stop(logger) + } catch (err) { + logger.error("Error Querying Subs!", err) + logger.error("IDS", ids) + } } async getIsSubbed(userId: string) { @@ -499,10 +525,15 @@ export const ViewerCache = Service( } private async queryUserInfo(...userIds: string[]) { + const perf1 = startPerfTime("Query User Gather") const ids = getNValues(this.unknownUserInfo, userIds, 100) + perf1.stop(logger) try { + const perf2 = startPerfTime(`Run Get Users Query ${ids.length}`) const users = await TwitchAccount.channel.apiClient.users.getUsersByIds(ids) + perf2.stop(logger) + const perf3 = startPerfTime(`Update User Info`) for (const user of users) { const cached = this.getOrCreate(user.id) @@ -513,7 +544,11 @@ export const ViewerCache = Service( this.unknownUserInfo.delete(user.id) } - } catch (err) {} + perf3.stop(logger) + } catch (err) { + logger.error("Error Updating Users!", err) + logger.error("IDS", ids) + } } async getResolvedViewer(userId: string) { @@ -560,7 +595,7 @@ export const ViewerCache = Service( if (neededFollowerIds.length > 0) { logger.log("---Querying Following:", neededFollowerIds.length) - //queryPromises.push(this.queryFollowing(...neededFollowerIds)) + queryPromises.push(this.queryFollowing(...neededFollowerIds)) } if (neededSubIds.length > 0) { From c954eea2f7d368e6c199b38aaca795a0a8b489f6 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Sun, 18 Aug 2024 19:12:28 -0400 Subject: [PATCH 05/23] Add enum resolution to labels on actions --- .../automation/DefaultActionComponent.vue | 2 +- .../data/views/EnumableDataView.vue | 68 +++++++++++++++++++ libs/castmate-ui-core/src/util/data.ts | 6 +- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 libs/castmate-ui-core/src/components/data/views/EnumableDataView.vue diff --git a/libs/castmate-ui-core/src/components/automation/DefaultActionComponent.vue b/libs/castmate-ui-core/src/components/automation/DefaultActionComponent.vue index 7b6e5524..fbe0a6d3 100644 --- a/libs/castmate-ui-core/src/components/automation/DefaultActionComponent.vue +++ b/libs/castmate-ui-core/src/components/automation/DefaultActionComponent.vue @@ -1,7 +1,7 @@ diff --git a/libs/castmate-ui-core/src/components/data/views/EnumableDataView.vue b/libs/castmate-ui-core/src/components/data/views/EnumableDataView.vue new file mode 100644 index 00000000..b86199c8 --- /dev/null +++ b/libs/castmate-ui-core/src/components/data/views/EnumableDataView.vue @@ -0,0 +1,68 @@ + + + diff --git a/libs/castmate-ui-core/src/util/data.ts b/libs/castmate-ui-core/src/util/data.ts index 06c62981..366d4d47 100644 --- a/libs/castmate-ui-core/src/util/data.ts +++ b/libs/castmate-ui-core/src/util/data.ts @@ -56,7 +56,7 @@ import DurationInputVue from "../components/data/inputs/DurationInput.vue" import DynamicTypeInputVue from "../components/data/inputs/DynamicTypeInput.vue" import DirectoryInputVue from "../components/data/inputs/DirectoryInput.vue" -import GenericDataViewVue from "../components/data/views/GenericDataView.vue" +import EnumableDataView from "../components/data/views/EnumableDataView.vue" import BooleanViewVue from "../components/data/views/BooleanView.vue" import ColorViewVue from "../components/data/views/ColorView.vue" import DurationViewVue from "../components/data/views/DurationView.vue" @@ -342,8 +342,8 @@ export function initData() { inputStore.registerInputComponent(FilePath, FilePathInputVue) inputStore.registerInputComponent(Command, CommandInputVue) - inputStore.registerViewComponent(String, GenericDataViewVue) - inputStore.registerViewComponent(Number, GenericDataViewVue) + inputStore.registerViewComponent(String, EnumableDataView) + inputStore.registerViewComponent(Number, EnumableDataView) inputStore.registerViewComponent(Boolean, BooleanViewVue) inputStore.registerViewComponent(Object, ObjectViewVue) inputStore.registerViewComponent(Range, RangeViewVue) From e3a83e49e99ee0ab791052e04877ed353044e33f Mon Sep 17 00:00:00 2001 From: LordTocs Date: Sun, 18 Aug 2024 19:12:53 -0400 Subject: [PATCH 06/23] Groups in OBS are implemented as weird scenes Add helpers for resolving scene items inside of groups Add groups to the scene list for some actions --- plugins/obs/main/src/connection.ts | 31 +++++++++++++++++++++++++++++- plugins/obs/main/src/media.ts | 2 +- plugins/obs/main/src/scenes.ts | 2 +- plugins/obs/main/src/sources.ts | 2 +- plugins/obs/main/src/transform.ts | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/plugins/obs/main/src/connection.ts b/plugins/obs/main/src/connection.ts index 4426f142..7220e255 100644 --- a/plugins/obs/main/src/connection.ts +++ b/plugins/obs/main/src/connection.ts @@ -306,6 +306,21 @@ export class OBSConnection extends FileResource { + try { + logger.log("Fetching Scene/Group Names") + const [sceneResp, groupResp] = await Promise.all([ + this.connection.call("GetSceneList"), + this.connection.call("GetGroupList"), + ]) + const scenes = sceneResp.scenes as unknown as OBSSceneListItem[] + const groups = groupResp.groups as unknown as string[] + return [...scenes.map((s) => s.sceneName).reverse(), ...groups] + } catch (err) { + return [] + } + } + async getInputs(inputKinds?: string | string[]): Promise { try { if (Array.isArray(inputKinds)) { @@ -343,7 +358,21 @@ export class OBSConnection extends FileResource inputKinds.includes(i.inputKind)) + } else if (inputKinds) { + items = items.filter((i) => i.inputKind == inputKinds) + } + return items.map((i) => ({ + name: i.sourceName, + value: i.sceneItemId, + })) + } catch (err) { + return [] + } } } diff --git a/plugins/obs/main/src/media.ts b/plugins/obs/main/src/media.ts index aca102df..71ca4410 100644 --- a/plugins/obs/main/src/media.ts +++ b/plugins/obs/main/src/media.ts @@ -139,7 +139,7 @@ export function setupMedia(obsDefault: ReactiveRef) { type: String, required: true, async enum(context: { obs: OBSConnection }) { - return (await context?.obs?.getSceneNames()) ?? [] + return (await context?.obs?.getSceneAndGroupNames()) ?? [] }, }, source: { diff --git a/plugins/obs/main/src/scenes.ts b/plugins/obs/main/src/scenes.ts index 3fa6c7e5..5b5ac95d 100644 --- a/plugins/obs/main/src/scenes.ts +++ b/plugins/obs/main/src/scenes.ts @@ -22,7 +22,7 @@ export function setupScenes(obsDefault: ReactiveRef) { required: true, //template: true, async enum(context: { obs: OBSConnection }) { - return (await context?.obs?.getSceneNames()) ?? [] + return (await context?.obs?.getSceneAndGroupNames()) ?? [] }, }, }, diff --git a/plugins/obs/main/src/sources.ts b/plugins/obs/main/src/sources.ts index 27088a92..57c56fd3 100644 --- a/plugins/obs/main/src/sources.ts +++ b/plugins/obs/main/src/sources.ts @@ -23,7 +23,7 @@ export function setupSources(obsDefault: ReactiveRef) { name: "Scene", template: true, async enum(context: { obs: OBSConnection }) { - return (await context?.obs?.getSceneNames()) ?? [] + return (await context?.obs?.getSceneAndGroupNames()) ?? [] }, }, source: { diff --git a/plugins/obs/main/src/transform.ts b/plugins/obs/main/src/transform.ts index ac7982d9..24dc7e4a 100644 --- a/plugins/obs/main/src/transform.ts +++ b/plugins/obs/main/src/transform.ts @@ -26,7 +26,7 @@ export function setupTransforms(obsDefault: ReactiveRef) { required: true, name: "Scene", async enum(context: { obs: OBSConnection }) { - return (await context?.obs?.getSceneNames()) ?? [] + return (await context?.obs?.getSceneAndGroupNames()) ?? [] }, }, source: { From e03153eebfc51bf1e0f438228dbd5392f2dbc457 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Sun, 18 Aug 2024 19:29:56 -0400 Subject: [PATCH 07/23] Add Chapter Marker action for OBS * Bumped Websocket Lib Version --- plugins/obs/main/package.json | 2 +- plugins/obs/main/src/media.ts | 26 ++++++++++++++++++++++++++ yarn.lock | 10 +++++----- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/plugins/obs/main/package.json b/plugins/obs/main/package.json index b5e6ce33..0af37d5d 100644 --- a/plugins/obs/main/package.json +++ b/plugins/obs/main/package.json @@ -18,7 +18,7 @@ "castmate-schema": "workspace:^", "jsqr": "^1.4.0", "node-screenshots": "^0.2.0", - "obs-websocket-js": "^5.0.5", + "obs-websocket-js": "^5.0.6", "regedit": "^5.1.3" } } diff --git a/plugins/obs/main/src/media.ts b/plugins/obs/main/src/media.ts index 71ca4410..d0b772a1 100644 --- a/plugins/obs/main/src/media.ts +++ b/plugins/obs/main/src/media.ts @@ -200,4 +200,30 @@ export function setupMedia(obsDefault: ReactiveRef) { }) }, }) + + defineAction({ + id: "chapterMarker", + name: "Chapter Marker", + description: "Creates a Chapter Marker in the OBS recording", + icon: "mdi mdi-map-marker", + config: { + type: Object, + properties: { + obs: { + type: OBSConnection, + name: "OBS Connection", + required: true, + default: () => obsDefault.value, + }, + chapterName: { + type: String, + name: "Chapter Name", + template: true, + }, + }, + }, + async invoke(config, contextData, abortSignal) { + await config.obs?.connection?.call("CreateRecordChapter", { chapterName: config.chapterName }) + }, + }) } diff --git a/yarn.lock b/yarn.lock index 98e4c189..8284a692 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3305,7 +3305,7 @@ __metadata: castmate-schema: "workspace:^" jsqr: "npm:^1.4.0" node-screenshots: "npm:^0.2.0" - obs-websocket-js: "npm:^5.0.5" + obs-websocket-js: "npm:^5.0.6" regedit: "npm:^5.1.3" typescript: "npm:*" languageName: unknown @@ -7828,9 +7828,9 @@ __metadata: languageName: node linkType: hard -"obs-websocket-js@npm:^5.0.5": - version: 5.0.5 - resolution: "obs-websocket-js@npm:5.0.5" +"obs-websocket-js@npm:^5.0.6": + version: 5.0.6 + resolution: "obs-websocket-js@npm:5.0.6" dependencies: "@msgpack/msgpack": "npm:^2.7.1" crypto-js: "npm:^4.1.1" @@ -7839,7 +7839,7 @@ __metadata: isomorphic-ws: "npm:^5.0.0" type-fest: "npm:^3.11.0" ws: "npm:^8.13.0" - checksum: 10/10075f057e05cddf0805b3edad9263f6c6da31c817a4cba27a2e6fd6fef20df188db0bcc929bbdd48bd6542b19f5c6e08e0acbdc062065ca7e571addd91a4601 + checksum: 10/a48a6df46c6673b374444443cb0eb3ec14b7a1928c3c33459181a9697f93b470c72349a8619518785dcde4c5f2f2287404e086c522519a61ff3e00727c0a5d3f languageName: node linkType: hard From fb7855f8588ef398ed31a190e7ff62e882a9acea Mon Sep 17 00:00:00 2001 From: LordTocs Date: Mon, 19 Aug 2024 02:37:48 -0400 Subject: [PATCH 08/23] Fix Cooldowns starting when a command isn't actually triggered --- plugins/twitch/main/src/chat.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/twitch/main/src/chat.ts b/plugins/twitch/main/src/chat.ts index 5643e416..a233b90b 100644 --- a/plugins/twitch/main/src/chat.ts +++ b/plugins/twitch/main/src/chat.ts @@ -125,6 +125,10 @@ export function setupChat() { if (matchResult == null) return undefined + if (!(await inTwitchViewerGroup(context.viewer, config.group))) { + return undefined + } + if (config.cooldown) { const now = Date.now() const slug = `${mapping.profileId}.${mapping.triggerId}` @@ -137,10 +141,6 @@ export function setupChat() { chatCommandCooldownMap.set(slug, now) } - if (!(await inTwitchViewerGroup(context.viewer, config.group))) { - return undefined - } - return { ...context, ...matchResult, From 60d589c9747e6d14dca78ab47926ca93f6406428 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Fri, 16 Aug 2024 14:17:44 -0400 Subject: [PATCH 09/23] Move Add Reward button to header because group headers don't work properly --- .../channel-points/ChannelPointsEditPage.vue | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/plugins/twitch/renderer/src/components/channel-points/ChannelPointsEditPage.vue b/plugins/twitch/renderer/src/components/channel-points/ChannelPointsEditPage.vue index e17b4ec8..6e2ce89f 100644 --- a/plugins/twitch/renderer/src/components/channel-points/ChannelPointsEditPage.vue +++ b/plugins/twitch/renderer/src/components/channel-points/ChannelPointsEditPage.vue @@ -13,25 +13,26 @@ sort-field="config.controllable" :sort-order="-1" > - + Create CastMate Reward - --> + + From 84d299bca5fc381519585863c51598833b87715b Mon Sep 17 00:00:00 2001 From: LordTocs Date: Mon, 19 Aug 2024 15:38:57 -0400 Subject: [PATCH 10/23] Don't show refresh all browsers unless OBS is connected --- plugins/obs/renderer/src/components/DashboardObsCard.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/obs/renderer/src/components/DashboardObsCard.vue b/plugins/obs/renderer/src/components/DashboardObsCard.vue index 15e52546..8eb7e617 100644 --- a/plugins/obs/renderer/src/components/DashboardObsCard.vue +++ b/plugins/obs/renderer/src/components/DashboardObsCard.vue @@ -5,6 +5,7 @@ {{ obs?.config?.name }}
Date: Mon, 19 Aug 2024 15:39:24 -0400 Subject: [PATCH 11/23] Don't mark OBS as connected until initial querys have succeeded This prevents UI from running browser queries before OBS has loaded --- plugins/obs/main/src/connection.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/obs/main/src/connection.ts b/plugins/obs/main/src/connection.ts index 7220e255..6182604d 100644 --- a/plugins/obs/main/src/connection.ts +++ b/plugins/obs/main/src/connection.ts @@ -10,7 +10,7 @@ import { AnalyticsService, InfoService, } from "castmate-core" -import OBSWebSocket from "obs-websocket-js" +import OBSWebSocket, { OBSWebSocketError } from "obs-websocket-js" import { OBSConnectionConfig, OBSConnectionState, @@ -207,21 +207,25 @@ export class OBSConnection extends FileResource { logger.log("OBS Identified Ver:", ev.negotiatedRpcVersion) - this.state.connected = true this.queryInitialStateLoop() }) } private async queryInitialStateLoop() { - for (let i = 0; i < 20; ++i) { + for (let i = 0; i < 40; ++i) { try { await this.queryInitialState() return } catch (err) { - //We probably got a not ready error? + if (err.code == 207) { + logger.log(err.message) + } else { + logger.error("Error Trying Initial State Check", err) + } } await sleep(1000) + logger.log("Retrying...") } } @@ -243,6 +247,9 @@ export class OBSConnection extends FileResource Date: Mon, 19 Aug 2024 15:44:22 -0400 Subject: [PATCH 12/23] Make Fix Errors button more prominent in Overlay Editor The old fix button of a tiny wrench was bad and confusing UI Now when there's a problem the fix button will be big and red * Moved OBS Source Info closer to the OBS drop down * Fixed some sizing issues with the source info label --- .../src/components/OverlayAddToObsButton.vue | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/plugins/overlays/renderer/src/components/OverlayAddToObsButton.vue b/plugins/overlays/renderer/src/components/OverlayAddToObsButton.vue index b3a0817e..e3f5cc54 100644 --- a/plugins/overlays/renderer/src/components/OverlayAddToObsButton.vue +++ b/plugins/overlays/renderer/src/components/OverlayAddToObsButton.vue @@ -1,6 +1,6 @@ @@ -88,7 +85,9 @@ onMounted(() => { () => ({ obs: props.obsId, id: props.overlayId, connected: hasObs.value }), async () => { try { - await findBrowserSource() + if (hasObs.value) { + await findBrowserSource() + } } catch {} }, { immediate: true, deep: true } @@ -185,16 +184,16 @@ async function openObs() { From 79c14e294e244a9348106b358e0ddab8a87a015d Mon Sep 17 00:00:00 2001 From: LordTocs Date: Mon, 19 Aug 2024 15:45:50 -0400 Subject: [PATCH 13/23] Make the project view use the configured resource creation dialog Makes a schema-less resource default to name configuration Makes Overlays have a schema to edit their width and height --- .../resources/ResourceEditDialog.vue | 15 +++++- .../src/project/project-store.ts | 51 ++++--------------- .../src/resources/resource-store.ts | 8 ++- plugins/overlays/main/src/overlay-resource.ts | 9 ++-- .../src/components/OverlayEditorPage.vue | 6 +-- plugins/overlays/renderer/src/main.ts | 23 ++++++++- .../shared/src/overlay-resource-types.ts | 5 ++ 7 files changed, 65 insertions(+), 52 deletions(-) diff --git a/libs/castmate-ui-core/src/components/resources/ResourceEditDialog.vue b/libs/castmate-ui-core/src/components/resources/ResourceEditDialog.vue index dd42759b..d1d58c36 100644 --- a/libs/castmate-ui-core/src/components/resources/ResourceEditDialog.vue +++ b/libs/castmate-ui-core/src/components/resources/ResourceEditDialog.vue @@ -1,6 +1,18 @@ diff --git a/plugins/overlays/renderer/src/components/style/OverlayTextStrokeEdit.vue b/plugins/overlays/renderer/src/components/style/OverlayTextStrokeEdit.vue index 955970a9..9d66017e 100644 --- a/plugins/overlays/renderer/src/components/style/OverlayTextStrokeEdit.vue +++ b/plugins/overlays/renderer/src/components/style/OverlayTextStrokeEdit.vue @@ -25,7 +25,7 @@
-
+
Add Stroke
From 85b70aab1189964ee5e33d778e633b08cb64f1a0 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Mon, 19 Aug 2024 16:38:09 -0400 Subject: [PATCH 16/23] Put a label on the alert media array --- plugins/overlays/overlay/src/widgets/Alert.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/overlays/overlay/src/widgets/Alert.vue b/plugins/overlays/overlay/src/widgets/Alert.vue index 6cd358c5..c4d54d29 100644 --- a/plugins/overlays/overlay/src/widgets/Alert.vue +++ b/plugins/overlays/overlay/src/widgets/Alert.vue @@ -42,12 +42,9 @@ defineOptions({ config: { type: Object, properties: { - transition: { - type: OverlayTransitionAnimation, - name: "Transition", - }, media: { type: Array, + name: "Alert Media", items: { type: Object, properties: { @@ -57,6 +54,10 @@ defineOptions({ }, }, }, + transition: { + type: OverlayTransitionAnimation, + name: "Transition", + }, textBelowMedia: { type: Boolean, name: "Text Below Media", From 40bd9b521ba274d07e7ba73a057a4b8ab4852b75 Mon Sep 17 00:00:00 2001 From: LordTocs Date: Mon, 19 Aug 2024 16:38:40 -0400 Subject: [PATCH 17/23] Move Save Shortcut handling to the App root element --- .../src/components/document/DocumentEditor.vue | 7 ------- packages/castmate/src/renderer/App.vue | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libs/castmate-ui-core/src/components/document/DocumentEditor.vue b/libs/castmate-ui-core/src/components/document/DocumentEditor.vue index 9b590979..5fa03edb 100644 --- a/libs/castmate-ui-core/src/components/document/DocumentEditor.vue +++ b/libs/castmate-ui-core/src/components/document/DocumentEditor.vue @@ -4,7 +4,6 @@ v-if="documentComponent && document" v-model="documentData" v-model:view="documentView" - @keydown="onKeyDown" tabindex="-1" /> @@ -57,12 +56,6 @@ const documentView = computed({ document.value.viewData = data }, }) - -function onKeyDown(ev: KeyboardEvent) { - if (ev.ctrlKey && ev.code == "KeyS") { - documentStore.saveDocument(props.documentId) - } -} diff --git a/packages/castmate/src/renderer/App.vue b/packages/castmate/src/renderer/App.vue index 792f84aa..2cb66be8 100644 --- a/packages/castmate/src/renderer/App.vue +++ b/packages/castmate/src/renderer/App.vue @@ -1,5 +1,5 @@