source_utils_quickplay.bs
import "pkg:/source/utils/nodeHelpers.bs"
import "pkg:/source/utils/streamSelection.bs"
' Render-thread-safe Quick Play helpers.
' API-calling quickplay logic lives in QuickPlayTask (components/tasks/QuickPlayTask.bs).
namespace quickplay
' Takes an array of items and adds to global queue.
' Also shuffles the playlist if asked
sub pushToQueue(queueArray as object, shufflePlay = false as boolean)
if isValidAndNotEmpty(queueArray)
for each item in queueArray
m.global.queueManager.callFunc("push", nodeHelpers.createQueueItem(item))
end for
' shuffle the playlist if asked
if shufflePlay and m.global.queueManager.callFunc("getCount") > 1
m.global.queueManager.callFunc("toggleShuffle")
end if
end if
end sub
' A single video file.
sub video(itemNode as object)
if not isValid(itemNode) or not isValid(itemNode.id) or itemNode.id = "" then return
' Create a queue-specific item to avoid modifying the UI node
' This prevents the quickPlayNode field observer from firing twice
queueItem = nodeHelpers.createQueueItem(itemNode)
if not isValid(queueItem) then return
' Select best video source for device capabilities
' When multiple sources exist, set mediaSourceId so LoadVideoContentTask uses the
' preferred source without overwriting the base item ID needed for metadata/reporting.
audioStreams = itemNode.audioStreams
if isValid(itemNode.mediaSourcesData) and isValidAndNotEmpty(itemNode.mediaSourcesData.mediaSources)
mediaSources = itemNode.mediaSourcesData.mediaSources
if mediaSources.Count() > 1
bestSourceIndex = findBestVideoSource(mediaSources)
bestSource = mediaSources[bestSourceIndex]
if isValidAndNotEmpty(bestSource.Id)
queueItem.mediaSourceId = bestSource.Id
end if
' Use the selected source's audio streams for best audio selection
if isValid(bestSource.MediaStreams)
audioStreams = []
for each stream in bestSource.MediaStreams
if isValid(stream.Type) and LCase(stream.Type) = "audio"
audioStreams.push(stream)
end if
end for
end if
end if
end if
' Get user session for audio selection
localUser = m.global.user
' audioStreams is pre-filtered to audio-only by the transformer (or re-filtered above).
' findBestAudioStreamIndex filters by Type="audio" internally, so passing
' pre-filtered audio streams works correctly.
audioStreamIndex = 0
if isValidAndNotEmpty(audioStreams)
playDefault = resolvePlayDefaultAudioTrack(localUser.settings, localUser.config)
audioStreamIndex = findBestAudioStreamIndex(audioStreams, playDefault, resolveAudioLanguagePreference(localUser.settings, localUser.config))
end if
' Resume position from typed field; startingPoint is computed here, not stored on node
playbackPosition = itemNode.playbackPositionTicks
queueItem.selectedAudioStreamIndex = audioStreamIndex
queueItem.startingPoint = playbackPosition
m.global.queueManager.callFunc("push", queueItem)
end sub
' A single audio file.
sub audio(itemNode as object)
if not isValid(itemNode) or not isValid(itemNode.id) then return
' Create a queue-specific item to avoid modifying the UI node
queueItem = nodeHelpers.createQueueItem(itemNode)
if not isValid(queueItem) then return
m.global.queueManager.callFunc("push", queueItem)
end sub
' A single music video file.
sub musicVideo(itemNode as object)
if not isValid(itemNode) or not isValidAndNotEmpty(itemNode.id) then return
' Create a queue-specific item to avoid modifying the UI node
queueItem = nodeHelpers.createQueueItem(itemNode)
if not isValid(queueItem) then return
m.global.queueManager.callFunc("push", queueItem)
end sub
' A single photo.
sub photo(itemNode as object)
if not isValid(itemNode) or not isValid(itemNode.id) then return
photoPlayer = CreateObject("roSgNode", "PhotoDetails")
photoPlayer.itemsNode = itemNode
photoPlayer.itemIndex = 0
m.global.sceneManager.callfunc("pushScene", photoPlayer)
end sub
' Quick Play A TVChannel
sub tvChannel(itemNode as object)
if not isValid(itemNode) or not isValidAndNotEmpty(itemNode.id)
print "ERROR: quickplay.tvChannel() - missing itemNode or id"
stopLoadingSpinner()
return
end if
' Push TV channel queue item — keep spinner active until video content loads
m.global.queueManager.callFunc("push", nodeHelpers.createQueueItem(itemNode))
end sub
' Quick Play A Live Program
sub program(itemNode as object)
if not isValid(itemNode) or not isValidAndNotEmpty(itemNode.channelId)
print "ERROR: quickplay.program() - missing ChannelId"
stopLoadingSpinner()
return
end if
' Play the channel this program is on, not the program itself.
' Override id and type on the queue item so the playback pipeline targets the channel.
' Keep spinner active until video content loads.
queueItem = nodeHelpers.createQueueItem(itemNode)
queueItem.id = itemNode.channelId
queueItem.type = "TvChannel"
m.global.queueManager.callFunc("push", queueItem)
end sub
end namespace