From 0b5339b2e0f0753c1037b3ea05d228bb303e6691 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Thu, 11 Sep 2025 13:25:50 +0200 Subject: [PATCH 1/9] feat: Add module variable for slide label --- src/main.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++- src/variables.ts | 4 ++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index f4962db..804e9fe 100644 --- a/src/main.ts +++ b/src/main.ts @@ -588,7 +588,8 @@ class ModuleInstance extends InstanceBase { SetVariableValues(this, { video_countdown_timer: videoCountdownTimerJSONObject.data }) } - presentationSlideIndexUpdate = (statusJSONObject: StatusUpdateJSON) => { + + presentationSlideIndexUpdate = async (statusJSONObject: StatusUpdateJSON) => { this.log('debug', 'presentationSlideIndexUpdate: ' + JSON.stringify(statusJSONObject)) if (statusJSONObject.data.presentation_index) { // ProPresenter can return a null presentation_index when no presentation is active @@ -599,12 +600,58 @@ class ModuleInstance extends InstanceBase { active_presentation_uuid: statusJSONObject.data.presentation_index.presentation_id.uuid, active_presentation_index: statusJSONObject.data.presentation_index.presentation_id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter }) + + // Try to get complete presentation data from library to see if it contains slide labels + try { + const presentationUUID = statusJSONObject.data.presentation_index.presentation_id.uuid + // Get presentation data by UUID to get slide labels + const presentationByUUID = await this.ProPresenter.presentationUUIDGet(presentationUUID) + if (presentationByUUID.ok && presentationByUUID.data) { + // Extract slide labels from the presentation data + const currentSlideIndex = statusJSONObject.data.presentation_index.index + let currentSlideLabel = '' + + // Look through all groups to find the slide at the current index + if (presentationByUUID.data.presentation && presentationByUUID.data.presentation.groups) { + let slideCount = 0 + for (const group of presentationByUUID.data.presentation.groups) { + if (group.slides) { + for (const slide of group.slides) { + if (slideCount === currentSlideIndex) { + currentSlideLabel = slide.label || '' + break + } + slideCount++ + } + if (currentSlideLabel) break + } + } + } + + // Always set the slide label variable (empty string if no label found) + SetVariableValues(this, { + active_presentation_current_slide_label: currentSlideLabel + }) + + if (!currentSlideLabel) { + this.log('debug', 'No slide label found for index: ' + currentSlideIndex + ', setting to empty string') + } + } + + } catch (error) { + this.log('debug', 'Error fetching presentation data for slide labels: ' + error) + // Set to empty string if there's an error + SetVariableValues(this, { + active_presentation_current_slide_label: '' + }) + } } else { SetVariableValues(this, { // For the times when no presentation is active: active_presentation_slide_index: '', active_presentation_name: '', active_presentation_uuid: '', + active_presentation_current_slide_label: '', // Also set label to empty when no presentation }) } } diff --git a/src/variables.ts b/src/variables.ts index 522dbdf..5e79ab7 100644 --- a/src/variables.ts +++ b/src/variables.ts @@ -31,6 +31,10 @@ export function GetVariableDefinitions(propresenterStateStore: ProPresenterState name: 'Active Presentation Current Slide Text', variableId: 'active_presentation_current_slide_text', }) + variables.push({ + name: 'Active Presentation Current Slide Label', + variableId: 'active_presentation_current_slide_label', + }) variables.push({ name: 'Active Presentation Next Slide Text', variableId: 'active_presentation_next_slide_text', From 466b11873333a9f6c14ff8e0afb70c69e7b03603 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Thu, 11 Sep 2025 13:40:35 +0200 Subject: [PATCH 2/9] formatting fix --- src/main.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main.ts b/src/main.ts index 804e9fe..a5bf671 100644 --- a/src/main.ts +++ b/src/main.ts @@ -487,7 +487,8 @@ class ModuleInstance extends InstanceBase { active_presentation_current_slide_notes: statusJSONObject.data.current.notes, active_presentation_next_slide_notes: statusJSONObject.data.next != null ? statusJSONObject.data.next.notes : '', active_presentation_current_slide_imageuuid: statusJSONObject.data.current.uuid, - active_presentation_next_slide_imageuuid: statusJSONObject.data.next != null ? statusJSONObject.data.next.uuid : '', + active_presentation_next_slide_imageuuid: + statusJSONObject.data.next != null ? statusJSONObject.data.next.uuid : '', }) } @@ -588,7 +589,6 @@ class ModuleInstance extends InstanceBase { SetVariableValues(this, { video_countdown_timer: videoCountdownTimerJSONObject.data }) } - presentationSlideIndexUpdate = async (statusJSONObject: StatusUpdateJSON) => { this.log('debug', 'presentationSlideIndexUpdate: ' + JSON.stringify(statusJSONObject)) if (statusJSONObject.data.presentation_index) { @@ -610,14 +610,14 @@ class ModuleInstance extends InstanceBase { // Extract slide labels from the presentation data const currentSlideIndex = statusJSONObject.data.presentation_index.index let currentSlideLabel = '' - + // Look through all groups to find the slide at the current index if (presentationByUUID.data.presentation && presentationByUUID.data.presentation.groups) { let slideCount = 0 for (const group of presentationByUUID.data.presentation.groups) { if (group.slides) { for (const slide of group.slides) { - if (slideCount === currentSlideIndex) { + if (slideCount === currentSlideIndex) { currentSlideLabel = slide.label || '' break } @@ -627,22 +627,21 @@ class ModuleInstance extends InstanceBase { } } } - + // Always set the slide label variable (empty string if no label found) SetVariableValues(this, { - active_presentation_current_slide_label: currentSlideLabel + active_presentation_current_slide_label: currentSlideLabel, }) - + if (!currentSlideLabel) { this.log('debug', 'No slide label found for index: ' + currentSlideIndex + ', setting to empty string') } } - } catch (error) { this.log('debug', 'Error fetching presentation data for slide labels: ' + error) // Set to empty string if there's an error SetVariableValues(this, { - active_presentation_current_slide_label: '' + active_presentation_current_slide_label: '', }) } } else { @@ -775,7 +774,13 @@ class ModuleInstance extends InstanceBase { ), }) } else { - this.log('debug', 'Error getting focused playlist items: ' + focusedPlaylistItemsResponse.status + ': ' + focusedPlaylistItemsResponse.data) + this.log( + 'debug', + 'Error getting focused playlist items: ' + + focusedPlaylistItemsResponse.status + + ': ' + + focusedPlaylistItemsResponse.data + ) } } else { SetVariableValues(this, { From 32029f12be75f7263a3de778c5507358fa6da289 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Mon, 15 Sep 2025 10:49:17 +0200 Subject: [PATCH 3/9] Add presentation data to ProPresenterStateStore cache --- src/main.ts | 91 ++++++++++++++++++++++++++++++++++++++++++++++------ src/utils.ts | 1 + 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/main.ts b/src/main.ts index f4962db..e19f642 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,6 +51,7 @@ const emptyPropresenterStateStore: ProPresenterStateStore = { index: -1, }, stageMessage: '', + activePresentationData: null, } class ModuleInstance extends InstanceBase { @@ -414,6 +415,17 @@ class ModuleInstance extends InstanceBase { this.initFeedbacks() this.checkFeedbacks() + // Fetch initial presentation data if a presentation is active + try { + const activePresentationResult = await this.ProPresenter.presentationActiveGet() + if (activePresentationResult.ok && activePresentationResult.data && activePresentationResult.data.presentation) { + const presentationUUID = activePresentationResult.data.presentation.id.uuid + await this.updatePresentationData(presentationUUID) + } + } catch (error) { + this.log('debug', 'Error fetching initial presentation data: ' + error) + } + // Watchdog function - checks each second to record total time since last status update in a variable. (Users can monitor this variable to know if the module is still connected to ProPresenter - it should be updated every second) setInterval(() => { SetVariableValues(this, { time_since_last_status_update: (Date.now() - this.timeOfLastStatusUpdate) / 1000 }) @@ -481,13 +493,17 @@ class ModuleInstance extends InstanceBase { this.log('debug', 'statusSlideUpdated: ' + JSON.stringify(statusJSONObject)) } + // Handle case where current or next slide data is null + const currentSlide = statusJSONObject.data.current + const nextSlide = statusJSONObject.data.next + SetVariableValues(this, { - active_presentation_current_slide_text: statusJSONObject.data.current.text, - active_presentation_next_slide_text: statusJSONObject.data.next != null ? statusJSONObject.data.next.text : '', - active_presentation_current_slide_notes: statusJSONObject.data.current.notes, - active_presentation_next_slide_notes: statusJSONObject.data.next != null ? statusJSONObject.data.next.notes : '', - active_presentation_current_slide_imageuuid: statusJSONObject.data.current.uuid, - active_presentation_next_slide_imageuuid: statusJSONObject.data.next != null ? statusJSONObject.data.next.uuid : '', + active_presentation_current_slide_text: currentSlide ? currentSlide.text : '', + active_presentation_next_slide_text: nextSlide ? nextSlide.text : '', + active_presentation_current_slide_notes: currentSlide ? currentSlide.notes : '', + active_presentation_next_slide_notes: nextSlide ? nextSlide.notes : '', + active_presentation_current_slide_imageuuid: currentSlide ? currentSlide.uuid : '', + active_presentation_next_slide_imageuuid: nextSlide ? nextSlide.uuid : '', }) } @@ -588,16 +604,63 @@ class ModuleInstance extends InstanceBase { SetVariableValues(this, { video_countdown_timer: videoCountdownTimerJSONObject.data }) } + // Helper function to get current slide label from cached presentation data + private getCurrentSlideLabel(slideIndex: number): string { + if (!this.propresenterStateStore.activePresentationData) { + return '' + } + + const presentationData = this.propresenterStateStore.activePresentationData + if (!presentationData.presentation || !presentationData.presentation.groups) { + return '' + } + + // Count through all slides to find the one at the current index + let slideCount = 0 + for (const group of presentationData.presentation.groups) { + if (group.slides) { + for (const slide of group.slides) { + if (slideCount === slideIndex) { + return slide.label || '' + } + slideCount++ + } + } + } + + return '' + } + + // Function to update presentation data when presentation changes + private async updatePresentationData(presentationUUID: string) { + try { + // Get presentation data from library + const presentationData = await this.ProPresenter.presentationUUIDGet(presentationUUID) + if (presentationData.ok && presentationData.data) { + this.propresenterStateStore.activePresentationData = presentationData.data + this.log('debug', 'Updated presentation data for UUID: ' + presentationUUID) + } + } catch (error) { + this.log('debug', 'Error updating presentation data: ' + error) + } + } + presentationSlideIndexUpdate = (statusJSONObject: StatusUpdateJSON) => { this.log('debug', 'presentationSlideIndexUpdate: ' + JSON.stringify(statusJSONObject)) if (statusJSONObject.data.presentation_index) { // ProPresenter can return a null presentation_index when no presentation is active + const slideIndex = statusJSONObject.data.presentation_index.index + + // Get slide label from cached data + const slideLabel = this.getCurrentSlideLabel(slideIndex) + SetVariableValues(this, { - active_presentation_slide_index: statusJSONObject.data.presentation_index.index, + active_presentation_slide_index: slideIndex, // This status update includes the name and uuid of the presentation - so we can update these variables too active_presentation_name: statusJSONObject.data.presentation_index.presentation_id.name, active_presentation_uuid: statusJSONObject.data.presentation_index.presentation_id.uuid, active_presentation_index: statusJSONObject.data.presentation_index.presentation_id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter + active_presentation_current_slide_label: slideLabel, }) } else { SetVariableValues(this, { @@ -605,6 +668,7 @@ class ModuleInstance extends InstanceBase { active_presentation_slide_index: '', active_presentation_name: '', active_presentation_uuid: '', + active_presentation_current_slide_label: '', }) } } @@ -618,20 +682,29 @@ class ModuleInstance extends InstanceBase { }) } - activePresentationUpdated = (statusJSONObject: StatusUpdateJSON) => { + activePresentationUpdated = async (statusJSONObject: StatusUpdateJSON) => { this.log('debug', 'activePresentationUpdated: ' + JSON.stringify(statusJSONObject)) if (statusJSONObject.data.presentation) { // ProPresenter can return a null presentation when no presentation is active + const presentationUUID = statusJSONObject.data.presentation.id.uuid + + // Update presentation data when presentation changes + await this.updatePresentationData(presentationUUID) + SetVariableValues(this, { active_presentation_index: statusJSONObject.data.presentation.id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_name: statusJSONObject.data.presentation.id.name, - active_presentation_uuid: statusJSONObject.data.presentation.id.uuid, + active_presentation_uuid: presentationUUID, }) } else { + // Clear presentation data when no presentation is active + this.propresenterStateStore.activePresentationData = null + SetVariableValues(this, { active_presentation_index: '', // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_name: '', active_presentation_uuid: '', + active_presentation_current_slide_label: '', }) } } diff --git a/src/utils.ts b/src/utils.ts index af3c27e..cb44788 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -943,6 +943,7 @@ export type ProPresenterStateStore = { clearGroupChoices: DropdownChoice[] activeLookID: ProID stageMessage: string + activePresentationData: any // Cached presentation data with slides and arrangements } // Custom function to convert HH:mm:ss or mm:ss to seconds (number). Handles negative timestamps From f2f3754e0b2345a0da806b52a4b3c60f0b28cdab Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Mon, 15 Sep 2025 13:36:47 +0200 Subject: [PATCH 4/9] update variable for selected slide lebel --- src/main.ts | 102 +++++++++++++++++++++++++++++++++++++++++++---- src/variables.ts | 4 ++ 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/main.ts b/src/main.ts index e19f642..075f997 100644 --- a/src/main.ts +++ b/src/main.ts @@ -604,8 +604,95 @@ class ModuleInstance extends InstanceBase { SetVariableValues(this, { video_countdown_timer: videoCountdownTimerJSONObject.data }) } - // Helper function to get current slide label from cached presentation data - private getCurrentSlideLabel(slideIndex: number): string { + // Helper function to get current slide label from cached presentation data with arrangement support + private async getCurrentSlideLabelWithArrangement(slideIndex: number): Promise { + if (!this.propresenterStateStore.activePresentationData) { + return '' + } + + try { + // First check if presentation is from a playlist + const activePlaylistResult = await this.ProPresenter.playlistActiveGet() + let currentArrangement = '' + + if (activePlaylistResult.ok && activePlaylistResult.data && activePlaylistResult.data.presentation && activePlaylistResult.data.presentation.playlist) { + // Presentation is from a playlist + const playlistUUID = activePlaylistResult.data.presentation.playlist.uuid + const playlistItemIndex = activePlaylistResult.data.presentation.playlist.index + + // Get playlist data to find arrangement for this item + const playlistData = await this.ProPresenter.playlistPlaylistIdGet(playlistUUID) + if (playlistData.ok && playlistData.data && playlistData.data.items) { + const playlistItem = playlistData.data.items[playlistItemIndex] + if (playlistItem && playlistItem.arrangement) { + currentArrangement = playlistItem.arrangement + } + } + } else { + // Presentation is from library, get arrangement from active presentation + const activePresentationResult = await this.ProPresenter.presentationActiveGet() + if (activePresentationResult.ok && activePresentationResult.data && activePresentationResult.data.presentation) { + currentArrangement = activePresentationResult.data.presentation.current_arrangement || '' + } + } + + // Now get the slide label based on arrangement + const presentationData = this.propresenterStateStore.activePresentationData + if (!presentationData.presentation || !presentationData.presentation.groups) { + return '' + } + + // If we have a valid arrangement and arrangements exist, use arrangement-specific slide order + if (currentArrangement && presentationData.presentation.arrangements && presentationData.presentation.arrangements.length > 0) { + // Try to find arrangement by name first, then by UUID + let arrangement = presentationData.presentation.arrangements.find((arr: any) => arr.id?.name === currentArrangement) + if (!arrangement) { + // If not found by name, try by UUID + arrangement = presentationData.presentation.arrangements.find((arr: any) => arr.id?.uuid === currentArrangement) + } + + if (arrangement) { + // Use arrangement-specific slide order based on arrangement groups + let slideCount = 0 + for (const arrangementGroupUUID of arrangement.groups) { + // Find the group in the presentation data + const group = presentationData.presentation.groups.find((g: any) => g.id?.uuid === arrangementGroupUUID) + if (group && group.slides) { + for (const slide of group.slides) { + if (slideCount === slideIndex) { + return slide.label || '' + } + slideCount++ + } + } + } + + return '' + } + } + + // Fallback to default slide order (no arrangement or arrangement not found) + let slideCount = 0 + for (const group of presentationData.presentation.groups) { + if (group.slides) { + for (const slide of group.slides) { + if (slideCount === slideIndex) { + return slide.label || '' + } + slideCount++ + } + } + } + + return '' + } catch (error) { + // Fallback to simple method on any error + return this.getCurrentSlideLabelSimple(slideIndex) + } + } + + // Simple fallback function for getting slide label without arrangement logic + private getCurrentSlideLabelSimple(slideIndex: number): string { if (!this.propresenterStateStore.activePresentationData) { return '' } @@ -631,6 +718,7 @@ class ModuleInstance extends InstanceBase { return '' } + // Function to update presentation data when presentation changes private async updatePresentationData(presentationUUID: string) { try { @@ -638,27 +726,27 @@ class ModuleInstance extends InstanceBase { const presentationData = await this.ProPresenter.presentationUUIDGet(presentationUUID) if (presentationData.ok && presentationData.data) { this.propresenterStateStore.activePresentationData = presentationData.data - this.log('debug', 'Updated presentation data for UUID: ' + presentationUUID) } } catch (error) { this.log('debug', 'Error updating presentation data: ' + error) } } - presentationSlideIndexUpdate = (statusJSONObject: StatusUpdateJSON) => { + presentationSlideIndexUpdate = async (statusJSONObject: StatusUpdateJSON) => { this.log('debug', 'presentationSlideIndexUpdate: ' + JSON.stringify(statusJSONObject)) if (statusJSONObject.data.presentation_index) { // ProPresenter can return a null presentation_index when no presentation is active const slideIndex = statusJSONObject.data.presentation_index.index + const presentationUUID = statusJSONObject.data.presentation_index.presentation_id.uuid - // Get slide label from cached data - const slideLabel = this.getCurrentSlideLabel(slideIndex) + // Get slide label with arrangement support + const slideLabel = await this.getCurrentSlideLabelWithArrangement(slideIndex) SetVariableValues(this, { active_presentation_slide_index: slideIndex, // This status update includes the name and uuid of the presentation - so we can update these variables too active_presentation_name: statusJSONObject.data.presentation_index.presentation_id.name, - active_presentation_uuid: statusJSONObject.data.presentation_index.presentation_id.uuid, + active_presentation_uuid: presentationUUID, active_presentation_index: statusJSONObject.data.presentation_index.presentation_id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_current_slide_label: slideLabel, }) diff --git a/src/variables.ts b/src/variables.ts index 522dbdf..5e79ab7 100644 --- a/src/variables.ts +++ b/src/variables.ts @@ -31,6 +31,10 @@ export function GetVariableDefinitions(propresenterStateStore: ProPresenterState name: 'Active Presentation Current Slide Text', variableId: 'active_presentation_current_slide_text', }) + variables.push({ + name: 'Active Presentation Current Slide Label', + variableId: 'active_presentation_current_slide_label', + }) variables.push({ name: 'Active Presentation Next Slide Text', variableId: 'active_presentation_next_slide_text', From 90e3c0ee2b07499d502fd84ca7703f92d8d8943b Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Mon, 15 Sep 2025 13:49:04 +0200 Subject: [PATCH 5/9] revert old changes --- src/main.ts | 52 +--------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4924ba8..075f997 100644 --- a/src/main.ts +++ b/src/main.ts @@ -750,50 +750,6 @@ class ModuleInstance extends InstanceBase { active_presentation_index: statusJSONObject.data.presentation_index.presentation_id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_current_slide_label: slideLabel, }) - - // Try to get complete presentation data from library to see if it contains slide labels - try { - const presentationUUID = statusJSONObject.data.presentation_index.presentation_id.uuid - // Get presentation data by UUID to get slide labels - const presentationByUUID = await this.ProPresenter.presentationUUIDGet(presentationUUID) - if (presentationByUUID.ok && presentationByUUID.data) { - // Extract slide labels from the presentation data - const currentSlideIndex = statusJSONObject.data.presentation_index.index - let currentSlideLabel = '' - - // Look through all groups to find the slide at the current index - if (presentationByUUID.data.presentation && presentationByUUID.data.presentation.groups) { - let slideCount = 0 - for (const group of presentationByUUID.data.presentation.groups) { - if (group.slides) { - for (const slide of group.slides) { - if (slideCount === currentSlideIndex) { - currentSlideLabel = slide.label || '' - break - } - slideCount++ - } - if (currentSlideLabel) break - } - } - } - - // Always set the slide label variable (empty string if no label found) - SetVariableValues(this, { - active_presentation_current_slide_label: currentSlideLabel, - }) - - if (!currentSlideLabel) { - this.log('debug', 'No slide label found for index: ' + currentSlideIndex + ', setting to empty string') - } - } - } catch (error) { - this.log('debug', 'Error fetching presentation data for slide labels: ' + error) - // Set to empty string if there's an error - SetVariableValues(this, { - active_presentation_current_slide_label: '', - }) - } } else { SetVariableValues(this, { // For the times when no presentation is active: @@ -933,13 +889,7 @@ class ModuleInstance extends InstanceBase { ), }) } else { - this.log( - 'debug', - 'Error getting focused playlist items: ' + - focusedPlaylistItemsResponse.status + - ': ' + - focusedPlaylistItemsResponse.data - ) + this.log('debug', 'Error getting focused playlist items: ' + focusedPlaylistItemsResponse.status + ': ' + focusedPlaylistItemsResponse.data) } } else { SetVariableValues(this, { From e197d9babc57dbf0e8e1ce57e187fa5c361dddcd Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Mon, 15 Sep 2025 14:18:16 +0200 Subject: [PATCH 6/9] added remaing committed --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 075f997..96015b7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -656,7 +656,7 @@ class ModuleInstance extends InstanceBase { let slideCount = 0 for (const arrangementGroupUUID of arrangement.groups) { // Find the group in the presentation data - const group = presentationData.presentation.groups.find((g: any) => g.id?.uuid === arrangementGroupUUID) + const group = presentationData.presentation.groups.find((g: any) => (g.id?.uuid === arrangementGroupUUID) || (g.uuid === arrangementGroupUUID)) if (group && group.slides) { for (const slide of group.slides) { if (slideCount === slideIndex) { From 8891457377c66fccc594a2cc892d7317fb27d979 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Mon, 15 Sep 2025 14:30:33 +0200 Subject: [PATCH 7/9] formatting --- src/main.ts | 62 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/main.ts b/src/main.ts index 96015b7..8fa49be 100644 --- a/src/main.ts +++ b/src/main.ts @@ -418,7 +418,11 @@ class ModuleInstance extends InstanceBase { // Fetch initial presentation data if a presentation is active try { const activePresentationResult = await this.ProPresenter.presentationActiveGet() - if (activePresentationResult.ok && activePresentationResult.data && activePresentationResult.data.presentation) { + if ( + activePresentationResult.ok && + activePresentationResult.data && + activePresentationResult.data.presentation + ) { const presentationUUID = activePresentationResult.data.presentation.id.uuid await this.updatePresentationData(presentationUUID) } @@ -615,11 +619,16 @@ class ModuleInstance extends InstanceBase { const activePlaylistResult = await this.ProPresenter.playlistActiveGet() let currentArrangement = '' - if (activePlaylistResult.ok && activePlaylistResult.data && activePlaylistResult.data.presentation && activePlaylistResult.data.presentation.playlist) { + if ( + activePlaylistResult.ok && + activePlaylistResult.data && + activePlaylistResult.data.presentation && + activePlaylistResult.data.presentation.playlist + ) { // Presentation is from a playlist const playlistUUID = activePlaylistResult.data.presentation.playlist.uuid const playlistItemIndex = activePlaylistResult.data.presentation.playlist.index - + // Get playlist data to find arrangement for this item const playlistData = await this.ProPresenter.playlistPlaylistIdGet(playlistUUID) if (playlistData.ok && playlistData.data && playlistData.data.items) { @@ -631,7 +640,11 @@ class ModuleInstance extends InstanceBase { } else { // Presentation is from library, get arrangement from active presentation const activePresentationResult = await this.ProPresenter.presentationActiveGet() - if (activePresentationResult.ok && activePresentationResult.data && activePresentationResult.data.presentation) { + if ( + activePresentationResult.ok && + activePresentationResult.data && + activePresentationResult.data.presentation + ) { currentArrangement = activePresentationResult.data.presentation.current_arrangement || '' } } @@ -643,20 +656,30 @@ class ModuleInstance extends InstanceBase { } // If we have a valid arrangement and arrangements exist, use arrangement-specific slide order - if (currentArrangement && presentationData.presentation.arrangements && presentationData.presentation.arrangements.length > 0) { + if ( + currentArrangement && + presentationData.presentation.arrangements && + presentationData.presentation.arrangements.length > 0 + ) { // Try to find arrangement by name first, then by UUID - let arrangement = presentationData.presentation.arrangements.find((arr: any) => arr.id?.name === currentArrangement) + let arrangement = presentationData.presentation.arrangements.find( + (arr: any) => arr.id?.name === currentArrangement + ) if (!arrangement) { // If not found by name, try by UUID - arrangement = presentationData.presentation.arrangements.find((arr: any) => arr.id?.uuid === currentArrangement) + arrangement = presentationData.presentation.arrangements.find( + (arr: any) => arr.id?.uuid === currentArrangement + ) } - + if (arrangement) { // Use arrangement-specific slide order based on arrangement groups let slideCount = 0 for (const arrangementGroupUUID of arrangement.groups) { // Find the group in the presentation data - const group = presentationData.presentation.groups.find((g: any) => (g.id?.uuid === arrangementGroupUUID) || (g.uuid === arrangementGroupUUID)) + const group = presentationData.presentation.groups.find( + (g: any) => g.id?.uuid === arrangementGroupUUID || g.uuid === arrangementGroupUUID + ) if (group && group.slides) { for (const slide of group.slides) { if (slideCount === slideIndex) { @@ -666,7 +689,7 @@ class ModuleInstance extends InstanceBase { } } } - + return '' } } @@ -718,7 +741,6 @@ class ModuleInstance extends InstanceBase { return '' } - // Function to update presentation data when presentation changes private async updatePresentationData(presentationUUID: string) { try { @@ -738,10 +760,10 @@ class ModuleInstance extends InstanceBase { // ProPresenter can return a null presentation_index when no presentation is active const slideIndex = statusJSONObject.data.presentation_index.index const presentationUUID = statusJSONObject.data.presentation_index.presentation_id.uuid - + // Get slide label with arrangement support const slideLabel = await this.getCurrentSlideLabelWithArrangement(slideIndex) - + SetVariableValues(this, { active_presentation_slide_index: slideIndex, // This status update includes the name and uuid of the presentation - so we can update these variables too @@ -775,10 +797,10 @@ class ModuleInstance extends InstanceBase { if (statusJSONObject.data.presentation) { // ProPresenter can return a null presentation when no presentation is active const presentationUUID = statusJSONObject.data.presentation.id.uuid - + // Update presentation data when presentation changes await this.updatePresentationData(presentationUUID) - + SetVariableValues(this, { active_presentation_index: statusJSONObject.data.presentation.id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_name: statusJSONObject.data.presentation.id.name, @@ -787,7 +809,7 @@ class ModuleInstance extends InstanceBase { } else { // Clear presentation data when no presentation is active this.propresenterStateStore.activePresentationData = null - + SetVariableValues(this, { active_presentation_index: '', // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter active_presentation_name: '', @@ -889,7 +911,13 @@ class ModuleInstance extends InstanceBase { ), }) } else { - this.log('debug', 'Error getting focused playlist items: ' + focusedPlaylistItemsResponse.status + ': ' + focusedPlaylistItemsResponse.data) + this.log( + 'debug', + 'Error getting focused playlist items: ' + + focusedPlaylistItemsResponse.status + + ': ' + + focusedPlaylistItemsResponse.data + ) } } else { SetVariableValues(this, { From f268e8edc677bc7a9ead85021f6a6452fae035a2 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Wed, 17 Sep 2025 14:42:27 +0200 Subject: [PATCH 8/9] feat: Add variable for current slide group name --- src/main.ts | 99 +++++++++++++++++++++--------------------------- src/variables.ts | 4 ++ 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8fa49be..ff52a99 100644 --- a/src/main.ts +++ b/src/main.ts @@ -609,52 +609,17 @@ class ModuleInstance extends InstanceBase { } // Helper function to get current slide label from cached presentation data with arrangement support - private async getCurrentSlideLabelWithArrangement(slideIndex: number): Promise { - if (!this.propresenterStateStore.activePresentationData) { - return '' - } - + private async getCurrentSlideInfoWithArrangement(slideIndex: number): Promise<{label: string, groupName: string}> { try { - // First check if presentation is from a playlist - const activePlaylistResult = await this.ProPresenter.playlistActiveGet() - let currentArrangement = '' - - if ( - activePlaylistResult.ok && - activePlaylistResult.data && - activePlaylistResult.data.presentation && - activePlaylistResult.data.presentation.playlist - ) { - // Presentation is from a playlist - const playlistUUID = activePlaylistResult.data.presentation.playlist.uuid - const playlistItemIndex = activePlaylistResult.data.presentation.playlist.index - - // Get playlist data to find arrangement for this item - const playlistData = await this.ProPresenter.playlistPlaylistIdGet(playlistUUID) - if (playlistData.ok && playlistData.data && playlistData.data.items) { - const playlistItem = playlistData.data.items[playlistItemIndex] - if (playlistItem && playlistItem.arrangement) { - currentArrangement = playlistItem.arrangement - } - } - } else { - // Presentation is from library, get arrangement from active presentation - const activePresentationResult = await this.ProPresenter.presentationActiveGet() - if ( - activePresentationResult.ok && - activePresentationResult.data && - activePresentationResult.data.presentation - ) { - currentArrangement = activePresentationResult.data.presentation.current_arrangement || '' - } - } - - // Now get the slide label based on arrangement + // Get the current arrangement from the active presentation data const presentationData = this.propresenterStateStore.activePresentationData - if (!presentationData.presentation || !presentationData.presentation.groups) { - return '' + if (!presentationData || !presentationData.presentation || !presentationData.presentation.groups) { + return { label: '', groupName: '' } } + // Get current arrangement from the presentation data + const currentArrangement = presentationData.currentArrangement + // If we have a valid arrangement and arrangements exist, use arrangement-specific slide order if ( currentArrangement && @@ -683,14 +648,17 @@ class ModuleInstance extends InstanceBase { if (group && group.slides) { for (const slide of group.slides) { if (slideCount === slideIndex) { - return slide.label || '' + return { + label: slide.label || '', + groupName: group.id?.name || group.name || '' + } } slideCount++ } } } - return '' + return { label: '', groupName: '' } } } @@ -700,29 +668,32 @@ class ModuleInstance extends InstanceBase { if (group.slides) { for (const slide of group.slides) { if (slideCount === slideIndex) { - return slide.label || '' + return { + label: slide.label || '', + groupName: group.id?.name || group.name || '' + } } slideCount++ } } } - return '' + return { label: '', groupName: '' } } catch (error) { // Fallback to simple method on any error - return this.getCurrentSlideLabelSimple(slideIndex) + return this.getCurrentSlideInfoSimple(slideIndex) } } - // Simple fallback function for getting slide label without arrangement logic - private getCurrentSlideLabelSimple(slideIndex: number): string { + // Simple fallback function for getting slide info without arrangement logic + private getCurrentSlideInfoSimple(slideIndex: number): {label: string, groupName: string} { if (!this.propresenterStateStore.activePresentationData) { - return '' + return { label: '', groupName: '' } } const presentationData = this.propresenterStateStore.activePresentationData if (!presentationData.presentation || !presentationData.presentation.groups) { - return '' + return { label: '', groupName: '' } } // Count through all slides to find the one at the current index @@ -731,14 +702,17 @@ class ModuleInstance extends InstanceBase { if (group.slides) { for (const slide of group.slides) { if (slideCount === slideIndex) { - return slide.label || '' + return { + label: slide.label || '', + groupName: group.id?.name || group.name || '' + } } slideCount++ } } } - return '' + return { label: '', groupName: '' } } // Function to update presentation data when presentation changes @@ -761,8 +735,8 @@ class ModuleInstance extends InstanceBase { const slideIndex = statusJSONObject.data.presentation_index.index const presentationUUID = statusJSONObject.data.presentation_index.presentation_id.uuid - // Get slide label with arrangement support - const slideLabel = await this.getCurrentSlideLabelWithArrangement(slideIndex) + // Get both slide label and group name with arrangement support + const slideInfo = await this.getCurrentSlideInfoWithArrangement(slideIndex) SetVariableValues(this, { active_presentation_slide_index: slideIndex, @@ -770,7 +744,8 @@ class ModuleInstance extends InstanceBase { active_presentation_name: statusJSONObject.data.presentation_index.presentation_id.name, active_presentation_uuid: presentationUUID, active_presentation_index: statusJSONObject.data.presentation_index.presentation_id.index, // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter - active_presentation_current_slide_label: slideLabel, + active_presentation_current_slide_label: slideInfo.label, + active_presentation_current_slide_group_name: slideInfo.groupName, }) } else { SetVariableValues(this, { @@ -779,6 +754,7 @@ class ModuleInstance extends InstanceBase { active_presentation_name: '', active_presentation_uuid: '', active_presentation_current_slide_label: '', + active_presentation_current_slide_group_name: '', }) } } @@ -790,6 +766,17 @@ class ModuleInstance extends InstanceBase { focused_presentation_name: statusJSONObject.data.name, focused_presentation_uuid: statusJSONObject.data.uuid, }) + + // Clear presentation-related variables when no presentation is active + if (!statusJSONObject.data.uuid) { + SetVariableValues(this, { + active_presentation_index: '', // Note that this seems to return invalid indexes. Keeping it here for the future, in case it becomes useful in a future version of ProPresenter + active_presentation_name: '', + active_presentation_uuid: '', + active_presentation_current_slide_label: '', + active_presentation_current_slide_group_name: '', + }) + } } activePresentationUpdated = async (statusJSONObject: StatusUpdateJSON) => { diff --git a/src/variables.ts b/src/variables.ts index 5e79ab7..96169ae 100644 --- a/src/variables.ts +++ b/src/variables.ts @@ -35,6 +35,10 @@ export function GetVariableDefinitions(propresenterStateStore: ProPresenterState name: 'Active Presentation Current Slide Label', variableId: 'active_presentation_current_slide_label', }) + variables.push({ + name: 'Active Presentation Current Slide Group Name', + variableId: 'active_presentation_current_slide_group_name', + }) variables.push({ name: 'Active Presentation Next Slide Text', variableId: 'active_presentation_next_slide_text', From f98922a38769e90ef51be2a5f9e2e8e105c03558 Mon Sep 17 00:00:00 2001 From: Rashmi Sinha Date: Wed, 17 Sep 2025 14:47:32 +0200 Subject: [PATCH 9/9] format fix --- src/main.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.ts b/src/main.ts index ff52a99..65bcb97 100644 --- a/src/main.ts +++ b/src/main.ts @@ -609,7 +609,7 @@ class ModuleInstance extends InstanceBase { } // Helper function to get current slide label from cached presentation data with arrangement support - private async getCurrentSlideInfoWithArrangement(slideIndex: number): Promise<{label: string, groupName: string}> { + private async getCurrentSlideInfoWithArrangement(slideIndex: number): Promise<{ label: string; groupName: string }> { try { // Get the current arrangement from the active presentation data const presentationData = this.propresenterStateStore.activePresentationData @@ -650,7 +650,7 @@ class ModuleInstance extends InstanceBase { if (slideCount === slideIndex) { return { label: slide.label || '', - groupName: group.id?.name || group.name || '' + groupName: group.id?.name || group.name || '', } } slideCount++ @@ -670,7 +670,7 @@ class ModuleInstance extends InstanceBase { if (slideCount === slideIndex) { return { label: slide.label || '', - groupName: group.id?.name || group.name || '' + groupName: group.id?.name || group.name || '', } } slideCount++ @@ -686,7 +686,7 @@ class ModuleInstance extends InstanceBase { } // Simple fallback function for getting slide info without arrangement logic - private getCurrentSlideInfoSimple(slideIndex: number): {label: string, groupName: string} { + private getCurrentSlideInfoSimple(slideIndex: number): { label: string; groupName: string } { if (!this.propresenterStateStore.activePresentationData) { return { label: '', groupName: '' } } @@ -704,7 +704,7 @@ class ModuleInstance extends InstanceBase { if (slideCount === slideIndex) { return { label: slide.label || '', - groupName: group.id?.name || group.name || '' + groupName: group.id?.name || group.name || '', } } slideCount++