Members

(static, constant) TRICKPLAYBAR_POSITION_LABEL_INDEX

Child index for position label in Roku's built-in trickPlayBar component. The trickPlayBar is part of the Video node and doesn't expose child IDs, so we must access by index. Fallback search logic exists if Roku changes the structure. Defined at module level (BrighterScript const requirement) to provide immutability and enable reuse across multiple helper functions if needed.

Default Value
  • 8

Methods

(static) abandonErrorDialog() → {void}

Called by PlayerHostView BEFORE it clears the modal/overlay channels during its own teardown (prepareToLeaveMount, shared by the finished and Live TV stall paths). See the call site for why this has to run first. Abandon, not cancel: nothing should observe a result from a dialog that playback is walking away from regardless.

Returns:
Type: 
void

(static) announceNowPlaying() → {object}

Returns the metadata in the response: main.bs's transport dispatcher calls roAppManager.SetNowPlayingContentMetaData() on the MAIN thread (roAppManager can't be created on the render thread, where this callFunc executes).

Returns:
Type: 
object

(static) availSubtitleTrackIdx(tracknameToFind) → {integer}

availSubtitleTrackIdx: Returns Roku's index for requested subtitle track

Parameters:
NameTypeDescription
tracknameToFindstring

TrackName for subtitle we're looking to match

Returns:

indicating Roku's index for requested subtitle track. Returns SubtitleSelection.NONE if not found

Type: 
integer

(static) bufferCheck() → {void}

Check the the buffering has not hung

Returns:
Type: 
void

(static) checkMediaSegments() → {void}

Check media segments and trigger appropriate actions based on current playback position

Returns:
Type: 
void

(static) checkTimeToDisplayNextEpisode() → {void}

Checks if we need to display the Next Episode button

Returns:
Type: 
void

(static) clearPlaybackErrorState() → {void}

The state one shown error owns: the dialog slot, the text both tiers render, and the exit claim PlayerHostView reads. One place, because the three ways an error ends (acknowledged, superseded, abandoned by teardown) all have to leave exactly the same nothing behind. A claim outliving its dialog would gag the host's queue logic for the life of this player node. Every queue advance builds a fresh one (PlayerHostView.playCurrentQueueItem), so it cannot leak past that, which is the bound and not a reason to be sloppy about clearing it.

Returns:
Type: 
void

(static) exitFromPlaybackError() → {void}

One exit path for both tiers, so the report and the alert cannot drift apart about what closing means.

Returns:
Type: 
void

(static) fetchNextEpisode() → {void}

Fetches the current + next episode (Limit 2) to decide whether the Next Episode button should be enabled. Render-thread promise; replaces the former GetNextEpisodeTask, a pure-fetch Task that existed only to move one fetchRes off the render thread (Phase-3a collapse; canonical example in docs/dev/promises.md).

Returns:
Type: 
void

(static) findTrickPlayBarPositionLabel() → {dynamic}

findTrickPlayBarPositionLabel: Defensively finds the position text label in trickPlayBar

Tries multiple strategies to find the Label that displays seek position:

  1. Expected child index (8) - fast path for current Roku OS
  2. Search for FIRST Label child - position text comes before remaining time
  3. Return invalid if not found - feature gracefully degrades
Returns:
  • Label node or invalid if not found
Type: 
dynamic

(static) forceFinishPlayback() → {void}

Forces playback to finished state for proper watched-status and auto-play. Triggers synchronous teardown (onState -> PlayerHostView.onPlayerStateChange -> destroy/ goBack -> onDestroy), invalidating all m. references. Callers must return immediately after.

Returns:
Type: 
void

(static) getCurrentChapterIndex() → {integer}

getCurrentChapterIndex: Finds current chapter index

Returns:

indicating index of current chapter within chapter data or 0 if chapter lookup fails

Type: 
integer

(static) getEffectiveDuration() → {float}

The media duration in seconds, or 0 when it is not known.

Falls back to content.length (which Jellyfin populates from mediaSource.RunTimeTicks) when Roku's own duration probe returns 0. This happens with live-transcoded progressive MKV: ffmpeg can't know the final duration while encoding, so it writes 0 into the MKV SegmentInfo header, and Roku's probe inherits that.

Returns:
Type: 
float

(static) getInstantReplaySeconds() → {integer}

Returns:
Type: 
integer

(static) handleChapterListAction() → {void}

handleChapterListAction: Handles action to show chapter list

Returns:
Type: 
void

(static) handleChapterSkipAction(action) → {void}

handleChapterSkipAction: Handles user command to skip chapters in playing video

