Methods
(static) AudioItem(id) → {dynamic}
Get audio item metadata (raw, no transform)
| Name | Type | Description |
|---|---|---|
id | string |
- Source
- Type:
- dynamic
(static) AudioStream(id) → {dynamic}
| Name | Type | Description |
|---|---|---|
id | string |
- Source
- Type:
- dynamic
(static) BackdropImage(id) → {dynamic}
| Name | Type | Description |
|---|---|---|
id | string |
- Source
- Type:
- dynamic
(static) BuildAlbumSongsRequest(albumId) → {dynamic}
The Audio tracks on an album.
| Name | Type | Description |
|---|---|---|
albumId | string |
- Source
- Type:
- dynamic
(static) BuildArtistAlbumsRequest(artistId) → {dynamic}
Albums where this artist is the album artist (strict: AlbumArtistIds only), newest first. Does not include albums the artist only contributes to. See BuildArtistAppearsOnRequest.
| Name | Type | Description |
|---|---|---|
artistId | string |
- Source
- Type:
- dynamic
(static) BuildArtistAppearsOnRequest(artistId) → {dynamic}
Albums an artist appears on as a contributing artist but is not the album artist of: Jellyfin's ContributingArtistIds, so mutually exclusive with BuildArtistAlbumsRequest. Newest first.
| Name | Type | Description |
|---|---|---|
artistId | string |
- Source
- Type:
- dynamic
(static) BuildArtistSongsRequest(artistId) → {dynamic}
All Audio tracks by an artist in any capacity (album artist OR contributing), so songs on compilations or with mismatched album-level tags still surface. Grouped by album then track; capped at 100 for prolific artists.
| Name | Type | Description |
|---|---|---|
artistId | string |
- Source
- Type:
- dynamic
(static) GetIntroVideos(id) → {dynamic}
Get Intro Videos for an item
| Name | Type | Description |
|---|---|---|
id | string |
- Source
- Type:
- dynamic
(static) GetItemLyrics(itemId) → {dynamic}
Get lyrics for an Audio item.
| Name | Type | Description |
|---|---|---|
itemId | string | The Audio item ID |
- Source
LyricDto: { Metadata: {...}, Lyrics: [{Start: ticks, Text: string}] }, or invalid
- Type:
- dynamic
(static) GetMediaSegments(id) → {dynamic}
GetMediaSegments: Fetches media segments for an item (Intro, Outro, Recap, etc.).
Only available on Jellyfin 10.10.0+ servers. Returns invalid for older servers.
| Name | Type | Description |
|---|---|---|
id | string | The item ID |
- Source
- { Items: [MediaSegmentDto], TotalRecordCount } or invalid
- Type:
- dynamic
(static) ItemDetailsMetaData(id, forceRefreshopt) → {dynamic}
MetaData for an item detail screen. Includes People, Genres, and Studios in addition to Chapters and Trickplay. Use this instead of ItemMetaData() when populating a detail view.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
id | string | |||
forceRefresh | boolean | <optional> | false |
- Source
- Type:
- dynamic
(static) ItemMetaData(id, fieldsopt, forceRefreshopt) → {dynamic}
MetaData about an item. Returns a JellyfinBaseItem node.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
id | string | |||
fields | string | <optional> | "Chapters,Trickplay" | Comma-separated Jellyfin fields to request. Defaults to Chapters and Trickplay only. |
forceRefresh | boolean | <optional> | false |
- Source
- Type:
- dynamic
(static) ItemPostPlaybackInfo(id, mediaSourceIdopt, audioTrackIndexopt, subtitleTrackIndexopt, startTimeTicksopt, videoMetadataopt, bypassDoviPreservationopt, forceTranscodingopt) → {dynamic}
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
id | string | |||
mediaSourceId | string | <optional> | "" | |
audioTrackIndex | integer | <optional> | -1 | |
subtitleTrackIndex | integer | <optional> | SubtitleSelection.NONE | |
startTimeTicks | longinteger | <optional> | 0& | |
videoMetadata | dynamic | <optional> | invalid | |
bypassDoviPreservation | boolean | <optional> | false | |
forceTranscoding | boolean | <optional> | false |
- Source
- Type:
- dynamic
(static) ItemPostPlaybackInfoResponse(id, mediaSourceIdopt, audioTrackIndexopt, subtitleTrackIndexopt, startTimeTicksopt, videoMetadataopt, bypassDoviPreservationopt, forceTranscodingopt, timeoutMsopt) → {dynamic}
ItemPostPlaybackInfo's pool response itself, so a caller can tell an answer that never came (apiResponse.noAnswer) from a refusal.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
id | string | |||
mediaSourceId | string | <optional> | "" | |
audioTrackIndex | integer | <optional> | -1 | |
subtitleTrackIndex | integer | <optional> | SubtitleSelection.NONE | |
startTimeTicks | longinteger | <optional> | 0& | |
videoMetadata | dynamic | <optional> | invalid | |
bypassDoviPreservation | boolean | <optional> | false | |
forceTranscoding | boolean | <optional> | false | |
timeoutMs | integer | <optional> | 0 | the request's HTTP limit (apiTimeout); 0 keeps the default |
- Source
the pool response AA, or invalid when the caller's wait ran out
- Type:
- dynamic
(static) applyLiveTvMinSegments(postData) → {void}
applyLiveTvMinSegments: For HLS transcodes that report no source duration (live channels), request ≥8 segments per Roku's recommendation. Gives ~48 s seekable DVR window.
| Name | Type | Description |
|---|---|---|
postData | object |
- Source
- Type:
- void
(static) applyMediaSourceToPostData(postData, mediaSourceId, forceTranscoding) → {void}
applyMediaSourceToPostData: Applies the media source ID and the transcode retry flag to a postData object. Live TV sends no mediaSourceId. On the first attempt, direct play is not disabled so the server can evaluate compatibility (matching web client behaviour). On the retry after a failed direct play, forceTranscoding=true sets EnableDirectPlay=false, live or not: a server that allowed direct play would otherwise answer the retry with the same "yes" and no transcode URL.
| Name | Type | Description |
|---|---|---|
postData | object | The request body assoc array to modify |
mediaSourceId | string | Media source ID, or "" for live TV |
forceTranscoding | boolean | True when retrying with forced transcoding |
- Source
- Type:
- void
(static) buildHomeNextUpParams(serverVersion, enableRewatching, maxDays, nowSeconds) → {object}
buildHomeNextUpParams: Query parameters for the Home Next Up row.
On 10.7–10.10, a user with no watch history inside the cutoff gets the first episode of every series (one per series, not a short list). DisableFirstEpisode=true drops those, but on 10.8–10.10 it also makes the server ignore NextUpDateCutoff. So it is sent only where it costs nothing: always on 10.7 (which has no cutoff), and on 10.8–10.10 only when Max Days is off. With Max Days on, those servers keep the cutoff and still add first episodes. From 10.11 the parameter does nothing, and the server adds the first episode of every series with an episode started but none finished. Wherever the parameter is not sent, LoadItemsTask drops those itself (nextUpNeedsStartedFilter), so every version shows the same row and a user with no finished episode gets no Next Up row. That is intended, and differs from jellyfin-web, which shows those first episodes.
| Name | Type | Description |
|---|---|---|
serverVersion | string | Server version string, for example "10.10.7" |
enableRewatching | boolean | uiDetailsEnableRewatchingNextUp |
maxDays | dynamic | uiDetailsMaxDaysNextUp; 0 or invalid means off |
nowSeconds | integer | Current time as epoch seconds, for the cutoff |
- Source
- Params for BuildGetNextUpRequest
- Type:
- object
(static) buildPlaybackInfoPostData(mediaSourceIdopt, audioTrackIndexopt, subtitleTrackIndexopt, startTimeTicksopt, videoMetadataopt, bypassDoviPreservationopt, forceTranscodingopt) → {object}
buildPlaybackInfoPostData: The PlaybackInfo request body, tuned to the version being played.
Split from ItemPostPlaybackInfo so the body can be tested without a server.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
mediaSourceId | string | <optional> | "" | |
audioTrackIndex | integer | <optional> | -1 | |
subtitleTrackIndex | integer | <optional> | SubtitleSelection.NONE | |
startTimeTicks | longinteger | <optional> | 0& | |
videoMetadata | dynamic | <optional> | invalid | |
bypassDoviPreservation | boolean | <optional> | false | |
forceTranscoding | boolean | <optional> | false |
- Source
the POST body for BuildPostPlaybackInfoRequest
- Type:
- object
(static) classifyNextUpSeries(seriesItems) → {object}
classifyNextUpSeries: Whether each Next Up series has a watched regular episode.
From 10.11 the server offers a series' first episode once ANY of its episodes was started, even with none finished: jellyfin/jellyfin#13687 dropped the filter that 10.10 applied with DisableFirstEpisode (#973). The rule that filter applied is hasWatchedRegularEpisode()'s, and this decides it from batched lookups instead of one request per series.
It reads the series' own counts (Fields=RecursiveItemCount): nothing played means NOT_STARTED, anything played means STARTED. Both counts skip folders and missing episodes, so they are equal exactly when nothing is played. The counts include specials, which is why planNextUpSeriesLookups() sends a series with a played special to its own exact check instead. When the specials lookup got no answer, a series whose only played episode is a special counts as STARTED: an unanswered lookup never removes an episode from the row.
A series missing from the lookup, or without its counts, is left out.
| Name | Type | Description |
|---|---|---|
seriesItems | object | Series lookup items: [BaseItemDto] |
- Source
- AA of SeriesId -> NextUpSeriesStart value
- Type:
- object
(static) doviRemuxContainerProfile(mediaStreams, container, preserveDovi, bypass, apiVersion, mockCapabilitiesopt) → {dynamic}
doviRemuxContainerProfile: The container profile that forces a remux of Dolby Vision video in an mkv file, or invalid.
DOVI is not supported in the MKV container, so a remux (container swap) is forced for it. The profile tells the server that mkv is only acceptable when VideoRangeType differs from the stream's own value.
Hardware is read only after the cheap checks pass: the setting must be on and the caller must not have bypassed it. Only the first video stream with a codec other than AV1 is considered.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
mediaStreams | dynamic | MediaStream array of the played source, or invalid | ||
container | dynamic | the played source's container, or invalid | ||
preserveDovi | dynamic | the playbackPreserveDovi user setting, or invalid | ||
bypass | boolean | true when retrying after a buffer overflow, to allow direct play | ||
apiVersion | integer | the server's API tier (VideoRangeType needs tier 2) | ||
mockCapabilities | dynamic | <optional> | invalid | capabilities AA with isMock = true, for tests |
- Source
the container profile AA to add to ContainerProfiles, or invalid
- Type:
- dynamic
(static) foldNextUpLookup(found, entry, res) → {void}
foldNextUpLookup: Adds one nextUpLookupQueries() answer to the tally.
Series counts collect in seriesItems for classifyNextUpSeries(). A check decides its series in starts directly. A lookup with no answer, an error, or a body that is not a list only adds to unanswered, so its series stay undecided and keep their items.
| Name | Type | Description |
|---|---|---|
found | object | newNextUpLookups() tally, updated in place |
entry | object | The nextUpLookupQueries() entry the answer belongs to |
res | dynamic | The pool response AA, or invalid when it never answered |
- Source
- Type:
- void
(static) hasWatchedRegularEpisode(playedEpisodes) → {boolean}
hasWatchedRegularEpisode: Checks whether a series has a watched episode that is not a special.
Mirrors Jellyfin's own "last watched" rule for Next Up (played, ParentIndexNumber <> 0 or null), which is what decides whether a series counts as started. The client needs its own copy because Next Up's disableFirstEpisode param, which used to apply that rule for us, is ignored from Jellyfin 10.11 and removed in 12.0 (#925).
The REST API has no "not equals" filter, so the caller fetches watchedRegularEpisodeQuery(): played episodes sorted ParentIndexNumber,IndexNumber descending with Limit 1. Specials (season 0) sort below every regular season, so a special on top means no regular episode was watched.
| Name | Type | Description |
|---|---|---|
playedEpisodes | dynamic | Items query result: { Items: [BaseItemDto] } or invalid |
- Source
- true if the top played episode is not a special
- Type:
- boolean
(static) honorsDisableFirstEpisode(serverVersion) → {boolean}
honorsDisableFirstEpisode: Whether a server acts on Next Up's DisableFirstEpisode parameter.
Honored on 10.7–10.10. From 10.11 the server ignores it (#925), and 12.0 removes it. Send the parameter only where this returns true: it is registered as a version-gated parameter in docs/dev/jellyfin-endpoint-availability.yml, and lint:endpoint-availability fails a file that sends it without calling this.
| Name | Type | Description |
|---|---|---|
serverVersion | string | Server version string, for example "10.10.7" |
- Source
- true below 10.11.0
- Type:
- boolean
(static) inheritSeriesOriginalLanguage(item) → {void}
inheritSeriesOriginalLanguage: Give an episode its series' OriginalLanguage when track selection needs it (needsSeriesOriginalLanguage()), as the server does for its own pick. One extra request, made only for a viewer whose audio preference is "Original language".
| Name | Type | Description |
|---|---|---|
item | dynamic | JellyfinBaseItem from ItemMetaData() |
- Source
- Type:
- void
(static) keepStartedSeriesItems(items, starts) → {object}
keepStartedSeriesItems: Drops the Next Up items whose series is NOT_STARTED, keeping order.
| Name | Type | Description |
|---|---|---|
items | object | Next Up items: [BaseItemDto] |
starts | object | AA of SeriesId -> NextUpSeriesStart |
- Source
- The kept items
- Type:
- object
(static) newNextUpLookups() → {object}
newNextUpLookups: An empty tally for foldNextUpLookup().
- Source
- { seriesItems: [BaseItemDto], starts: AA of SeriesId -> NextUpSeriesStart, unanswered: integer }
- Type:
- object
(static) nextUpLookupQueries(plan) → {object}
nextUpLookupQueries: The lookups that decide the series in a plan, as pipeline entries.
The counted series go out apiIds.PER_REQUEST to a request, so a long Next Up row cannot push a request line past what a server or proxy accepts. Each exact series gets its own watchedRegularEpisodeQuery(). Each entry carries query for BuildGetItemsByQueryRequest, and lookup (with seriesId for a check) for foldNextUpLookup().
| Name | Type | Description |
|---|---|---|
plan | object | planNextUpSeriesLookups() result |
- Source
- Array of { requestId, query, lookup, seriesId? }
- Type:
- object
(static) nextUpNeedsStartedFilter(params) → {boolean}
nextUpNeedsStartedFilter: Whether Home's Next Up row must drop unstarted series itself.
True unless the request asks the server to drop them, so only servers that leave them in pay for the client's lookups (LoadItemsTask.keepStartedSeries). A server-side filter Jellyfin adds later is a version-gated parameter that buildHomeNextUpParams sends, and is recognized here next to DisableFirstEpisode.
| Name | Type | Description |
|---|---|---|
params | object | buildHomeNextUpParams() result |
- Source
- true when the client has to filter
- Type:
- boolean
(static) nextUpSeriesIds(items) → {object}
nextUpSeriesIds: The series behind a Next Up response's items, each once, in response order.
| Name | Type | Description |
|---|---|---|
items | dynamic | Next Up items: [BaseItemDto] or invalid |
- Source
- Array of SeriesId strings
- Type:
- object
(static) optimizeAudioCodecListForSource(deviceProfile, channelCount, preferredMultichannelCodecopt) → {void}
Tailors a video transcoding profile's AudioCodec list to the current source's channel count so the server (and downstream HLS variant selection) can't fall back to a less-desirable codec.
Multichannel source (>2ch): Strips ALL stereo-output codecs (aac, mp3, flac, alac, pcm, lpcm, wav, vorbis). Without this, Jellyfin's HLS muxer offers BOTH the surround codec AND a stereo fallback as separate variants in the master playlist, and Roku's HLS player has been observed (via in-house testing on physical hardware; no upstream tracking issue at time of writing) to pick the stereo variant, defeating the entire point of having surround passthrough hardware. Caller must already have verified the device has surround passthrough before invoking with channelCount > 2.
Stereo source (≤2ch): Strips surround passthrough codecs (eac3, ac3, dts) plus aac so transcoding falls through to mp3. Avoids handing the server a surround target codec for content that's only 2ch anyway. If filtering empties a previously non-empty list, falls back to "mp3" (the intended target).
Multichannel surround target (issue #573): For a >2ch source, the stripped list must lead with a server-encodeable surround codec. Two failure modes this prevents, both observed on Jellyfin 10.11 via PlaybackInfo probes:
- Empty list: Jellyfin's StreamBuilder omits the audioCodec query param, the server's InferAudioCodec falls through to the container name ("m3u8"), ffmpeg gets
-codec:a:0 m3u8and exits 8. Happens when passthrough is detected only via codecs not in surroundPriority (truehd/dtshd-only) so no surround codec is in the list. - On-device-decode leak: a list with no surround codec but an on-device-decode one like opus resolves server-side to opus, silently abandoning the user's surround/passthrough intent for a decoded stereo-ish path. Fix: prepend the user's preferred multichannel codec (playbackPreferredMultichannelCodec), clamped to a reliably-encodeable HLS surround target, eac3 or ac3 (dts is excluded: the server emits no audio stream for a dts transcode target). This is a no-op for healthy profiles (their stripped list already leads with eac3/ac3) and only rescues the degenerate truehd/dtshd-only shape.
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
deviceProfile | object | |||
channelCount | integer | |||
preferredMultichannelCodec | string | <optional> | "eac3" |
- Source
- Type:
- void
(static) planNextUpSeriesLookups(seriesIds, playedSpecials) → {object}
planNextUpSeriesLookups: Splits Next Up's series between the two ways of deciding them.
A series with a played special goes to the exact per-series check (hasWatchedRegularEpisode), because its counts include that special. Every other series is decided by the batched count lookup (classifyNextUpSeries). With no answer for the specials, every series is counted.
| Name | Type | Description |
|---|---|---|
seriesIds | object | nextUpSeriesIds() result |
playedSpecials | dynamic | playedSpecialsQuery() items: [BaseItemDto] or invalid |
- Source
- { counted: [SeriesId], exact: [SeriesId] }
- Type:
- object
(static) playedSpecialsQuery() → {object}
playedSpecialsQuery: Items query params for every played special (season 0) in the library.
Next Up's started-series filter reads it (planNextUpSeriesLookups). It does not depend on the Next Up response, so it can be sent alongside it.
- Source
- Params for BuildGetItemsByQueryRequest
- Type:
- object
(static) resolveMultichannelSurroundTarget(preferredMultichannelCodec) → {string}
Resolve the surround transcode target for a multichannel source from the user's preferred multichannel codec setting (playbackPreferredMultichannelCodec). Clamped to the reliably- encodeable HLS surround targets: eac3 (default) and ac3. dts is intentionally excluded: the Jellyfin server emits no audio stream for a dts transcode target (verified on 10.11), so a dts fallback would itself re-trigger the issue #573 failure. Both eac3 and ac3 are valid HLS audio targets in every video transcoding container (ts and mp4), so no per-container clamp is needed.
| Name | Type | Description |
|---|---|---|
preferredMultichannelCodec | string |
- Source
- Type:
- string
(static) supportsLyrics() → {boolean}
supportsLyrics: Checks if the connected Jellyfin server supports the Lyrics API.
The /Audio/{itemId}/Lyrics endpoint was introduced in Jellyfin 10.9.0. Servers below 10.9.0 do not have this endpoint and will return 404. Guarding the request mirrors supportsMediaSegments() (source/utils/mediaSegments.bs) and lets the endpoint-availability ledger record this as a validated version-guard.
- Source
- true if server supports lyrics
- Type:
- boolean
(static) useTranscodeAudioStream(playbackInfo) → {dynamic}
| Name | Type | Description |
|---|---|---|
playbackInfo | dynamic |
- Source
- Type:
- dynamic
(static) watchedRegularEpisodeQuery(seriesId) → {object}
watchedRegularEpisodeQuery: Items query params whose result hasWatchedRegularEpisode() reads.
| Name | Type | Description |
|---|---|---|
seriesId | string | The series to check |
- Source
- Params for BuildGetItemsByQueryRequest
- Type:
- object