Update API docs

This commit is contained in:
jellyfin-bot 2024-01-06 01:31:17 +00:00
parent 48c19eda75
commit 9e5bdd4979
12 changed files with 282 additions and 32 deletions

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,11 @@ import "pkg:/source/api/Image.bs"
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"
@ -46,19 +51,18 @@ sub loadItems()
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
@ -67,9 +71,10 @@ function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic,
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"
@ -79,6 +84,21 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
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
@ -109,16 +129,41 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
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
@ -132,8 +177,6 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
m.playbackInfo = meta.json
end if
addSubtitlesToVideo(video, meta)
if meta.live
video.transcodeParams = {
"MediaSourceId": m.playbackInfo.MediaSources[0].Id,
@ -185,13 +228,106 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
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"

View File

@ -142,14 +142,12 @@ sub loadInitialItems()
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

View File

@ -113,19 +113,20 @@ sub processSubtitleSelection()
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

View File

@ -95,6 +95,8 @@ function onKeyEvent(key as string, press as boolean) as boolean
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

View File

@ -258,6 +258,9 @@ end sub
' 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&)
@ -334,6 +337,29 @@ sub onVideoContentLoaded()
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
@ -581,6 +607,25 @@ function stateAllowsOSD() as boolean
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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -813,7 +813,7 @@ function CreateSeasonDetailsGroupByID(seriesID as string, seasonID as string) as
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()

View File

@ -73,11 +73,13 @@ sub runRegistryUserMigrations()
' 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}`