Skip to content

Commit

Permalink
Update API docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jellyfin-bot committed Jan 6, 2024
1 parent 48c19ed commit 9e5bdd4
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 32 deletions.
78 changes: 72 additions & 6 deletions docs/api/components_Clock.bs.html

Large diffs are not rendered by default.

162 changes: 149 additions & 13 deletions docs/api/components_ItemGrid_LoadVideoContentTask.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
import "pkg:/source/api/userauth.bs"
import "pkg:/source/utils/deviceCapabilities.bs"

enum SubtitleSelection
notset = -2
none = -1
end enum

sub init()
m.user = AboutMe()
m.top.functionName = "loadItems"
Expand Down Expand Up @@ -46,19 +51,18 @@
id = m.top.itemId
mediaSourceId = invalid
audio_stream_idx = m.top.selectedAudioStreamIndex
subtitle_idx = m.top.selectedSubtitleIndex
forceTranscoding = false

m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding)]
m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, forceTranscoding)]
end sub

function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean) as dynamic
function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean) as dynamic

video = {}
video.id = id
video.content = createObject("RoSGNode", "ContentNode")

LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding)
LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, forceTranscoding)

if video.content = invalid
return invalid
Expand All @@ -67,9 +71,10 @@
return video
end function

sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean)
sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean)

meta = ItemMetaData(video.id)
subtitle_idx = m.top.selectedSubtitleIndex

if not isValid(meta)
video.errorMsg = "Error loading metadata"
Expand All @@ -79,6 +84,21 @@

videotype = LCase(meta.type)

' Check for any Live TV streams coming from other places other than the TV Guide
if isValid(meta.json) and isValid(meta.json.ChannelId)
if isValid(meta.json.EpisodeTitle)
meta.title = meta.json.EpisodeTitle
else if isValid(meta.json.Name)
meta.title = meta.json.Name
end if
meta.live = true
if LCase(meta.json.type) = "program"
video.id = meta.json.ChannelId
else
video.id = meta.json.id
end if
end if

if videotype = "episode" or videotype = "series"
video.content.contenttype = "episode"
end if
Expand Down Expand Up @@ -109,16 +129,41 @@
if meta.live then mediaSourceId = ""

m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
video.videoId = video.id
video.mediaSourceId = mediaSourceId
video.audioIndex = audio_stream_idx

if not isValid(m.playbackInfo)
video.errorMsg = "Error loading playback info"
video.content = invalid
return
end if

addSubtitlesToVideo(video, meta)

' Enable default subtitle track
if subtitle_idx = SubtitleSelection.notset
defaultSubtitleIndex = defaultSubtitleTrackFromVid(video.id)

if defaultSubtitleIndex <> SubtitleSelection.none
video.SelectedSubtitle = defaultSubtitleIndex
subtitle_idx = defaultSubtitleIndex

m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
if not isValid(m.playbackInfo)
video.errorMsg = "Error loading playback info"
video.content = invalid
return
end if

addSubtitlesToVideo(video, meta)
else
video.SelectedSubtitle = subtitle_idx
end if
else
video.SelectedSubtitle = subtitle_idx
end if

video.videoId = video.id
video.mediaSourceId = mediaSourceId
video.audioIndex = audio_stream_idx

video.PlaySessionId = m.playbackInfo.PlaySessionId

if meta.live
Expand All @@ -132,8 +177,6 @@
m.playbackInfo = meta.json
end if

addSubtitlesToVideo(video, meta)

if meta.live
video.transcodeParams = {
"MediaSourceId": m.playbackInfo.MediaSources[0].Id,
Expand Down Expand Up @@ -185,13 +228,106 @@
setCertificateAuthority(video.content)
video.audioTrack = (audio_stream_idx + 1).ToStr() ' Roku's track indexes count from 1. Our index is zero based

video.SelectedSubtitle = subtitle_idx

if not fully_external
video.content = authRequest(video.content)
end if
end sub

' defaultSubtitleTrackFromVid: Identifies the default subtitle track given video id
'
' @param {dynamic} videoID - id of video user is playing
' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found
function defaultSubtitleTrackFromVid(videoID) as integer
if m.global.session.user.configuration.SubtitleMode = "None"
return SubtitleSelection.none ' No subtitles desired: return none
end if

meta = ItemMetaData(videoID)

if not isValid(meta) then return SubtitleSelection.none
if not isValid(meta.json) then return SubtitleSelection.none
if not isValidAndNotEmpty(meta.json.mediaSources) then return SubtitleSelection.none
if not isValidAndNotEmpty(meta.json.MediaSources[0].MediaStreams) then return SubtitleSelection.none

subtitles = sortSubtitles(meta.id, meta.json.MediaSources[0].MediaStreams)
selectedAudioLanguage = meta.json.MediaSources[0].MediaStreams[m.top.selectedAudioStreamIndex].Language ?? ""

defaultTextSubs = defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage, true) ' Find correct subtitle track (forced text)
if defaultTextSubs <> SubtitleSelection.none
return defaultTextSubs
end if

