Members
(static, constant) ESTIMATED_BUTTON_ROW_HEIGHT_PX
First-frame estimate for the button row's total rendered height. Used by anchorDateLabel() before boundingRect() has settled (it reports height=0 during initial render). Observed to land around 130 px for the typical 2-line-label icon button. A later renderTracking callback replaces this with the real measured height once layout completes.
- Default Value
- 130
- Source
(static, constant) ITEM_DETAILS_EXTRAS_PADDING
Gap between bottom of itemInfoRows and top of extras pane when extras are open
- Default Value
- 24
- Source
(static, constant) LOGO_MAX_DISPLAY_HEIGHT
Maximum display height for non-Person primary images — prevents portrait posters from extending above the metadata rows. Person photos are exempt because their info rows are short and don't reach the right edge where the photo sits.
- Default Value
- 336
- Source
(static, constant) LOGO_MAX_DISPLAY_WIDTH
Maximum display width for the logo image — prevents very wide/flat logos from overlapping buttons
- Default Value
- 500
- Source
(static, constant) LOGO_MIN_DISPLAY_HEIGHT
Minimum display height for the logo image — images too small are scaled up (aspect ratio preserved).
- Default Value
- 212
- Source
Methods
(static) SetDefaultAudioTrack(mediaStreams) → {void}
SetDefaultAudioTrack: Auto-select the best audio stream based on user language prefs, storing the result on m.top.selectedAudioStreamIndex. The dropdown trigger label is refreshed separately by applyDropdown() using the same index.
| Name | Type | Description |
|---|---|---|
mediaStreams | object |
- Type:
- void
(static) activateExtras() → {void}
- Type:
- void
(static) anchorDateLabel() → {integer}
anchorDateLabel: Derive the date label's Y position from the button group's position. Returns dateLabelY so callers (e.g. logo positioning) can use it without duplicating the math. Safe to call multiple times — idempotent, and safe to call BEFORE the button group has finished laying out: falls back to the group's fixed translation + ESTIMATED_BUTTON_ROW_HEIGHT_PX so the label never lands off-screen. A later renderTracking callback refines the position once the real rendered height is known.
dateLabelY — the Y coordinate used for the date label
- Type:
- integer
(static) applyDropdown(dropdown, items, selectedId, applicable) → {void}
applyDropdown: Push items + selection into a single TrackDropdown. Hides the slot when the track type isn't applicable (keeps layout order stable for the other two slots).
| Name | Type | Description |
|---|---|---|
dropdown | object | |
items | object | |
selectedId | string | |
applicable | boolean |
- Type:
- void
(static) buildAudioDropdownItems(streams) → {object}
buildAudioDropdownItems: Convert the MediaStreams array into dropdown items for audio. Item id is the stringified server-side stream index, matching the ItemDetails contract that selectedAudioStreamIndex is an integer spanning all stream types.
| Name | Type | Description |
|---|---|---|
streams | object |
- Type:
- object
(static) buildSubtitleDropdownItems(streams) → {object}
buildSubtitleDropdownItems: Convert the MediaStreams array into dropdown items for subtitles.
Two shapes are returned depending on whether the item actually has subtitle streams: No subtitle streams at all → [{ id:"-1", title:"None" }]. Rendered as a static non-interactive slot so the "Subtitles" title row still shows and the layout stays consistent across items. "None" (not "Off") because the user has no choice to make — subtitles simply don't exist on this item. One or more subtitle streams → [{ id:"-1", title:"Off" }, ...tracks]. The "Off" entry lets the user disable subtitles when tracks ARE present. id "-1" is the SubtitleSelection.NONE sentinel used by m.top.selectedSubtitleStreamIndex.
| Name | Type | Description |
|---|---|---|
streams | object |
- Type:
- object
(static) buildVideoDropdownItems(mediaSources) → {object}
buildVideoDropdownItems: Convert MediaSources into dropdown items. "Video" here is the MediaSource, not a stream — it's the user-facing alternate-version selector (e.g. "1080p H264" vs "4K HEVC HDR10").
| Name | Type | Description |
|---|---|---|
mediaSources | object |
- Type:
- object
(static) checkDeepLinkLaunch() → {void}
See the call site in onScreenShown. A deep-link route carries ?deeplink=
- Type:
- void
(static) checkTrailerAvailability(itemId) → {void}
Fetches whether the item has local trailers, to add/remove the Trailer button (onTrailerAvailableChanged reacts to the result). Render-thread promise — replaces the former trailerResultNode + onTrailerCheckDone observer (Phase-3b: a render-thread submitApiRequest + observeField flow → fetchAsync().then(); canonical in docs/dev/promises.md).
| Name | Type | Description |
|---|---|---|
itemId | string |
- Type:
- void
(static) createDividerNode(dividerId) → {object}
createDividerNode: Create a bullet divider node for separating info items
| Name | Type | Description |
|---|---|---|
dividerId | string | Unique ID for the divider |
Configured divider node
- Type:
- object
(static) createEndsAtNode() → {void}
createEndsAtNode: Build an "Ends at" time label with AM/PM support and store it on m.endsAtNode for dynamic clock updates. Used by types with runTimeTicks-based durations.
- Type:
- void
(static) createInfoLabel(labelId) → {object}
createInfoLabel: Create a bold label node for the info rows
| Name | Type | Description |
|---|---|---|
labelId | string | Unique ID for the label |
Configured LabelPrimaryMedium node
- Type:
- object
(static) createTimeLabel(labelId, timeText, periodText) → {object}
createTimeLabel: Creates a time label with an optional lowercase am/pm suffix. In 24h mode returns a single label; in 12h mode appends the period to the time text.
| Name | Type | Description |
|---|---|---|
labelId | string | |
timeText | string | |
periodText | string |
- Type:
- object
(static) deactivateExtras() → {void}
- Type:
- void
(static) deferDeepLinkLaunchUntilIdle() → {void}
keepAlive resume: the content is already loaded, but onScreenShown runs MID-navigation, and the router rejects a navigateTo issued while a navigation is in progress (Router.brs _navigateTo). So wait for the navigation to settle (routerState -> NavigationEnd) before launching, otherwise startPlayFromDetail's navigateTo("/play") is swallowed (toast fires, but no player). Fresh mounts don't need this — they launch from onDetailsLoaded, which is already async / router-idle.
- Type:
- void
(static) dispatchDeepLinkAction() → {void}
Do exactly what the route's action asked, on the validated item. The action is the SENDER'S explicit intent — never inferred from the resolved item: open (and any unknown action) -> stay on the springboard (this view). Grid-container targets (library/folder/genre/studio/channel) never reach here — JRScene.onDeepLinkResolved diverts them to their grid. play -> QueueManager.launchItem (the DRY per-type play engine: video resumes its bookmark, Series smart-resumes, containers play, live watches, audio -> audio player, photo -> viewer). shuffle -> the same path the Shuffle button uses (onShuffleButtonPressed). trailer -> play this item's trailer(s). instantmix -> build an instant mix from the item (mirrors the instantMixButton).
- Type:
- void
(static) displayDirectorGenreNode(node) → {void}
displayDirectorGenreNode: Add a node to the second info row, prepending a bullet divider if needed
| Name | Type | Description |
|---|---|---|
node | object |
- Type:
- void
(static) displayInfoNode(node) → {void}
displayInfoNode: Add a node to the info group, prepending a bullet divider if needed
| Name | Type | Description |
|---|---|---|
node | object |
- Type:
- void
(static) displayRatingNodes(userSettings, communityRating, criticRating) → {void}
displayRatingNodes: Community + critic rating chips shared across every rateable item type's Row 1. Both are gated behind uiMoviesShowRatings and only render when the value is present (> 0), so it's safe to call for any type — types without a rating from the server simply show nothing. Values are passed explicitly (rather than reading item.* directly) so callers that need a parent-series fallback (Season) can resolve the value first.
| Name | Type | Description |
|---|---|---|
userSettings | object | |
communityRating | float | |
criticRating | float |
- Type:
- void
(static) firstInteractiveDropdown() → {object}
firstInteractiveDropdown: Returns the first visible, interactive TrackDropdown in left-to-right order, or invalid if none exist.
- Type:
- object
(static) focusButtonGroupChild() → {void}
focusButtonGroupChild: Focus the button at the current buttonFocused index directly
- Type:
- void
(static) focusInteractiveDropdown(candidates) → {void}
focusInteractiveDropdown: Walks the given candidate list and focuses the first dropdown that is interactive AND visible. The candidate order encodes both direction and wrap behavior; the currently-focused dropdown is always last so the nav falls back to it if nothing else is interactive (effectively: stay put).
| Name | Type | Description |
|---|---|---|
candidates | object |
- Type:
- void
(static) getButtonIndex(buttonId) → {integer}
getButtonIndex: Find the index of a button by ID in the button group
| Name | Type | Description |
|---|---|---|
buttonId | string | The id of the button to find |
The index of the button, or -1 if not found
- Type:
- integer
(static) getHistory() → {string}
getHistory: Format the air schedule/status string for a Series item Example output: "ABC" or "Fridays at 9:30 PM on NBC"
- Type:
- string
(static) getResumeButtonText(item) → {string}
getResumeButtonText: Return "Resume S{n}E{n}" when season and episode numbers are known, otherwise fall back to plain "Resume".
| Name | Type | Description |
|---|---|---|
item | object | nextUpEpisode JellyfinBaseItem node |
Localised button label
- Type:
- string
(static) getRuntime() → {integer}
- Type:
- integer
(static) getStreamsForSelectedSource(mediaSources) → {object}
getStreamsForSelectedSource: Pull the MediaStreams array from whichever media source matches m.top.selectedVideoStreamId. Falls back to mediaSources[0] when the selected id isn't found (e.g. first load before selection).
| Name | Type | Description |
|---|---|---|
mediaSources | object |
- Type:
- object
(static) init() → {void}
- Source
- Type:
- void
(static) isPlayAllType(itemType) → {boolean}
True for item types whose Play builds a multi-item queue via an API call (handled by QuickPlayTask, not the single-item path below).
| Name | Type | Description |
|---|---|---|
itemType | dynamic |
- Type:
- boolean
(static) launchQueueItemToPlay(queueItem, routeType, routeId) → {void}
Seed the queue with a single item and navigate to the play route. The router is idle (the user pressed a button on this settled view), so navigateTo won't hit the in-progress guard; PlayerHostView reads this queue on mount. :type/:id give the route a deep-link identity; the queue is the source of truth for what actually plays.
| Name | Type | Description |
|---|---|---|
queueItem | object | |
routeType | string | |
routeId | string |
- Type:
- void
(static) loadFromRoute(route) → {void}
Set itemType + itemId from a route's params. Setting itemId fires onItemIdChanged (the async loader). itemType is set first since the loader reads it.
| Name | Type | Description |
|---|---|---|
route | object |
- Source
- Type:
- void
(static) manageResumeButton() → {void}
manageResumeButton: Add or remove Resume button based on playback position (non-Series types)
- Type:
- void
(static) onAudioDropdownFocusExit() → {void}
- Type:
- void
(static) onAudioDropdownSelection() → {void}
Audio dropdown selection: updates selectedAudioStreamIndex and re-seeds the subtitle auto-selection (Smart mode depends on which audio is playing). If the user has already manually overridden the subtitle, we leave it alone.
- Type:
- void
(static) onButtonGrpRendered() → {void}
onButtonGrpRendered: Fires after the render thread settles the button group layout. Re-anchors the date label and repositions the logo. The track dropdown cluster lives inside itemDetails LayoutGroup and is positioned automatically by the layout engine, so it doesn't need to be re-placed here.
- Type:
- void
(static) onClockMinuteChanged() → {void}
onClockMinuteChanged: Dynamically update "Ends At" time when overhang clock minute changes.
- Type:
- void
(static) onDeepLinkRouterIdle() → {void}
- Type:
- void
(static) onDeleteButtonPressed(item) → {void}
Delete button. Confirm, then delete and leave the now-gone routed detail via the router. Scoped isDataReturned observer (see onWatchedButtonPressed).
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) onDeleteConfirmResponse() → {void}
- Type:
- void
(static) onDestroy() → {void}
onDestroy: Full teardown releasing all resources before component removal Called automatically via JRScreen.beforeViewClose when sgRouter permanently closes this view.
- Type:
- void
(static) onDetailNavButton(msg) → {void}
Single handler for every button on this detail's button group. Detail→detail nav (goToSeries / goToAlbum / goToArtist / goToChannel) navigates the router; playback buttons launch through the QueueManager / the play route; the rest run their render-thread action directly.
| Name | Type | Description |
|---|---|---|
msg | dynamic |
- Type:
- void
(static) onDetailsLoaded() → {void}
Callback when initial item details metadata arrives from the task
- Type:
- void
(static) onDropdownRequestDown() → {void}
DOWN from any dropdown returns focus to the button group.
- Type:
- void
(static) onDropdownRequestUp() → {void}
Dropdown navigation: UP from any dropdown goes to description when in layout, else is consumed (no-op). parent-level UP handling reused so we don't have three identical handlers.
- Type:
- void
(static) onExtrasItemSelected(msg) → {void}
Extras grid (cast / related / next-up) selection → navigate to its route, passing the rich node as context. Non-navigable items fall through to playback (quickPlayNode).
| Name | Type | Description |
|---|---|---|
msg | dynamic |
- Type:
- void
(static) onExtrasTargetTranslationYChanged() → {void}
onExtrasTargetTranslationYChanged: Animate the RowList translation to the new target. Fired early by onKeyEvent in ExtrasRowList (at key press) so the animation runs in parallel with the RowList's floatingFocus animation, and confirmed by onRowItemFocused after focus lands.
- Type:
- void
(static) onFavoriteToggleFailed(favoriteButton, attemptedState) → {void}
Reverts the favorite button to its pre-press state and surfaces an error toast.
| Name | Type | Description |
|---|---|---|
favoriteButton | object | |
attemptedState | boolean |
- Type:
- void
(static) onFirstEpisodeLoaded() → {void}
onFirstEpisodeLoaded: Start playback of first episode for Series Play button
- Type:
- void
(static) onItemContentChanged() → {void}
- Type:
- void
(static) onItemDetailsRendered() → {void}
- Type:
- void
(static) onItemIdChanged() → {void}
Triggered when itemId is set (route load) — kicks off async data load
- Type:
- void
(static) onKeyEvent(key, press) → {boolean}
| Name | Type | Description |
|---|---|---|
key | string | |
press | boolean |
- Type:
- boolean
(static) onLogoLoadStatusChanged() → {void}
onLogoLoadStatusChanged: Position logo to the right, with its bottom just above the date label. When the date label is hidden, anchors to where the date label would be. Images smaller than LOGO_MIN_DISPLAY_HEIGHT are scaled up while preserving aspect ratio, unless the logo is very wide/flat, in which case LOGO_MAX_DISPLAY_WIDTH takes precedence.
- Type:
- void
(static) onLyricsLoaded() → {void}
onLyricsLoaded: Show lyrics in the description area once the async fetch completes (Audio only)
- Type:
- void
(static) onNextUpEpisodeChanged() → {void}
nextUpEpisodeChanged: For Series — create/remove Resume button based on nextUpEpisode. On first load, replaces the LoadingButton placeholder from setupButtons(). On refresh, inserts/updates/removes the Resume button directly.
- Type:
- void
(static) onPersonHasMediaChanged() → {void}
onPersonHasMediaChanged: Show or hide the Shuffle button once the person extras chain completes. On first load, replaces the LoadingButton placeholder from setupButtons(). On refresh, inserts/removes the Shuffle button directly. Fires via alwaysNotify so it triggers even when personHasMedia stays the same value (e.g. on refresh).
- Type:
- void
(static) onPlaylistContentKindChanged() → {void}
onPlaylistContentKindChanged: Drives the Watched button and item-count label based on the confirmed content kind of the playlist ("video" / "audio" / "mixed" / "unknown"). Fires via alwaysNotify so it triggers even when the kind is unchanged (e.g. on refresh).
Watched button: only shown for "video" (has at least one video-type item). Label: "Tracks" only when positively confirmed "audio" (all items are Audio type). All other kinds — including "unknown" (load failure) and "mixed" — stay "Items".
- Type:
- void
(static) onQuickPlayLaunch(msg) → {void}
Forward a non-navigable extras selection to the playback launcher.
| Name | Type | Description |
|---|---|---|
msg | dynamic |
- Type:
- void
(static) onRecordButtonPressed(item) → {void}
Record / cancel-record a Live TV program. Owns the RecordProgramTask on this render thread.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) onRecordResult() → {void}
- Type:
- void
(static) onRefreshDetailsLoaded() → {void}
Callback when refreshed item details metadata arrives
- Type:
- void
(static) onRefreshExtrasData() → {void}
onRefreshExtrasData: Reload all extras rows when the user explicitly presses Refresh.
- Type:
- void
(static) onRefreshItemDetailsData() → {void}
Triggered by refreshItemDetailsData field toggle (return from playback, refresh button). Refreshes silently in the background — no spinner, no input blocking. The UI already has data from the initial load so the user can navigate freely.
- Type:
- void
(static) onRefreshResumeData() → {void}
Triggered by refreshResumeData field toggle (watched toggle on Series). Re-fetches ONLY the next-up/resume episode — no full rebuild, no setupButtons(). The existing onNextUpEpisodeChanged() handles adding/removing/updating the resume button.
- Type:
- void
(static) onRouteUpdate(_eventopt) → {dynamic}
The router reuses this view (no remount) when navigating to the SAME details path it's already showing — e.g. a cast of the item you're already on, after a player above it was popped. m.top.route is the new route by now, so re-run the deep-link check (its route.id dedup makes it a one-shot per navigation). Non-deep-link same-path updates are no-ops.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
_event | object | <optional> | {} |
- Source
- Type:
- dynamic
(static) onScreenHidden() → {void}
- Source
- Type:
- void
(static) onScreenShown() → {void}
onScreenShown: Callback when view is presented on screen
- Source
- Type:
- void
(static) onSeasonSeriesDataLoaded() → {void}
onSeasonSeriesDataLoaded: Update Season info rows and logo with parent series metadata
- Type:
- void
(static) onSeriesResumeLoaded() → {void}
onSeriesResumeLoaded: Set nextUpEpisode from seriesResume task result to show/hide the Resume button
- Type:
- void
(static) onShuffleButtonPressed(item) → {void}
Shuffle button. Routes by item type so new types can be added. PhotoAlbum launches a random slideshow; everything else resolves a randomized item set via GetShuffleItemsTask on the QueueManager.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) onSubtitleDropdownFocusExit() → {void}
- Type:
- void
(static) onSubtitleDropdownSelection() → {void}
Subtitle dropdown selection: marks user override so subsequent audio changes don't clobber the pick, then stores the new index. Action "-1" = Off.
- Type:
- void
(static) onTrackDropdownFocusChanged() → {void}
onTrackDropdownFocusChanged: Observer wired to each TrackDropdown's focusedChild. Remembers the last dropdown that held focus so the UP-from-buttons handler can restore the previous slot on re-entry instead of always defaulting to video.
- Type:
- void
(static) onTrackDropdownMenuOpenChanged() → {void}
onTrackDropdownMenuOpenChanged: Observer wired to each TrackDropdown's menuOpen. Toggles the full-screen dimmer iff ANY dropdown's menu is currently open. The trackCluster (titles + triggers + the open menu itself) renders ABOVE the dimmer in XML sibling order, so only the screen content BEHIND the cluster dims — category titles and trigger labels stay full-brightness as the user's "you are here" cue while picking a track.
- Type:
- void
(static) onTrailerAvailableChanged() → {void}
- Type:
- void
(static) onVideoDropdownFocusExit() → {void}
LEFT/RIGHT between dropdowns — each dropdown has its own exit handler so we know which slot we came from and can target the correct neighbor, skipping non-interactive slots.
- Type:
- void
(static) onVideoDropdownSelection() → {void}
Video dropdown selection fires when the user picks a different MediaSource (alternate version). We swap in the new source's streams, re-run audio auto-select, and rebuild the audio/subtitle dropdowns against the new source. Focus stays on the video dropdown.
- Type:
- void
(static) onWatchChannelButtonPressed(item) → {void}
Watch a Live TV channel (TvChannel detail, or the channel a Program airs on) — single-item launch via the play route.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) onWatchedButtonPressed(item) → {void}
Watched button. Movie/Episode toggle immediately; a Series confirms first (marking all episodes can affect hundreds). The confirmation result is read off the SceneManager via a SCOPED isDataReturned observer (the proven settings.bs pattern). On confirm we call toggleWatched(), which re-reads the button state to pick mark vs unmark.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) onWatchedConfirmResponse() → {void}
Series mark-all-watched confirmation result.
- Type:
- void
(static) onWatchedToggleFailed(watchedButton, attemptedState) → {void}
Reverts the watched button to its pre-press state, clears the resume button's loading state, and surfaces an error toast.
| Name | Type | Description |
|---|---|---|
watchedButton | object | |
attemptedState | boolean |
- Type:
- void
(static) pickTrackDropdownFromButtons() → {object}
pickTrackDropdownFromButtons: Chooses which TrackDropdown to focus when UP is pressed from the button group. Ignores m.lastFocusedDropdown by design — UP-from-buttons should ALWAYS land on the dropdown visually above the currently focused button, not on wherever the user was last time. Each slot spans 2 buttons: slot 1 sits above buttons [0,1], slot 2 above [2,3], slot 3 above [4,5,...]. Widens outward to the nearest interactive slot if the preferred one is static/hidden.
CRITICAL: guards on m.trackCluster.visible — when the item type has no media tracks (Series/Person/BoxSet/etc.), the cluster is hidden but the individual dropdown nodes may still carry stale visible=true / isInteractive=true from a previously-loaded item. Without this guard, focus would move to an invisible stale dropdown when the user presses UP on those item types.
- Type:
- object
(static) pickTrackDropdownFromDescription() → {object}
pickTrackDropdownFromDescription: Chooses which TrackDropdown to focus when DOWN is pressed from the description. Restores m.lastFocusedDropdown if still usable so the user returns to wherever they were before moving up. Falls back to the leftmost interactive dropdown (video → audio → subtitles) for the first-ever entry. Also guards on m.trackCluster.visible to match pickTrackDropdownFromButtons above.
- Type:
- object
(static) playFromDeepLink(actionopt) → {void}
Run the deep-link action on this already-loaded item in response to a runtime cast that landed while the user is ALREADY on its details (replayRoute.replayDeepLinkRuntime) — no navigation, so no Home flash and no re-mount. The router is idle here, so any navigateTo the action triggers succeeds directly (no NavigationEnd defer needed). action is the new cast's intent (the cached view's m.deepLinkAction is from its original mount and may be stale).
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
action | string | <optional> | "play" |
- Type:
- void
(static) populateDescriptionGroup() → {void}
populateDescriptionGroup: Set FocusableOverview text with tagline and overview
- Type:
- void
(static) populateInfoGroup() → {void}
populateInfoGroup: Dispatch to type-specific info row builder
- Type:
- void
(static) populateInfoGroupAudio(item, userSettings) → {void}
populateInfoGroupAudio: Info rows for Audio (song) Row 1: Track N · Disc N (only when disc > 1) · Runtime · Ends At Row 2: Album name · Album artist
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupBoxSet(item, userSettings) → {void}
populateInfoGroupBoxSet: Info rows for BoxSet (movie collection) Row 1: Year · Official Rating · Community Rating · Critic Rating · N Movies Row 2: Genres · Studio
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupEpisode(item, userSettings) → {void}
populateInfoGroupEpisode: Info rows for Episode Row 1: Air Date · Official Rating · Community Rating · Critic Rating · Runtime · Ends At Row 2: Series name + "S{n}E{n}"
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupMovie(item, userSettings) → {void}
populateInfoGroupMovie: Info rows for Movie, Video, Recording Row 1: Year · Official Rating · Community Rating · Critic Rating · Runtime · Ends At Row 2: Genres · Director(s)
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupMusicAlbum(item, userSettings) → {void}
populateInfoGroupMusicAlbum: Info rows for MusicAlbum Row 1: Year · Runtime · Ends At Row 2: Album Artist · Genres · N Tracks
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupMusicArtist(item) → {void}
populateInfoGroupMusicArtist: Info rows for MusicArtist Row 1: N Albums · N Songs · Year Row 2: Genres
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) populateInfoGroupMusicVideo(item, userSettings) → {void}
populateInfoGroupMusicVideo: Info rows for MusicVideo Row 1: Year · Official Rating · Community Rating · Critic Rating · Runtime · Ends At Row 2: Genres · Artist(s)
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupPerson(item) → {void}
populateInfoGroupPerson: Info rows for Person Row 1: {birthDate} [- {deathDate}] · {n} years old Living: Jan 1, 1980 · 45 years old Deceased: Jan 1, 1920 - Dec 31, 1980 · 60 years old Row 2: {n} Movie(s) [· {n} Episode(s)] — omitted entirely if both counts are 0
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) populateInfoGroupPhoto(item) → {void}
populateInfoGroupPhoto: Info rows for Photo Row 1: Resolution ("WxH") · Camera ("Make Model") · Production Year Row 2: Album name (if present)
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) populateInfoGroupPhotoAlbum(item) → {void}
populateInfoGroupPhotoAlbum: Info rows for PhotoAlbum Row 1: Photo count
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) populateInfoGroupPlaylist(item, userSettings) → {void}
populateInfoGroupPlaylist: Info rows for Playlist Row 1: N Items · Runtime · Ends At Row 2: Genres The item count label starts as "Items" and is swapped to "Tracks" by onPlaylistContentKindChanged() once the extras chain confirms the playlist is all-audio.
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupProgram(item, userSettings) → {void}
populateInfoGroupProgram: Info rows for Program (Live TV EPG entry) Row 1: Year · CH X - ChanName · OfficialRating · CommunityRating · CriticRating · S#E# · Premiere/Repeat · Runtime · BroadcastTime · Ends At Row 2: Genres (or category flags)
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupRecording(item, userSettings) → {void}
populateInfoGroupRecording: Info rows for Recording (Live TV recorded content) Row 1: PremiereYear · OfficialRating · CommunityRating · CriticRating · S#E# · Runtime · Ends At · CH X - ChanName · Recorded: Date Row 2: Genres
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupSeason(item, userSettings) → {void}
populateInfoGroupSeason: Info rows for Season Row 1: Year · Official Rating (series) · Community Rating (series) · Critic Rating (series) · Avg episode runtime (series) · Ends At Row 2: Series name · Episode count · Studio
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupSeries(item, userSettings) → {void}
populateInfoGroupSeries: Info rows for Series Row 1: Year Range · Official Rating · Community Rating · Critic Rating · Runtime · Ends At (only when avg episode runtime is available) Row 2: Genres · Air schedule/Status
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateInfoGroupTvChannel(item, userSettings) → {void}
populateInfoGroupTvChannel: Info rows for TvChannel (Live TV) Displays metadata from the current program (the channel is a vessel for what's airing). Row 1: CH N · OfficialRating · CommunityRating · CriticRating · S#E# · Program Name · Runtime · BroadcastTime · Ends At Row 2: Genres (or category flags)
| Name | Type | Description |
|---|---|---|
item | object | |
userSettings | object |
- Type:
- void
(static) populateTrackDropdowns(mediaSources, allStreams, itemType) → {void}
populateTrackDropdowns: Build the Video/Audio/Subtitle dropdown items from the current media source list and stream list for the given item type, then toggle the cluster + title row visibility. Seeds m.top.selectedSubtitleStreamIndex from findDefaultSubtitleStreamIndex() on first load so the initial trigger label reflects what playback will actually use.
| Name | Type | Description |
|---|---|---|
mediaSources | object | Array of MediaSource objects (may be empty) |
allStreams | object | MediaStreams from the selected source (video/audio/subs mixed) |
itemType | string | The item type string (drives which slots apply) |
- Type:
- void
(static) removeResumeButtonWithFocus(resumeButton) → {void}
removeResumeButtonWithFocus: Remove resume button while preserving focus position
| Name | Type | Description |
|---|---|---|
resumeButton | object |
- Type:
- void
(static) removeResumeLoadingButton() → {void}
removeResumeLoadingButton: Remove the resume LoadingButton placeholder if still present. Called when async data confirms no resume episode exists (nextUpEpisode stays invalid).
- Type:
- void
(static) resolveGoToArtistId(item) → {string}
Resolve the artist id for goToArtist: prefer the primary album artist, fall back to the single artist item.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- string
(static) resumeSeriesNextUp() → {void}
Series Resume plays the next-up episode (a single item) from its saved position, via the play route.
- Type:
- void
(static) round(f) → {integer}
| Name | Type | Description |
|---|---|---|
f | float |
- Type:
- integer
(static) setDateAdded(item) → {void}
setDateAdded: Set date added label text and position at bottom right corner
| Name | Type | Description |
|---|---|---|
item | object | JellyfinBaseItem node |
- Type:
- void
(static) setDescriptionInLayout(shouldShow) → {void}
setDescriptionInLayout: Add or remove itemDescription from the itemDetails LayoutGroup. Invisible nodes still take up space in RSG LayoutGroups, so reparenting is required to truly eliminate spacing when there is no description text.
| Name | Type | Description |
|---|---|---|
shouldShow | boolean |
- Type:
- void
(static) setFieldText(field, value) → {void}
| Name | Type | Description |
|---|---|---|
field | dynamic | |
value | dynamic |
- Type:
- void
(static) setItemLogo(item) → {void}
setItemLogo: Set the item logo image URL if available. Fallback chains by type — every chain ends in a typed placeholder via getPlaceholderImagePath() so the logo slot never goes blank, matching the pattern Person and MusicArtist always used:
- Movie/Series/BoxSet: Logo → primaryImageTag (poster, compact size) → placeholder
- Episode/Season/Recording: primaryImageTag → parentLogoImageTag (series logo) → seriesPrimaryImageTag → placeholder
- Video/MusicVideo: primaryImageTag → placeholder
- MusicAlbum / Playlist / Photo / PhotoAlbum / TvChannel: primaryImageTag → placeholder
- Program: primaryImageTag → channel logo → placeholder
- Audio: primaryImageTag → album art → placeholder
- Person / MusicArtist: primaryImageTag (portrait) → placeholder
| Name | Type | Description |
|---|---|---|
item | object | JellyfinBaseItem node |
- Type:
- void
(static) setTracksInLayout(shouldShow) → {void}
setTracksInLayout: Add or remove the 62px itemTracks spacer from the itemDetails LayoutGroup. When a track cluster is applicable to the current item, the spacer stays in the layout and pushes description bottom up to y=701 so the trackCluster sibling can sit at y=713 with 12px breathing pad above and 18px below between the description and the button group. For item types without any media tracks (Series/Person/etc.), the spacer is removed and description bottom drops back to y=775 (matching main's behavior — no cluster, no padding, no regression).
| Name | Type | Description |
|---|---|---|
shouldShow | boolean |
- Type:
- void
(static) setupButtons(item) → {void}
setupButtons: Build the complete button set for the given item type. Clears all existing buttons and adds the correct sync buttons in order. Loading placeholders are added for async buttons (Series Resume, Person Shuffle) so the button row renders at its final width immediately. The async handlers replace or remove the placeholders when data arrives. Called on every itemContentChanged — the button list is rebuilt from scratch each time.
| Name | Type | Description |
|---|---|---|
item | object |
- Type:
- void
(static) startPlayFromDetail(startingPoint) → {void}
Build the single-item play queue from this detail's own state and navigate to the play route. The router is idle (the user pressed a button on this settled view), so navigateTo won't hit the in-progress guard, and the PlayerHostView reads this queue on mount.
| Name | Type | Description |
|---|---|---|
startingPoint | longinteger |
- Type:
- void
(static) toggleFavorite() → {void}
callFunc entry — toggles the favorite state of the current item. Invoked from main.bs's button router; because callFunc rendezvouses to this render-thread-owned node, the body (and the fetchAsync().then() promise delivery + auto-abandon) runs on this component's render thread, where the named-observer adapter works. This is the Phase-3c canonical "main thread → render thread delegation" pattern — see docs/dev/promises.md. It moves the favorite toggle off main.bs's god-loop (was submitApiRequest + isDone branch + handler).
- Type:
- void
(static) toggleWatched() → {void}
callFunc entry — toggles the watched/played state of the current item. Invoked from main.bs's button router; Movie/Episode call it directly, while Series route through the "mark all episodes" confirmation dialog first (main.bs keeps that dialog routing and re-invokes this on confirm — #550 sgRouter territory). Because callFunc rendezvouses to this render-thread-owned node, the body (and the fetchAsync().then() promise delivery + auto-abandon) runs on this component's render thread, where the named-observer adapter works. This is the deferred twin of toggleFavorite() — the Phase-3c "main thread → render thread delegation" pattern (see docs/dev/promises.md). It moves the LAST raw submitApiRequest + isDone flow off main.bs's god-loop.
- Type:
- void
(static) triggerTextForSelection(items, selectedId) → {string}
triggerTextForSelection: Look up the currently-selected item's display title.
| Name | Type | Description |
|---|---|---|
items | object | |
selectedId | string |
- Type:
- string
(static) updateFavoriteButton() → {void}
- Type:
- void
(static) updateItemDetailsAnimationTarget() → {void}
updateItemDetailsAnimationTarget: Slide itemDetails so the bottom of itemInfoRows sits just above the extras pane. boundingRect() on a child returns LOCAL coords relative to the parent's translation point, so we use translation[1] (not boundingRect().y) as the screen origin. Called just-in-time from the DOWN key handler to guarantee the layout is fully settled (text wrapping complete) before measuring. Eager calculation via renderTracking races with async text layout, producing stale targets — especially for long descriptions.
- Type:
- void
(static) updateTextGradient() → {void}
- Type:
- void
(static) updateWatchedButton() → {void}
- Type:
- void