Methods
(static) LoadItems_AddVideoContent(video, mediaSourceId, audioStreamIdxopt, forceTranscodingopt, bypassDoviPreservationopt) → {void}
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
video | object | |||
mediaSourceId | dynamic | |||
audioStreamIdx | integer | <optional> | 1 | |
forceTranscoding | boolean | <optional> | false | |
bypassDoviPreservation | boolean | <optional> | false |
- Type:
- void
(static) LoadItems_VideoPlayer(id, mediaSourceId, audioStreamIdxopt, forceTranscodingopt, bypassDoviPreservationopt) → {dynamic}
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
id | string | |||
mediaSourceId | dynamic | |||
audioStreamIdx | integer | <optional> | 1 | |
forceTranscoding | boolean | <optional> | false | |
bypassDoviPreservation | boolean | <optional> | false |
- Type:
- dynamic
(static) addAudioStreamsToVideo(video, meta, mediaSourceId) → {void}
addAudioStreamsToVideo: Populate video.fullAudioData with the item's audio tracks.
Sources from the original item metadata (meta.mediaSourcesData), not from the PlaybackInfo response. The /PlaybackInfo response can return a transcode-shaped MediaSource carrying only the chosen audio stream, which would shrink the OSD picker to a single entry (issue #500). The OSD picker must always list every original track so the user can switch.
| Name | Type | Description |
|---|---|---|
video | object | video AA receiving the fullAudioData field |
meta | dynamic | item metadata (from ItemMetaData) holding mediaSourcesData |
mediaSourceId | dynamic | chosen MediaSource ID (matches one entry under meta.mediaSourcesData.mediaSources) |
- Type:
- void
(static) addNextEpisodesToQueue(showID) → {void}
Add next episodes to the playback queue
| Name | Type | Description |
|---|---|---|
showID | dynamic |
- Type:
- void
(static) addSubtitlesToVideo(video, meta) → {void}
| Name | Type | Description |
|---|---|---|
video | dynamic | |
meta | dynamic |
- Type:
- void
(static) fetchMostRecentVersionId(itemId, meta, mediaSources) → {string}
fetchMostRecentVersionId: Ask the server which of an item's versions it would resume.
The resume query returns the version that owns the resume point, which is the answer the source order gives only from a primary (see versionResume.chooseResumeSource). Scoped to the item's parent (its season, or the folder holding a movie), so the reply is that parent's in-progress items rather than the whole of Continue Watching, and lean, because only ids are read.
answer, so the caller falls back to the order instead of asking again
| Name | Type | Description |
|---|---|---|
itemId | string | the item being played |
meta | object | ItemMetaData() for it |
mediaSources | object | its MediaSources |
the version's source id, or "" when the server cannot say, itself an
- Type:
- string
(static) fetchVersionPositions(positions, sourceIds) → {void}
fetchVersionPositions: Read each named version's own position into positions.
A version that does not answer is recorded as POSITION_UNREADABLE rather than left absent, so the caller's next pass cannot ask for it again and loop, and so an unread position is never mistaken for "this version has no progress", which would silently restart the content.
| Name | Type | Description |
|---|---|---|
positions | object | sourceId -> ticks, filled in place |
sourceIds | object | the versions to read |
- Type:
- void
(static) init() → {void}
- Type:
- void
(static) loadItems() → {void}
- Type:
- void
(static) reloadProbedStreams(meta, mediaSourceId) → {void}
reloadProbedStreams: Replace the item's media sources with the ones the server saved when the first PlaybackInfo probed them. Leaves meta as it was when the read fails, so the caller's picks stand and nothing else changes.
| Name | Type | Description |
|---|---|---|
meta | object | item metadata (from ItemMetaData), updated in place |
mediaSourceId | dynamic | the MediaSource being played |
- Type:
- void
(static) resolveResumeVersion(itemId, meta, mediaSources) → {object}
resolveResumeVersion: Which of an item's versions resumes, and from where.
The imperative shell around versionResume.chooseResumeSource(): that function owns every rule and says what it still needs; this fetches it and asks again. Same division as ItemDetails, so both entry points reach an identical answer. The split between them is what made the app name one version on the details screen and play another.
Reads ride apiPipeline rather than a fetch loop: the pipeline keeps as many requests on the pool as it has slots, so N versions cost roughly one round trip instead of N. Each reply was ~150 bytes against the item's ~17 KB (measured 2026-09-19), and nothing is fetched at all unless something is already in progress, so an item nobody has started costs no requests on the playback path. When the source order cannot say which version was played last, one more request asks the server (fetchMostRecentVersionId).
| Name | Type | Description |
|---|---|---|
itemId | string | the item being played |
meta | object | ItemMetaData() for it (its own UserData position comes from here) |
mediaSources | object | its MediaSources, in server order |
{ sourceId, ticks }: sourceId "" when no version is in progress
- Type:
- object
(static) setupVideoContentWithAuth(video, mediaSourceId, audioStreamIdx) → {void}
setupVideoContentWithAuth: Configures video content URL and applies authentication
Determines the appropriate URL based on protocol and stream location, then applies Jellyfin authentication headers for internal streams. External streams (non-localhost) receive the raw URL without authentication to prevent credential leakage.
Protocol handling:
- "file": Direct stream from Jellyfin server (gets auth)
- Non-file with localhost domain: Proxied through Jellyfin (gets auth)
- Non-file with external domain: Direct external URL (NO auth)
| Name | Type | Description |
|---|---|---|
video | object | Video object containing content node to configure |
mediaSourceId | dynamic | Media source ID or empty string for live streams |
audioStreamIdx | integer | Selected audio stream index |
- Type:
- void
(static) upstreamManifestAnswers(url, format) → {boolean}
upstreamManifestAnswers: Whether THIS device can load a source's upstream manifest URL.
The device check before playing a source from its own URL (getUpstreamManifestBlocker). The server reaching a URL says nothing about the Roku reaching it, and a Roku handed one it cannot reach does not error: an unroutable host or an unresolvable name leaves it buffering, so the direct-play fallback does not run. A GET within timeouts.UPSTREAM_PREFLIGHT_MS that returns a manifest of the declared format is the answer (isUpstreamManifestResponse); anything else uses the server's stream. Raw roUrlTransfer on this Task thread, no Jellyfin auth (the URL is not Jellyfin's) and the URL is never logged, because upstream URLs carry session tokens.
| Name | Type | Description |
|---|---|---|
url | dynamic | the source's upstream manifest URL (MediaSource.Path) |
format | string | "hls" or "dash" (upstreamManifestFormat) |
- Type:
- boolean