Multistream Toggle 1 - #6164
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
A new required checklist field is added without updating the typed streaming service initial state, and there are additional correctness/accessibility/i18n issues that should be resolved before merging.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds groundwork for “Live Output Editing” / multistream update UX, including new UI cards, expanded Restream error taxonomy, and i18n reorganization to support new mid-stream output editing flows.
Changes:
- Extends streaming checklist/error handling to support more granular Restream/live-output-editing failures.
- Introduces new Go Live UI components/props for Live Output Editing vs Stream Shift compatibility and Enhanced Broadcasting restrictions.
- Moves/expands English strings into a new
live-output-editing.jsonand updates fallback registration.
File summaries
| File | Description |
|---|---|
| app/services/streaming/streaming-api.ts | Adds a new required checklist entry (destination) to stream info. |
| app/services/streaming/stream-error.ts | Adds multiple new Restream error types and a helper to rethrow Restream errors consistently. |
| app/services/settings/streaming/stream-settings.ts | Introduces a typed custom destination ID helper. |
| app/services/platforms/twitch.ts | Disables Enhanced Broadcasting when Live Output Editing is enabled. |
| app/services/dismissables.ts | Adds a new dismissable key and simplifies dismissAll(). |
| app/i18n/fallback.ts | Registers the new live-output-editing.json fallback bundle. |
| app/i18n/en-US/twitch.json | Adds tooltip string for Enhanced Broadcasting + Live Output Editing. |
| app/i18n/en-US/streaming.json | Removes the old Enhanced Broadcasting failure string (replaced by new wording). |
| app/i18n/en-US/live-outputs.json | Removes legacy locale file for live outputs. |
| app/i18n/en-US/live-output-editing.json | Adds new strings for Live Output Editing UX and new Restream errors. |
| app/i18n/en-US/highlighter.json | Adds “Do not ask again” string. |
| app/components-react/windows/go-live/StreamShiftCard.tsx | New Stream Shift card with tooltip logic and Learn More link. |
| app/components-react/windows/go-live/platforms/TwitchEditStreamInfo.tsx | Disables/adjusts Enhanced Broadcasting UX when Live Output Editing is active. |
| app/components-react/windows/go-live/platforms/PlatformSettingsLayout.tsx | Adds isLiveOutputEditingEnabled to platform component params. |
| app/components-react/windows/go-live/LiveOutputEditingCard.tsx | New Live Output Editing card and analytics tracking. |
| app/components-react/windows/go-live/GoLiveWindow.tsx | Clarifies the Stream Shift prompt effect dependency comment. |
| app/components-react/windows/go-live/GoLiveSettings.tsx | Gates Stream Shift toggle behind a rollout flag and adjusts layout conditions. |
| app/components-react/windows/go-live/GoLiveError.tsx | Routes additional Restream error types to Restream error renderer and adjusts message layout. |
| app/components-react/windows/go-live/GoLive.m.less | Refactors banner styles and adds button/tooltip styling. |
| app/components-react/windows/go-live/CommonPlatformFields.tsx | Disables shared title input in a mid-stream edge case to avoid invalid required validation. |
| app/components-react/windows/go-live/AiHighlighterToggle.tsx | Adds dismissable banner behavior in update mode. |
| app/components-react/windows/go-live/AiHighlighterToggle.m.less | Adds styling for the new dismissable UI. |
| app/components-react/shared/inputs/RadioInput.m.less | Adds styling for disabled icon state. |
| app/components-react/shared/DisplaySelector.tsx | Restricts display changes for live targets and update-mode behavior. |
| app/components-react/root/LiveDock.tsx | Adds a data-name attribute to the edit-stream icon. |
Review details
- Files reviewed: 25/25 changed files
- Comments generated: 6
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
It introduces a confirmed Restream error-detail formatting bug and a GoLiveWindow effect that can capture stale prompt behavior (plus an accessibility issue) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
app/components-react/windows/go-live/StreamShiftCard.tsx:112
- The “Learn More” UI is implemented as a clickable
<span>containing an<a>without anhref, which is not reliably keyboard-accessible and doesn’t provide correct link semantics to assistive tech.
<span data-name="explanation" onClick={handleTooltipClick}>
{$t(
'Stay uninterrupted by switching between devices mid stream. Works between Desktop and Mobile App.',
)}
<a style={{ marginLeft: 4 }}>{$t('Learn More')}</a>
- Files reviewed: 25/25 changed files
- Comments generated: 2
- Review effort level: Lite
| useEffect(() => { | ||
| if (streamShiftStatus !== 'pending') return; | ||
| if (isStreamShiftPromptShown.current) return; | ||
| promptStreamShift(); | ||
| }, [streamShiftStatus, promptStreamShift]); | ||
| // Prompt the user to switch to Streamlabs Desktop if a stream is detected on another device | ||
| if (Services.RestreamService.views.streamShiftStatus === 'pending') { | ||
| promptStreamShift(); | ||
| } |
| function formatRestreamErrorMessage(e: unknown, message?: string) { | ||
| if (e instanceof StreamError) { | ||
| return e.details ?? e.statusText; | ||
| } | ||
|
|
||
| return message ?? $t('Failed to update Multistream platforms and destinations while live'); | ||
| } |
There was a problem hiding this comment.
🟡 Changes recommended
It introduces a call to a non-existent RestreamService.actions.return.handleStreamShiftEvent, which will crash on Stream Shift websocket events, alongside additional correctness/a11y issues that should be addressed before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
app/components-react/windows/go-live/StreamShiftCard.tsx:113
- The “Learn More” UI is implemented as a clickable
<span>with a nested<a>that has nohref. This is not keyboard-accessible by default and doesn’t expose a proper link/button semantic to assistive tech.
return showTooltip ? (
<span data-name={tooltipText.name}>{tooltipText.text}</span>
) : (
<span data-name="explanation" onClick={handleTooltipClick}>
{$t(
'Stay uninterrupted by switching between devices mid stream. Works between Desktop and Mobile App.',
)}
<a style={{ marginLeft: 4 }}>{$t('Learn More')}</a>
</span>
- Files reviewed: 38/38 changed files
- Comments generated: 4
- Review effort level: Lite
| const streamShiftEvent = StreamingService.streamShiftEvent.subscribe( | ||
| async (event: TSocketEvent) => { | ||
| // Notify the user | ||
| const message = formatStreamShiftMessage(isIncomingStream, event.data.identifier); | ||
|
|
||
| promptAction({ | ||
| title: $t('Stream successfully switched'), | ||
| message, | ||
| btnText: $t('Close'), | ||
| btnType: 'default', | ||
| cancelBtnPosition: 'none', | ||
| }); | ||
| } | ||
| }); | ||
| const message = await RestreamService.actions.return.handleStreamShiftEvent(event); | ||
|
|
There was a problem hiding this comment.
🟡 Changes recommended
There are correctness/robustness issues in the new restream error formatting and an async RxJS subscribe handler that can trigger unhandled promise rejections.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
app/services/streaming/stream-error.ts:683
formatRestreamErrorMessageuses nullish coalescing fore.details, butStreamError.detailsis always a string (defaults to''). That means this will return an empty string and dropstatusTexteven when it would be useful for the UI/support message.
app/components-react/windows/go-live/StreamShiftCard.tsx:113- The tooltip “Learn More” is rendered via a clickable
<span>containing an<a>withouthref. This isn’t reliably keyboard-accessible and can be confusing for assistive tech; use a real button/link element for the interactive control.
<span data-name="explanation" onClick={handleTooltipClick}>
{$t(
'Stay uninterrupted by switching between devices mid stream. Works between Desktop and Mobile App.',
)}
<a style={{ marginLeft: 4 }}>{$t('Learn More')}</a>
</span>
- Files reviewed: 39/39 changed files
- Comments generated: 1
- Review effort level: Lite
| const streamShiftEvent = StreamingService.streamShiftEvent.subscribe( | ||
| async (event: TSocketEvent) => { | ||
| // Notify the user | ||
| const message = formatStreamShiftMessage(isIncomingStream, event.data.identifier); | ||
|
|
||
| promptAction({ | ||
| title: $t('Stream successfully switched'), | ||
| message, | ||
| btnText: $t('Close'), | ||
| btnType: 'default', | ||
| cancelBtnPosition: 'none', | ||
| }); | ||
| } | ||
| }); | ||
| const message = await RestreamService.actions.return.handleStreamShiftEvent(event); | ||
|
|
There was a problem hiding this comment.
🔵 Needs a closer look
It contains at least one confirmed Stream Shift/Live Output Editing incompatibility bug and an unhandled async error path that can produce unhandled promise rejections.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
app/components-react/windows/go-live/StreamShiftCard.tsx:34
- The toggle guard only checks
isStreamShiftDisabled, but the comment says Stream Shift is mutually exclusive with Live Output Editing. As written, users can enable Stream Shift while Live Output Editing is enabled (and the tooltip is disabled), resulting in both flags being set at once.
app/services/restream.ts:1337 handleStreamShiftEventcalls the asyncconfirmStreamShift()without awaiting or handling rejection, which can lead to an unhandled promise rejection if the network request fails.
app/services/streaming/stream-error.ts:678getRestreamErrorTypeuses an unnecessary cast for the default error type. SinceTStreamErrorTypeiskeyof typeof errorTypes, returning the literal keeps this type-safe and avoids masking typos/renames.
- Files reviewed: 41/41 changed files
- Comments generated: 0 new
- Review effort level: Lite
BundleMonFiles updated (1)
Unchanged files (3)
Total files change +14.75KB +0.09% Final result: ✅ View report in BundleMon website ➡️ |
Add Live Output Editing Cards, Granular Restream Errors, and Highlighter Banner Dismissal
This is PR 1 of 2 (PR 6164) and cannot be merged independently of PR 2. PR 6164 adds UI and error-handling scaffolding that nothing in this PR actually wires up yet.
Summary
This branch splits the Live Output Editing feature (edit destinations mid-stream from the Edit Stream window) into two PRs.
Changes
DisplaySelector.tsxnow distinguishes a target that is already live from one that isn't.CommonPlatformFields.tsxonly persists custom title when opted in.Files changed:
app/components-react/root/LiveDock.tsx,app/components-react/shared/DisplaySelector.tsx,app/components-react/shared/inputs/RadioInput.m.less,app/components-react/windows/go-live/AiHighlighterToggle.{tsx,m.less},app/components-react/windows/go-live/CommonPlatformFields.tsx,app/components-react/windows/go-live/GoLive.m.less,app/components-react/windows/go-live/GoLiveError.tsx,app/components-react/windows/go-live/GoLiveSettings.tsx,app/components-react/windows/go-live/GoLiveWindow.tsx,app/components-react/windows/go-live/LiveOutputEditingCard.tsx(new),app/components-react/windows/go-live/StreamShiftCard.tsx(new),app/components-react/windows/go-live/platforms/PlatformSettingsLayout.tsx,app/components-react/windows/go-live/platforms/TwitchEditStreamInfo.tsx,app/i18n/en-US/{highlighter,live-output-editing,live-outputs,streaming,twitch}.json,app/i18n/fallback.ts,app/services/dismissables.ts,app/services/platforms/twitch.ts,app/services/settings/streaming/stream-settings.ts,app/services/streaming/stream-error.ts,app/services/streaming/streaming-api.tsPerformance Implications
None. No new network calls, timers, or renders on any hot path — the changes are new unused components, new error-type plumbing, a new i18n bundle (identical total string count to what it replaces), and small conditional-rendering tweaks gated on existing state.