Parameters:
NameTypeDescription
actionstring
Returns:
Type: 
void

(static) handleGoToLiveAction() → {void}

Returns:
Type: 
void

(static) handleHideAction(resume) → {void}

handleHideAction: Handles action to hide OSD menu

Parameters:
NameTypeDescription
resumeboolean

controls whether or not to resume video playback when sub is called

Returns:
Type: 
void

(static) handleItemSkipAction(action) → {void}

handleItemSkipAction: Handles user command to skip items

Parameters:
NameTypeDescription
actionstring

skip action to take

Returns:
Type: 
void

(static) handleShowAudioMenuAction() → {void}

handleShowAudioMenuAction: Handles action to show audio selection menu

Returns:
Type: 
void

(static) handleShowSubtitleMenuAction() → {void}

handleShowSubtitleMenuAction: Handles action to show subtitle selection menu

Returns:
Type: 
void

(static) handleShowVideoInfoPopupAction() → {void}

handleShowVideoInfoPopupAction: Handles action to show video info popup

Returns:
Type: 
void

(static) handleShowVideoSourceMenuAction() → {void}

handleShowVideoSourceMenuAction: Handles action to show video source selection menu

Returns:
Type: 
void

(static) handleTransport(evt) → {object}

handleTransport: Roku voice and remote-control transport handler. Reached through remoteDispatch.dispatchTransport (main.bs's voice roInputEvent branch, and the ws:// receiver) and PlayerHostView.handleTransport, which forwards to this player.

Returns { status: "" } per roInput.EventResponse(). Roku OS uses the status to render the appropriate HUD message. Codes used here:

  • success / success.seek-start / success.seek-end: op completed (with bounds note)
  • error.redundant: state already matches request (for example pause-while-paused)
  • error.generic: op semantically unsupported in this context
  • unhandled: command we don't recognize; lets Roku show "Command not available"

See https://github.com/rokudev/dev-doc, docs/DEVELOPER/media-playback/voice-controls/transport-controls.md

Parameters:
NameTypeDescription
evtobject
Returns:
Type: 
object

(static) handleVideoPlayPauseAction() → {void}

handleVideoPlayPauseAction: Handles action to either play or pause the video content

Returns:
Type: 
void

(static) handleVideoPreviousItem() → {object}

Remote "PreviousTrack": step back one queue item, symmetric with handleVoiceNextItem. error.generic at the head of the queue (no previous item): no chapter-back concept here.

Returns:
Type: 
object

(static) handleVoiceNextItem() → {object}

Reuse the OSD itemNext code path so Live-TV channel advance, queue advance, and Episode-to-next-Episode all behave identically to pressing the on-screen Next button.

Returns:
Type: 
object

(static) handleVoiceSeekCommand(evt) → {object}

Parameters:
NameTypeDescription
evtobject
Returns:
Type: 
object

(static) hideNextEpisodeButton() → {void}

Hide the Next Episode notification

Returns:
Type: 
void

(static) init() → {void}

Returns:
Type: 
void

(static) isLiveTvPlayback() → {boolean}

Returns:
Type: 
boolean

(static) isTrackPickAgainstOldVersion() → {boolean}

isTrackPickAgainstOldVersion: True when an audio or subtitle pick that needs a reload arrives while a version switch is still loading, and the pick must then be ignored.

The pickers list the tracks of the version that was playing until the new one delivers, so the picked index belongs to that version's streams, not the new one's. Reloading would either undo the switch or ask the new version for a track it may not have. Ignoring it lets the switch's run finish with the tracks it chose for the new version. The pick also rewrites no start point: the switch already mapped the position into the new version's timeline.

Returns:
Type: 
boolean

(static) itemOriginalLanguage() → {string}

The playing item's OriginalLanguage (12.0+), for the "Original language" audio preference.

Returns:
Type: 
string

(static) liveProgressMs() → {integer}

Called by PlayerHostView when this mount's live stream ends or stalls: how much of it played, for the restart rule (newLiveProgress in liveTv.bs).

Returns:
Type: 
integer

(static) loadCaption() → {void}

Set caption url to server subtitle track and run the fetch task

Returns:
Type: 
void

(static) loadChannelListForQueue() → {void}

Collapsed from LoadChannelListForQueueTask, a pure-fetch Task that existed only to move one fetchRes off the render thread (Phase-4 collapse; see docs/dev/promises.md). Fire-once per playback (guarded by m.channelListLoaded), so no seq guard is needed: a single .then can't race itself the way a hot re-fire would.

Returns:
Type: 
void

(static) onAllowCaptionsChange() → {void}

Only setup caption items if captions are allowed

Returns:
Type: 
void

(static) onAudioIndexChange() → {void}

Event handler for when audioIndex changes. For direct play: switches audio track directly using Roku's availableAudioTracks (no stop/reload needed since all tracks are in the container). For transcoded, or when the newly-selected stream exceeds the device's audio capability (for example, switching from stereo back to an 8ch track on a stereo Roku), must reload so the server transcodes the new selection.

Returns:
Type: 
void

(static) onDestroy() → {void}

onDestroy: Full teardown releasing all resources before component removal Called by PlayerHostView.destroyPlayer, on every remount and on the host's own teardown

Returns:
Type: 
void

(static) onKeyEvent(key, press) → {boolean}

Parameters:
NameTypeDescription
keystring
pressboolean
Returns:
Type: 
boolean

(static) onLiveTvMetadataRefreshed() → {void}

Returns:
Type: 
void

(static) onNextEpisodeFetchFailed() → {void}

Re-arms the next-episode check after a fetch that never produced a usable response, so a later "playing" transition retries it.

Returns:
Type: 
void

(static) onNextEpisodeNotificationAction() → {void}

Handler for Next Episode notification action

Returns:
Type: 
void

(static) onNotificationStateChanged() → {void}

Safety net: ensure focus isn't orphaned after notification dismissal animation completes

Returns:
Type: 
void

(static) onOSDAction() → {void}

onOSDAction: Process action events from OSD to their respective handlers

Returns:
Type: 
void

(static) onPlaybackErrorDetailsClosed() → {void}

Returns:
Type: 
void

(static) onPlaybackErrorDialogResult() → {void}

Fires on any REAL resolution of the error dialog: the user pressing OK, or Back (result.cancelled, same as OK here: there's nothing to cancel back to). Either way, leave the play route.

A close driven by PLAYBACK TEARDOWN instead of the user must never reach this handler. abandonErrorDialog() below is how teardown clears the dialog without firing it, so this always means a real user action. Routing teardown through the ordinary result path was the old bug (playback-error-dialog-closed-by-teardown): the old raw Dialog's wasClosed observer could not tell "user pressed OK" from "code closed me", so a teardown-triggered close both delivered a result AND raced the teardown's own navigation. PlayerHostView.prepareToLeaveMount is the call site that matters: it abandons before it cancels, and the comment there says why the order matters.

Returns:
Type: 
void

(static) onPositionChanged() → {void}

When Video Player state changes

Returns:
Type: 
void

(static) onSegmentNotificationAction() → {void}

Handler for segment notification action

Returns:
Type: 
void

(static) onState() → {void}

When Video Player state changes

Returns:
Type: 
void

(static) onSubtitleChange() → {void}

Event handler for when selectedSubtitle changes

Returns:
Type: 
void

(static) onTrickPlayBarTextChange() → {void}

Called when Roku's trickPlayBar position text changes Parses the time string to get seek position and syncs our carousel This ensures carousel stays in sync with Roku's authoritative seek position

Returns:
Type: 
void

(static) onVideoContentLoaded(event) → {void}

Parameters:
NameTypeDescription
eventobject
Returns:
Type: 
void

(static) onVideoSourceChange() → {void}

onVideoSourceChange: Handles video source switching from OSD Saves position, stops playback, re-selects audio for the new source's streams, and reloads video content with the new MediaSource ID.

Returns:
Type: 
void

(static) parkPlayerAfterSupersede() → {void}

A superseded error leaves the player alive and stopped. PARK it: clear the error state, hide the node, and stop treating it as a controllable player.

Not cosmetic. The Video node draws Roku's OWN buffering indicator (the internal retrievingBar / bufferingBar ProgressBars; bufferingBar is the one styled in init) and it keeps drawing after the stream stops: a black screen with a ring reading 0%, which is the app telling the user it is loading, forever. Hiding the node removes it and reveals the backdrop the host already set for this item.

The OSD goes with it. stateAllowsOSD() admits "stopped", so without the flag Up would open an OSD inside a hidden parent: a control surface that renders nothing and takes the focus Back needs. Parked there is nothing to control and Back is the only action, which is what the state actually is.

Undone in onState's playing branch, not here: the route back into playback is not this scope. A voice or remote-control play restarts a stopped node WITHOUT going through onVideoContentLoaded, which is the only other place that makes the player visible.

Returns:
Type: 
void

(static) pauseWithOsd() → {void}

Pause and show the OSD in its paused state: what the Play key does to a playing video. Also PlayerHostView's when nobody answers the still-watching prompt, so a viewer who comes back finds the same paused player they would have left themselves.

Returns:
Type: 
void

(static) playbackErrorContext() → {object}

What we know about WHAT was playing, for the Details rows. Read from the already-loaded content rather than re-derived: this runs on a failure path, so it must not be able to fail itself.

Returns:
Type: 
object

(static) populateChapterMenu() → {void}

populateChapterMenu: ' Parse chapter data from API and appeand to chapter list menu

Returns:
Type: 
void

(static) releaseUnplayedLiveStream(loadedLiveStream, why) → {void}

Close the live stream a load opened when no player will ever play it: the load failed, or it is being replaced by a load of the server's stream. Nothing reported its start, so the server has no session to release it with (endClosesLiveStream); a close by id does.

Parameters:
NameTypeDescription
loadedLiveStreamdynamic

LoadVideoContentTask.liveStream: { stage, id }, or invalid

whystring

for the log line

Returns:
Type: 
void

(static) releaseVideoLoad(task) → {void}

Lets go of the video load when this view goes away, releasing the Live TV live stream it opened exactly once (liveStreamHandoff.bs decides how, from the stage the load recorded).

Parameters:
NameTypeDescription
taskobject

the LoadVideoContentTask this view ran

Returns:
Type: 
void

(static) reportPlayback(stateopt) → {void}

Report playback to server

Parameters:
NameTypeAttributesDefaultDescription
statestring<optional>
"update"
Returns:
Type: 
void

(static) reportPlaybackEnd(playerState) → {void}

Report the end of this stream, once (classifyPlaybackEnd decides which report, if any). Every end needs one: the stop is also what stops the server's transcode and releases a Live TV live stream this session reported playing, which a terminal error would otherwise leave open until the server restarts, since onState ignores every later state (#988). A live stream that never reported its start is released by a close by id instead, and its stop then does not name it, so the stream is released exactly once (endClosesLiveStream). Once per stream, because a stop can also surface as finished, and the server records each report as its own "finished playing".

Parameters:
NameTypeDescription
playerStatestring

the Video state that ended the stream: stopped, finished or error

Returns:
Type: 
void

(static) reportStallStop() → {void}

Called by PlayerHostView right before it restarts a Live TV channel whose stream stalled. Without it, each stall restart left the server one consumer holding the live stream (on a tuner-limited server, a tuner): measured on a Stick 4K against 12.1, where Back, voice "stop" and a channel switch from a playing channel all report their stop.

Returns:
Type: 
void

(static) retryPlayback(bypassDovi, forceTranscode) → {void}

retryPlayback: Re-runs the content loader from the current position with updated task flags. Used by error handlers to retry without exiting the player.

Parameters:
NameTypeDescription
bypassDoviboolean

skips DoVi container profile so the server can grant direct play

forceTranscodeboolean

disables direct play so the server returns a transcode URL

Returns:
Type: 
void

(static) seekRelativeWithBounds(deltaSeconds) → {object}

Parameters:
NameTypeDescription
deltaSecondsinteger
Returns:
Type: 
object

(static) seekToWithBounds(targetSeconds) → {object}

30s end-slack matches the Roku transport-controls reference example for video: clamping shy of duration prevents the player from firing end-of-content immediately.

Parameters:
NameTypeDescription
targetSecondsfloat
Returns:
Type: 
object

(static) setFavorite(isLike) → {object}

Parameters:
NameTypeDescription
isLikeboolean
Returns:
Type: 
object

(static) shouldUseCustomSubtitlesForCurrentSelection() → {boolean}

Determines if custom subtitles should be used for the current selection Custom subtitles should only be used for external subtitles when the user has enabled the setting

Returns:
Type: 
boolean

(static) showChannelSwitchSpinner(nextItem) → {void}

Parameters:
NameTypeDescription
nextItemobject
Returns:
Type: 
void

(static) showLiveStreamStalledError(causeKey) → {void}

Called by PlayerHostView when a Live TV stream stalls and it will not restart the channel (it had not played healthily). The same cause as showLiveStreamStoppedError, plus the stop a stall needs (an ended stream has already stopped). Same shape as bufferCheck's stall error: the dialog claims the exit first, so the finished this stop can surface as is ignored by the host.

Parameters:
NameTypeDescription
causeKeystring

a translationKeys value

Returns:
Type: 
void

(static) showLiveStreamStoppedError(causeKey) → {void}

Called by PlayerHostView when it gives up on a Live TV channel that keeps ending without playing, which is a finished rather than an error, so nothing here would show one. The player reports no error code for it, so the cause is given in words, chosen by the host (liveGiveUpCauseKey in liveTv.bs).

Parameters:
NameTypeDescription
causeKeystring

a translationKeys value

Returns:
Type: 
void

(static) showNextEpisodeButton() → {void}

Show the Next Episode notification with countdown text

Returns:
Type: 
void

(static) showPlaybackErrorDetails() → {void}

The diagnostic readout behind [Details]. A plain report overlay: it owns no result contract (OverviewDialog self-closes), so the exit is driven by its closed field instead.

Returns:
Type: 
void

(static) showPlaybackErrorDialog(serverMessageopt) → {void}

Show the playback error.

serverMessage is a message the SERVER already explained in words (the LoadVideoContentTask failures); when it is empty the cause is derived from the Video node's own errorCode. Either way the diagnostics come off the node, so a failure that never reached the player has fewer rows.

Parameters:
NameTypeAttributesDefaultDescription
serverMessagestring<optional>
""
Returns:
Type: 
void

(static) startVideoLoad(audioStreamIndex, subtitleIndex, bypassDoviopt, forceTranscodeopt) → {void}

startVideoLoad: Start a run of the video load for the current item, on a NEW LoadVideoContentTask node, and declare the metadata fill onVideoContentLoaded resolves.

A new node every run because a run can start while the last one is still going: a second audio, subtitle or version pick before the first one's stream arrives, or the server-stream retry onVideoContentLoaded starts from inside a delivery. The same node would drop that launch, so the viewer's last pick was lost or the player stayed on its spinner (threading.md, "Relaunching and stopping a Task"). The run it replaces goes through releaseVideoLoad, never a bare STOP, because it may be opening a Live TV stream that only its answer names.

A new node starts with every field at its default, so this passes the full input set each time. The version is m.videoLoadMediaSourceId; the retry flags apply to one run only.

Parameters:
NameTypeAttributesDefaultDescription
audioStreamIndexinteger

server index of the audio stream; 0 lets the load pick

subtitleIndexinteger

server index of the subtitle stream, or a SubtitleSelection value

bypassDoviboolean<optional>
false

skip the DoVi container profile (retryPlayback)

forceTranscodeboolean<optional>
false

disable direct play (retryPlayback)

Returns:
Type: 
void

(static) stateAllowsOSD() → {boolean}

stateAllowsOSD: Check if current video state allows showing the OSD

Returns:

indicating if video state allows the OSD to show

Type: 
boolean

(static) submitPlaybackReport(state, failed, closesLiveStreamopt) → {void}

reportPlayback's body. A separate function because reportPlayback is also the playback timer's fire observer, which must keep its one-argument signature.

Parameters:
NameTypeAttributesDefaultDescription
statestring

start, update, stop or finished

failedboolean

a stop marked Failed, which leaves the resume position alone (reportPlaybackEnd)

closesLiveStreamboolean<optional>
false

an end whose live stream a close releases, so it must not name it

Returns:
Type: 
void

(static) switchToQueueItem(queueManager, targetPosition) → {void}

The channel's playback start is opened before this player stops, and the player mounted next takes it (QueueManager.takePlaybackStart), so nothing this player does on its way out can end it.

Parameters:
NameTypeDescription
queueManagerobject
targetPositioninteger
Returns:
Type: 
void

(static) toggleCaption() → {void}

Toggles visibility of custom subtitles and sets the caption renderer's player state

Returns:
Type: 
void

(static) trackLiveProgress() → {void}

Feeds this mount's live progress from one position notification. A jump is logged because the step size that separates playing from a jump (LIVE_PROGRESS_MAX_STEP_MS) is a tuned value.

Returns:
Type: 
void

(static) triggerLiveTvMetadataRefresh() → {void}

Returns:
Type: 
void

(static) tryActiveSegmentSkip() → {boolean}

Skip an active media segment (intro/recap/etc.) if one is currently in-window. Returns true if a segment was skipped, false if no active segment.

Returns:
Type: 
boolean

(static) updateCaption() → {void}

Removes old subtitle lines and adds new subtitle lines

Returns:
Type: 
void

(static) updateNextEpisodeCount() → {void}

Update Next Episode countdown text

Returns:
Type: 
void

(static) updateTrickplayCarousel(position) → {void}

Updates trickplay carousel with index calculated from video position Snaps to thumbnail boundaries for cleaner UX

Parameters:
NameTypeDescription
positionFloat

Video position in seconds

Returns:
Type: 
void