Skip to content

Multistream Toggle 1 - #6164

Merged
michelinewu merged 15 commits into
masterfrom
mw_multistream_toggle_final
Sep 9, 2026
Merged

Multistream Toggle 1#6164
michelinewu merged 15 commits into
masterfrom
mw_multistream_toggle_final

Conversation

@michelinewu

@michelinewu michelinewu commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

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

  • New card-based toggles for Stream Shift and Live Output Editing.
  • DisplaySelector.tsx now distinguishes a target that is already live from one that isn't.
  • Granular restream error types.
  • Add stable identifier for custom destination.
  • CommonPlatformFields.tsx only persists custom title when opted in.
  • Twitch enhanced broadcasting + live output editing handling.
  • Added Highlighter banner dismissable.
  • Add rollout flag.
  • Add strings.

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.ts

Performance 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.

Copilot AI lite review requested due to automatic review settings September 8, 2026 23:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.json and 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.

Comment thread app/services/streaming/streaming-api.ts
Comment thread app/components-react/windows/go-live/AiHighlighterToggle.tsx
Comment thread app/components-react/windows/go-live/LiveOutputEditingCard.tsx
Comment thread app/components-react/windows/go-live/StreamShiftCard.tsx
Comment thread app/i18n/en-US/live-output-editing.json
Comment thread app/services/settings/streaming/stream-settings.ts
Copilot AI review requested due to automatic review settings September 8, 2026 23:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 an href, 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

Comment on lines 249 to +253
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();
}
Comment on lines +680 to +686
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');
}
Copilot AI review requested due to automatic review settings September 9, 2026 01:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 no href. 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

Comment on lines +81 to +85
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);

Comment thread app/services/platforms/kick.ts
Comment thread app/components-react/windows/go-live/GoLiveInfoBanner.tsx Outdated
Comment thread app/services/platforms/kick.ts
@michelinewu michelinewu added the P0 highest priority to merge from Asana label Sep 9, 2026
Copilot AI review requested due to automatic review settings September 9, 2026 17:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

  • formatRestreamErrorMessage uses nullish coalescing for e.details, but StreamError.details is always a string (defaults to ''). That means this will return an empty string and drop statusText even 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> without href. 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

Comment on lines +81 to +85
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);

Copilot AI review requested due to automatic review settings September 9, 2026 18:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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
  • handleStreamShiftEvent calls the async confirmStreamShift() without awaiting or handling rejection, which can lead to an unhandled promise rejection if the network request fails.
    app/services/streaming/stream-error.ts:678
  • getRestreamErrorType uses an unnecessary cast for the default error type. Since TStreamErrorType is keyof 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

@bundlemon

bundlemon Bot commented Sep 9, 2026

Copy link
Copy Markdown

BundleMon

Files updated (1)
Status Path Size Limits
renderer.(hash).js
10.5MB (+14.75KB +0.14%) -
Unchanged files (3)
Status Path Size Limits
vendors~renderer.(hash).js
4.67MB -
updater.js
115.29KB -
guest-api.js
40.23KB -

Total files change +14.75KB +0.09%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@michelinewu
michelinewu merged commit 80150b1 into master Sep 9, 2026
10 of 14 checks passed
@michelinewu
michelinewu deleted the mw_multistream_toggle_final branch September 9, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P0 highest priority to merge from Asana

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants