components_manager_ViewCreator.bs

' Play Audio
sub CreateAudioPlayerView()
    m.view = CreateObject("roSGNode", "AudioPlayerView")
    m.view.observeField("state", "onStateChange")
    m.global.sceneManager.callFunc("pushScene", m.view)
end sub

' Play Video
sub CreateVideoPlayerView()
    m.playbackData = {}
    m.selectedSubtitle = {}

    m.view = CreateObject("roSGNode", "VideoPlayerView")
    m.view.observeField("state", "onStateChange")
    m.view.observeField("selectPlaybackInfoPressed", "onSelectPlaybackInfoPressed")
    m.view.observeField("selectSubtitlePressed", "onSelectSubtitlePressed")

    mediaSourceId = m.global.queueManager.callFunc("getCurrentItem").mediaSourceId

    if not isValid(mediaSourceId) or mediaSourceId = ""
        mediaSourceId = m.global.queueManager.callFunc("getCurrentItem").id
    end if

    m.getPlaybackInfoTask = createObject("roSGNode", "GetPlaybackInfoTask")
    m.getPlaybackInfoTask.videoID = mediaSourceId
    m.getPlaybackInfoTask.observeField("data", "onPlaybackInfoLoaded")

    m.global.sceneManager.callFunc("pushScene", m.view)
end sub

' -----------------
' Event Handlers
' -----------------

' User requested subtitle selection popup
sub onSelectSubtitlePressed()
    ' None is always first in the subtitle list
    subtitleData = {
        data: [{
            "Index": -1,
            "IsExternal": false,
            "Track": {
                "description": "None"
            },
            "Type": "subtitleselection"
        }]
    }

    for each item in m.view.fullSubtitleData
        item.type = "subtitleselection"

        if m.view.selectedSubtitle <> -1
            ' Subtitle is a track within the file
            if item.index = m.view.selectedSubtitle
                item.selected = true
            end if
        else
            ' Subtitle is from an external source
            availableSubtitleTrackIndex = availSubtitleTrackIdx(item.track.TrackName)
            if availableSubtitleTrackIndex <> -1

                ' Convert Jellyfin subtitle track name to Roku track name
                subtitleFullTrackName = m.view.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName

                if subtitleFullTrackName = m.view.subtitleTrack
                    item.selected = true
                end if

            end if
        end if

        subtitleData.data.push(item)
    end for

    m.global.sceneManager.callFunc("radioDialog", tr("Select Subtitles"), subtitleData)
    m.global.sceneManager.observeField("returnData", "onSelectionMade")
end sub

' User has selected something from the radioDialog popup
sub onSelectionMade()
    m.global.sceneManager.unobserveField("returnData")

    if not isValid(m.global.sceneManager.returnData) then return
    if not isValid(m.global.sceneManager.returnData.type) then return

    if LCase(m.global.sceneManager.returnData.type) = "subtitleselection"
        processSubtitleSelection()
    end if
end sub

sub processSubtitleSelection()
    m.selectedSubtitle = m.global.sceneManager.returnData

    ' The selected encoded subtitle did not change.
    if m.view.selectedSubtitle <> -1 or m.selectedSubtitle.index <> -1
        if m.view.selectedSubtitle = m.selectedSubtitle.index then return
    end if

    ' The playbackData is now outdated and must be refreshed
    m.playbackData = invalid

    if LCase(m.selectedSubtitle.track.description) = "none"
        m.view.globalCaptionMode = "Off"
        m.view.subtitleTrack = ""

        if m.view.selectedSubtitle <> -1
            m.view.selectedSubtitle = -1
        end if

        return
    end if

    if m.selectedSubtitle.IsEncoded
        m.view.globalCaptionMode = "Off"
    else
        m.view.globalCaptionMode = "On"
    end if

    if m.selectedSubtitle.IsExternal
        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
end sub

' User requested playback info
sub onSelectPlaybackInfoPressed()
    ' Check if we already have playback info and show it in a popup
    if isValid(m.playbackData) and isValid(m.playbackData.playbackinfo)
        m.global.sceneManager.callFunc("standardDialog", tr("Playback Info"), m.playbackData.playbackinfo)
        return
    end if

    m.getPlaybackInfoTask.control = "RUN"
end sub

' The playback info task has returned data
sub onPlaybackInfoLoaded()
    m.playbackData = m.getPlaybackInfoTask.data

    ' Check if we have playback info and show it in a popup
    if isValid(m.playbackData) and isValid(m.playbackData.playbackinfo)
        m.global.sceneManager.callFunc("standardDialog", tr("Playback Info"), m.playbackData.playbackinfo)
    end if
end sub

' Playback state change event handlers
sub onStateChange()
    if LCase(m.view.state) = "finished"
        ' Close any open dialogs
        if m.global.sceneManager.callFunc("isDialogOpen")
            m.global.sceneManager.callFunc("dismissDialog")
        end if

        ' If there is something next in the queue, play it
        if m.global.queueManager.callFunc("getPosition") < m.global.queueManager.callFunc("getCount") - 1
            m.global.sceneManager.callFunc("clearPreviousScene")
            m.global.queueManager.callFunc("moveForward")
            m.global.queueManager.callFunc("playQueue")
            return
        end if

        ' Playback completed, return user to previous screen
        m.global.sceneManager.callFunc("popScene")
        m.global.audioPlayer.loopMode = ""
    end if
end sub

' Roku translates the info provided in subtitleTracks into availableSubtitleTracks
' Including ignoring tracks, if they are not understood, thus making indexing unpredictable.
' This function translates between our internel selected subtitle index
' and the corresponding index in availableSubtitleTracks.
function availSubtitleTrackIdx(tracknameToFind as string) as integer
    idx = 0
    for each availTrack in m.view.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