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