if not m.global.session.user.settings["playback.subs.onlytext"]
return defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage) ' if no appropriate text subs exist, allow non-text
end if

return SubtitleSelection.none
end function

' defaultSubtitleTrack:
'
' @param {dynamic} sortedSubtitles - array of subtitles sorted by type and language
' @param {string} selectedAudioLanguage - language for selected audio track
' @param {boolean} [requireText=false] - indicates if only text subtitles should be considered
' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found
function defaultSubtitleTrack(sortedSubtitles, selectedAudioLanguage as string, requireText = false as boolean) as integer
userConfig = m.global.session.user.configuration

subtitleMode = isValid(userConfig.SubtitleMode) ? LCase(userConfig.SubtitleMode) : ""

allowSmartMode = false

' Only evaluate selected audio language if we have a value
if selectedAudioLanguage <> ""
allowSmartMode = selectedAudioLanguage <> userConfig.SubtitleLanguagePreference
end if

for each item in sortedSubtitles
' Only auto-select subtitle if language matches SubtitleLanguagePreference
languageMatch = true
if userConfig.SubtitleLanguagePreference <> ""
languageMatch = (userConfig.SubtitleLanguagePreference = item.Track.Language)
end if

' Ensure textuality of subtitle matches preferenced passed as arg
matchTextReq = ((requireText and item.IsTextSubtitleStream) or not requireText)

if languageMatch and matchTextReq
if subtitleMode = "default" and (item.isForced or item.IsDefault)
' Return first forced or default subtitle track
return item.Index
else if subtitleMode = "always"
' Return the first found subtitle track
return item.Index
else if subtitleMode = "onlyforced" and item.IsForced
' Return first forced subtitle track
return item.Index
else if subtitleMode = "smart" and allowSmartMode
' Return the first found subtitle track
return item.Index
end if
end if
end for

' User has chosed smart subtitle mode
' We already attempted to load subtitles in preferred language, but none were found.
' Fall back to default behaviour while ignoring preferredlanguage
if subtitleMode = "smart" and allowSmartMode
for each item in sortedSubtitles
' Ensure textuality of subtitle matches preferenced passed as arg
matchTextReq = ((requireText and item.IsTextSubtitleStream) or not requireText)
if matchTextReq
if item.isForced or item.IsDefault
' Return first forced or default subtitle track
return item.Index
end if
end if
end for
end if

return SubtitleSelection.none ' Keep current default behavior of "None", if no correct subtitle is identified
end function

sub addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external)
protocol = LCase(m.playbackInfo.MediaSources[0].Protocol)
if protocol <> "file"
Expand Down
2 changes: 0 additions & 2 deletions docs/api/components_ItemGrid_MusicLibraryView.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,12 @@
m.loadItemsTask.itemId = m.top.parentItem.parentFolder
else if LCase(m.view) = "artistspresentation" or LCase(m.options.view) = "artistspresentation"
m.loadItemsTask.genreIds = ""
m.top.showItemTitles = "hidealways"
else if LCase(m.view) = "artistsgrid" or LCase(m.options.view) = "artistsgrid"
m.loadItemsTask.genreIds = ""
else if LCase(m.view) = "albumartistsgrid" or LCase(m.options.view) = "albumartistsgrid"
m.loadItemsTask.genreIds = ""
else if LCase(m.view) = "albumartistspresentation" or LCase(m.options.view) = "albumartistspresentation"
m.loadItemsTask.genreIds = ""
m.top.showItemTitles = "hidealways"
else
m.loadItemsTask.itemId = m.top.parentItem.Id
end if
Expand Down
9 changes: 5 additions & 4 deletions docs/api/components_manager_ViewCreator.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,20 @@
end if

if m.selectedSubtitle.IsEncoded
' Roku can not natively display these subtitles, so turn off the caption mode on the device
m.view.globalCaptionMode = "Off"
else
' Roku can natively display these subtitles, ensure the caption mode on the device is on
m.view.globalCaptionMode = "On"
end if

if m.selectedSubtitle.IsExternal
' Roku may rearrange subtitle tracks. Look up track based on name to ensure we get the correct index
availableSubtitleTrackIndex = availSubtitleTrackIdx(m.selectedSubtitle.Track.TrackName)
if availableSubtitleTrackIndex = -1 then return

m.view.subtitleTrack = m.view.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName
else
m.view.selectedSubtitle = m.selectedSubtitle.Index
end if

m.view.selectedSubtitle = m.selectedSubtitle.Index
end sub

' User requested playback info
Expand Down
2 changes: 2 additions & 0 deletions docs/api/components_tvshows_TVEpisodes.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@
focusedItem = getFocusedItem()
if isValid(focusedItem)
m.top.selectedItem = focusedItem
'Prevent the selected item event from double firing
m.top.selectedItem = invalid
end if
return true
end if
Expand Down
45 changes: 45 additions & 0 deletions docs/api/components_video_VideoPlayerView.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@

' Event handler for when selectedSubtitle changes
sub onSubtitleChange()
' If the global caption mode is on, that means Roku can display the subtitles natively and doesn't need a video stop/start
if LCase(m.top.globalCaptionMode) = "on" then return

' Save the current video position
m.global.queueManager.callFunc("setTopStartingPoint", int(m.top.position) * 10000000&)

Expand Down Expand Up @@ -334,6 +337,29 @@
m.top.allowCaptions = true
end if

' Allow default subtitles
m.top.unobserveField("selectedSubtitle")

' Set subtitleTrack property is subs are natively supported by Roku
selectedSubtitle = invalid
for each subtitle in m.top.fullSubtitleData
if subtitle.Index = videoContent[0].selectedSubtitle
selectedSubtitle = subtitle
exit for
end if
end for

if isValid(selectedSubtitle)
availableSubtitleTrackIndex = availSubtitleTrackIdx(selectedSubtitle.Track.TrackName)
if availableSubtitleTrackIndex <> -1
m.top.subtitleTrack = m.top.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName
end if
end if

m.top.selectedSubtitle = videoContent[0].selectedSubtitle

m.top.observeField("selectedSubtitle", "onSubtitleChange")

if isValid(m.top.audioIndex)
m.top.audioTrack = (m.top.audioIndex + 1).toStr()
else
Expand Down Expand Up @@ -581,6 +607,25 @@
return inArray(validStates, m.top.state)
end function


' availSubtitleTrackIdx: Returns Roku's index for requested subtitle track
'
' @param {string} tracknameToFind - TrackName for subtitle we're looking to match
' @return {integer} indicating Roku's index for requested subtitle track. Returns -1 if not found
function availSubtitleTrackIdx(tracknameToFind as string) as integer
idx = 0
for each availTrack in m.top.availableSubtitleTracks
' The TrackName must contain the URL we supplied originally, though
' Roku mangles the name a bit, so we check if the URL is a substring, rather
' than strict equality
if Instr(1, availTrack.TrackName, tracknameToFind)
return idx
end if
idx = idx + 1
end for
return -1
end function

function onKeyEvent(key as string, press as boolean) as boolean

' Keypress handler while user is inside the chapter menu
Expand Down
2 changes: 1 addition & 1 deletion docs/api/data/search.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/api/module-Clock.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/api/module-LoadVideoContentTask.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/api/module-VideoPlayerView.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/api/source_ShowScenes.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@
group.objects = TVEpisodes(seriesID, seasonID)
group.episodeObjects = group.objects
' watch for button presses
group.observeField("episodeSelected", m.port)
group.observeField("selectedItem", m.port)
group.observeField("quickPlayNode", m.port)
' don't wait for the extras button
stopLoadingSpinner()
Expand Down
6 changes: 4 additions & 2 deletions docs/api/source_migrations.bs.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@
' app versions < 2.0.0 didn't save LastRunVersion at the user level
' fall back to using the apps lastRunVersion
lastRunVersion = m.global.app.lastRunVersion
registry_write("LastRunVersion", lastRunVersion, section)
if isValid(lastRunVersion)
registry_write("LastRunVersion", lastRunVersion, section)
end if
end if

' BASE_MIGRATION
if not versionChecker(lastRunVersion, CLIENT_VERSION_REQUIRING_BASE_MIGRATION)
if isValid(lastRunVersion) and not versionChecker(lastRunVersion, CLIENT_VERSION_REQUIRING_BASE_MIGRATION)
m.wasMigrated = true
print `Running Registry Migration for ${CLIENT_VERSION_REQUIRING_BASE_MIGRATION} for userid: ${section}`

Expand Down

0 comments on commit 9e5bdd4

Please sign in to comment.