Methods

(static) formatAudioChannels(channels) → {string}

formatAudioChannels: Convert channel count integer to display format Ignores ChannelLayout field since it can return inconsistent strings (for example "stereo")

Parameters:
NameTypeDescription
channelsinteger

Number of audio channels

Returns:
  • Channel layout string (for example "2.0", "5.1", "7.1") or "" if invalid/zero
Type: 
string

(static) formatAudioDisplayTitle(stream) → {string}

formatAudioDisplayTitle: Build a display title for an audio stream Format: "Language CODEC CHANNELS" or "Language CODEC CHANNELS (Default)"

Parameters:
NameTypeDescription
streamobject

Audio MediaStream object from Jellyfin API

Returns:
  • Formatted display title (for example "English AAC 2.0 (Default)") or "N/A" if insufficient data
Type: 
string

(static) formatSubtitleDisplayTitle(stream, cacheopt) → {string}

formatSubtitleDisplayTitle: Build a display title for a subtitle stream Format: "Language CODEC", optionally followed by a parenthesized flag list: "English SUBRIP (Hearing impaired)", "English SUBRIP (Hearing impaired, Forced)". The language is omitted for "und"/Undefined. The flags matter: the panel badges hearing-impaired, so without it the dropdown and the panel described the same track differently.

Parameters:
NameTypeAttributesDefaultDescription
streamobject

Subtitle MediaStream object from Jellyfin API

cacheobject<optional>
invalid

translateCached() batch cache, for a caller labeling many tracks

Returns:
  • Formatted display title (for example "English SUBRIP (Forced)") or "N/A" if insufficient data
Type: 
string

(static) formatSubtitleTrackLabel(stream, markExternalopt, cacheopt) → {string}

formatSubtitleTrackLabel: The label a subtitle list shows for one track. The details-screen dropdown and the playback picker both use it, so the same track reads the same on both. It was two paths once, and the picker's (the server's DisplayTitle verbatim) led with "Undefined" for a track with no language.

A track's own Title leads when it has one, because it is often the only thing telling two tracks apart: "Spanish (Latin America)" and "Spanish (Spain)" are both "Spanish SUBRIP" by language and codec, as are a "Signs" track and a full one. This is the server's own DisplayTitle rule, minus its "Undefined" placeholder: the Title, then each part it does not already say. A Title that names the language stands in for it, so the codec follows with a space ("English (SDH) SUBRIP"); otherwise " · " separates the two ("SDH · English SUBRIP (Hearing impaired)").

A file kept outside the video gets a marker. "External" is the word Jellyfin and the playback report use for it, and it covers a download and a file placed by hand alike. When there is no Title, language or codec to build from, the server's DisplayTitle says more than "N/A".

Parameters:
NameTypeAttributesDefaultDescription
streamobject

Subtitle MediaStream object from Jellyfin API

markExternalboolean<optional>
true

false for a slot that shows the track alone, without the entries the marker distinguishes it from

cacheobject<optional>
invalid

translateCached() batch cache, for a caller labeling many tracks

Returns:
  • for example "English SUBRIP", "SAMI · External", "Spanish (Latin America) SUBRIP"; "N/A" if there is nothing to describe it by
Type: 
string

(static) formatVideoDisplayTitle(stream) → {string}

formatVideoDisplayTitle: Build a display title for a video stream Format: "RESOLUTION CODEC" or "RESOLUTION CODEC RANGETYPE" (when HDR)

Parameters:
NameTypeDescription
streamobject

Video MediaStream object from Jellyfin API

Returns:
  • Formatted display title (for example "4K HEVC HDR10") or "N/A" if insufficient data
Type: 
string

(static) formatVideoRangeLabel(stream) → {string}

formatVideoRangeLabel: The dynamic-range label for a video stream.

Extracted from formatVideoDisplayTitle so the playback-info report can name the same range the track pickers do, rather than growing a second copy of the Dolby Vision profile/compatibility formatting.

Callers differ in one way, and this function leaves that choice to them on purpose: formatVideoDisplayTitle only asks for a label when VideoRange is "HDR", because "1080p H264 SDR" is noise in a picker row. The report asks unconditionally, because "SDR" is exactly what it needs to render on the target side of a tone-mapping transcode.

VideoRangeType is a 10.8+ field, so on the floor server this falls back to the coarse VideoRange ("SDR" / "HDR") that has existed throughout.

Parameters:
NameTypeDescription
streamobject

Video MediaStream object from Jellyfin API

Returns:
  • for example "DV 8.1", "HDR10+", "HLG", "SDR", or "" with nothing to go on
Type: 
string

(static) getVideoResolutionLabel(width, height, isInterlaced) → {string}

getVideoResolutionLabel: Determine resolution label from video dimensions Resolution thresholds check width OR height (either can qualify) 4K never gets p/i suffix. All other resolutions get "p" or "i" based on interlacing.

Parameters:
NameTypeDescription
widthinteger

Video width in pixels

heightinteger

Video height in pixels

isInterlacedboolean

Whether the video is interlaced

Returns:
  • Resolution label (for example "4K", "1080p", "720i") or "" if below all thresholds
Type: 
string

(static) joinSubtitleLabelParts(language, codec, flags) → {string}

joinSubtitleLabelParts: "Language CODEC (flag, flag)", leaving out whatever is empty. "" when there is no language and no codec, whatever the flags: a flag alone does not say which track it is.

Parameters:
NameTypeDescription
languagestring
codecstring
flagsobject
Returns:
Type: 
string

(static) resolveLanguageName(langCode, cacheopt) → {string}

resolveLanguageName: Convert a media stream language code to a localized display name.

MediaStream.Language passes through whatever the container metadata holds: ffmpeg/Jellyfin do not normalize, so real-world inputs include ISO 639-2/T ("fra"), 639-2/B ("fre"), 639-1 ("fr"), and BCP-47 tags ("fr-FR", "pt_BR").

Three-tier resolution chain:

  1. Lowercase + strip after first "-" or "_" (drop region/script suffix)
  2. "und" / "zxx" give "": caller omits the language label
  3. Alias map: normalize 3-letter / deprecated codes to a base form
  4. Tier 1: translationKey lookup, then translate(): localized to user's UI
  5. Tier 2: English-name fallback: covers every other ISO 639-2 code
  6. Tier 3: raw code passthrough: last-resort, preserves info

"und" (Undefined) and "zxx" (No linguistic content: instrumental music, ambient sound, foley) are both omitted: rendering "No linguistic content EAC3 5.1" as a track label is noisier than plain "EAC3 5.1". The other ISO 639-2 special codes ("mul" Multiple, "mis" Uncoded) ARE displayed because they convey real information when they appear.

Parameters:
NameTypeAttributesDefaultDescription
langCodestring

Media stream language code from any common format

cacheobject<optional>
invalid

translateCached() batch cache

Returns:
  • Localized name, English fallback, "" for und/zxx, or raw code
Type: 
string

(static) subtitleLabelParts(stream, cacheopt) → {object}

subtitleLabelParts: What a subtitle stream says about itself, as the pieces its labels are built from: the full language name ("" for none, "und" or "zxx"), the codec uppercased ("" for none), and the flags in display order. Hearing-impaired leads because it changes what the track IS rather than when it plays; Forced takes precedence over Default if both are set.

Parameters:
NameTypeAttributesDefaultDescription
streamobject

Subtitle MediaStream object from Jellyfin API

cacheobject<optional>
invalid

translateCached() batch cache, for a caller labeling many tracks

Returns:
  • { language as string, codec as string, flags as roArray of string }
Type: 
object