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.
- 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).
- Type:
- object
(static) availSubtitleTrackIdx(tracknameToFind) → {integer}
availSubtitleTrackIdx: Returns Roku's index for requested subtitle track
| Name | Type | Description |
|---|---|---|
tracknameToFind | string | TrackName for subtitle we're looking to match |
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
- Type:
- void
(static) checkMediaSegments() → {void}
Check media segments and trigger appropriate actions based on current playback position
- Type:
- void
(static) checkTimeToDisplayNextEpisode() → {void}
Checks if we need to display the Next Episode button
- 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.
- Type:
- void
(static) exitFromPlaybackError() → {void}
One exit path for both tiers, so the report and the alert cannot drift apart about what closing means.
- 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).
- 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:
- Expected child index (8) - fast path for current Roku OS
- Search for FIRST Label child - position text comes before remaining time
- Return invalid if not found - feature gracefully degrades
- 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.
- Type:
- void
(static) getCurrentChapterIndex() → {integer}
getCurrentChapterIndex: Finds current chapter index
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.
- Type:
- float
(static) getInstantReplaySeconds() → {integer}
- Type:
- integer
(static) handleChapterListAction() → {void}
handleChapterListAction: Handles action to show chapter list
- Type:
- void
(static) handleChapterSkipAction(action) → {void}
handleChapterSkipAction: Handles user command to skip chapters in playing video
| Name | Type | Description |
|---|---|---|
action | string |
- Type:
- void
(static) handleGoToLiveAction() → {void}
- Type:
- void
(static) handleHideAction(resume) → {void}
handleHideAction: Handles action to hide OSD menu
| Name | Type | Description |
|---|---|---|
resume | boolean | controls whether or not to resume video playback when sub is called |
- Type:
- void
(static) handleItemSkipAction(action) → {void}
handleItemSkipAction: Handles user command to skip items
| Name | Type | Description |
|---|---|---|
action | string | skip action to take |
- Type:
- void
(static) handleShowAudioMenuAction() → {void}
handleShowAudioMenuAction: Handles action to show audio selection menu
- Type:
- void
(static) handleShowSubtitleMenuAction() → {void}
handleShowSubtitleMenuAction: Handles action to show subtitle selection menu
- Type:
- void
(static) handleShowVideoInfoPopupAction() → {void}
handleShowVideoInfoPopupAction: Handles action to show video info popup
- Type:
- void
(static) handleShowVideoSourceMenuAction() → {void}
handleShowVideoSourceMenuAction: Handles action to show video source selection menu
- 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
| Name | Type | Description |
|---|---|---|
evt | object |
- Type:
- object
(static) handleVideoPlayPauseAction() → {void}
handleVideoPlayPauseAction: Handles action to either play or pause the video content
- 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.
- 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.
- Type:
- object
(static) handleVoiceSeekCommand(evt) → {object}
| Name | Type | Description |
|---|---|---|
evt | object |
- Type:
- object
(static) hideNextEpisodeButton() → {void}
Hide the Next Episode notification
- Type:
- void
(static) init() → {void}
- Type:
- void
(static) isLiveTvPlayback() → {boolean}
- 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.
- Type:
- boolean
(static) itemOriginalLanguage() → {string}
The playing item's OriginalLanguage (12.0+), for the "Original language" audio preference.
- 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).
- Type:
- integer
(static) loadCaption() → {void}
Set caption url to server subtitle track and run the fetch task
- 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.
- Type:
- void
(static) onAllowCaptionsChange() → {void}
Only setup caption items if captions are allowed
- 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.
- 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
- Type:
- void
(static) onKeyEvent(key, press) → {boolean}
| Name | Type | Description |
|---|---|---|
key | string | |
press | boolean |
- Type:
- boolean
(static) onLiveTvMetadataRefreshed() → {void}
- 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.
- Type:
- void
(static) onNextEpisodeNotificationAction() → {void}
Handler for Next Episode notification action
- Type:
- void
(static) onNotificationStateChanged() → {void}
Safety net: ensure focus isn't orphaned after notification dismissal animation completes
- Type:
- void
(static) onOSDAction() → {void}
onOSDAction: Process action events from OSD to their respective handlers
- Type:
- void
(static) onPlaybackErrorDetailsClosed() → {void}
- 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.
- Type:
- void
(static) onPositionChanged() → {void}
When Video Player state changes
- Type:
- void
(static) onSegmentNotificationAction() → {void}
Handler for segment notification action
- Type:
- void
(static) onState() → {void}
When Video Player state changes
- Type:
- void
(static) onSubtitleChange() → {void}
Event handler for when selectedSubtitle changes
- 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
- Type:
- void
(static) onVideoContentLoaded(event) → {void}
| Name | Type | Description |
|---|---|---|
event | object |
- 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.
- 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.
- 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.
- 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.
- Type:
- object
(static) populateChapterMenu() → {void}
populateChapterMenu: ' Parse chapter data from API and appeand to chapter list menu
- 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.
| Name | Type | Description |
|---|---|---|
loadedLiveStream | dynamic | LoadVideoContentTask.liveStream: { stage, id }, or invalid |
why | string | for the log line |
- 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).
| Name | Type | Description |
|---|---|---|
task | object | the LoadVideoContentTask this view ran |
- Type:
- void
(static) reportPlayback(stateopt) → {void}
Report playback to server
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
state | string | <optional> | "update" |
- 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".
| Name | Type | Description |
|---|---|---|
playerState | string | the Video state that ended the stream: stopped, finished or error |
- 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.
- 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.
| Name | Type | Description |
|---|---|---|
bypassDovi | boolean | skips DoVi container profile so the server can grant direct play |
forceTranscode | boolean | disables direct play so the server returns a transcode URL |
- Type:
- void
(static) seekRelativeWithBounds(deltaSeconds) → {object}
| Name | Type | Description |
|---|---|---|
deltaSeconds | integer |
- 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.
| Name | Type | Description |
|---|---|---|
targetSeconds | float |
- Type:
- object
(static) setFavorite(isLike) → {object}
| Name | Type | Description |
|---|---|---|
isLike | boolean |
- 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
- Type:
- boolean
(static) showChannelSwitchSpinner(nextItem) → {void}
| Name | Type | Description |
|---|---|---|
nextItem | object |
- 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.
| Name | Type | Description |
|---|---|---|
causeKey | string | a translationKeys value |
- 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).
| Name | Type | Description |
|---|---|---|
causeKey | string | a translationKeys value |
- Type:
- void
(static) showNextEpisodeButton() → {void}
Show the Next Episode notification with countdown text
- 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.
- 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.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
serverMessage | string | <optional> | "" |
- 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.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
audioStreamIndex | integer | server index of the audio stream; 0 lets the load pick | ||
subtitleIndex | integer | server index of the subtitle stream, or a SubtitleSelection value | ||
bypassDovi | boolean | <optional> | false | skip the DoVi container profile (retryPlayback) |
forceTranscode | boolean | <optional> | false | disable direct play (retryPlayback) |
- Type:
- void
(static) stateAllowsOSD() → {boolean}
stateAllowsOSD: Check if current video state allows showing the OSD
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.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
state | string | start, update, stop or finished | ||
failed | boolean | a stop marked | ||
closesLiveStream | boolean | <optional> | false | an end whose live stream a close releases, so it must not name it |
- 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.
| Name | Type | Description |
|---|---|---|
queueManager | object | |
targetPosition | integer |
- Type:
- void
(static) toggleCaption() → {void}
Toggles visibility of custom subtitles and sets the caption renderer's player state
- 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.
- Type:
- void
(static) triggerLiveTvMetadataRefresh() → {void}
- 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.
- Type:
- boolean
(static) updateCaption() → {void}
Removes old subtitle lines and adds new subtitle lines
- Type:
- void
(static) updateNextEpisodeCount() → {void}
Update Next Episode countdown text
- Type:
- void
(static) updateTrickplayCarousel(position) → {void}
Updates trickplay carousel with index calculated from video position Snaps to thumbnail boundaries for cleaner UX
| Name | Type | Description |
|---|---|---|
position | Float | Video position in seconds |
- Type:
- void