2023-05-03 21:21:04 +00:00
|
|
|
import "pkg:/source/utils/misc.brs"
|
|
|
|
import "pkg:/source/utils/config.brs"
|
|
|
|
import "pkg:/source/roku_modules/api/api.brs"
|
|
|
|
|
2019-10-12 21:00:07 +00:00
|
|
|
sub init()
|
2021-09-05 02:43:00 +00:00
|
|
|
m.playbackTimer = m.top.findNode("playbackTimer")
|
|
|
|
m.bufferCheckTimer = m.top.findNode("bufferCheckTimer")
|
2020-05-24 09:33:07 +00:00
|
|
|
m.top.observeField("state", "onState")
|
2022-11-18 02:05:32 +00:00
|
|
|
m.top.observeField("content", "onContentChange")
|
|
|
|
|
2021-09-05 02:43:00 +00:00
|
|
|
m.playbackTimer.observeField("fire", "ReportPlayback")
|
2021-07-09 20:08:32 +00:00
|
|
|
m.bufferPercentage = 0 ' Track whether content is being loaded
|
2021-09-05 02:43:00 +00:00
|
|
|
m.playReported = false
|
2021-06-12 15:03:47 +00:00
|
|
|
m.top.transcodeReasons = []
|
2022-09-12 09:00:55 +00:00
|
|
|
m.bufferCheckTimer.duration = 30
|
2021-07-09 20:08:32 +00:00
|
|
|
|
2022-07-16 02:28:59 +00:00
|
|
|
if get_user_setting("ui.design.hideclock") = "true"
|
|
|
|
clockNode = findNodeBySubtype(m.top, "clock")
|
2022-08-12 06:48:14 +00:00
|
|
|
if clockNode[0] <> invalid then clockNode[0].parent.removeChild(clockNode[0].node)
|
2022-07-16 02:28:59 +00:00
|
|
|
end if
|
2022-11-03 01:18:16 +00:00
|
|
|
|
|
|
|
'Play Next Episode button
|
2022-09-07 04:06:10 +00:00
|
|
|
m.nextEpisodeButton = m.top.findNode("nextEpisode")
|
|
|
|
m.nextEpisodeButton.text = tr("Next Episode")
|
|
|
|
m.nextEpisodeButton.setFocus(false)
|
2023-02-03 19:00:02 +00:00
|
|
|
m.nextupbuttonseconds = get_user_setting("playback.nextupbuttonseconds", "30")
|
2023-04-11 21:33:45 +00:00
|
|
|
if isValid(m.nextupbuttonseconds)
|
|
|
|
m.nextupbuttonseconds = val(m.nextupbuttonseconds)
|
|
|
|
else
|
|
|
|
m.nextupbuttonseconds = 30
|
|
|
|
end if
|
2022-11-21 01:18:23 +00:00
|
|
|
|
|
|
|
m.showNextEpisodeButtonAnimation = m.top.findNode("showNextEpisodeButton")
|
|
|
|
m.hideNextEpisodeButtonAnimation = m.top.findNode("hideNextEpisodeButton")
|
2022-11-21 05:43:20 +00:00
|
|
|
|
2022-11-21 21:48:24 +00:00
|
|
|
m.checkedForNextEpisode = false
|
|
|
|
m.getNextEpisodeTask = createObject("roSGNode", "GetNextEpisodeTask")
|
|
|
|
m.getNextEpisodeTask.observeField("nextEpisodeData", "onNextEpisodeDataLoaded")
|
|
|
|
|
2023-03-26 01:52:12 +00:00
|
|
|
m.top.observeField("allowCaptions", "onAllowCaptionsChange")
|
|
|
|
end sub
|
|
|
|
|
|
|
|
sub onAllowCaptionsChange()
|
|
|
|
if not m.top.allowCaptions then return
|
2023-01-27 00:03:09 +00:00
|
|
|
|
|
|
|
m.captionGroup = m.top.findNode("captionGroup")
|
2023-02-02 03:16:25 +00:00
|
|
|
m.captionGroup.createchildren(9, "LayoutGroup")
|
2023-01-27 00:03:09 +00:00
|
|
|
m.captionTask = createObject("roSGNode", "captionTask")
|
|
|
|
m.captionTask.observeField("currentCaption", "updateCaption")
|
2023-02-05 08:07:01 +00:00
|
|
|
m.captionTask.observeField("useThis", "checkCaptionMode")
|
2023-01-27 00:03:09 +00:00
|
|
|
m.top.observeField("currentSubtitleTrack", "loadCaption")
|
2023-02-02 03:16:25 +00:00
|
|
|
m.top.observeField("globalCaptionMode", "toggleCaption")
|
2023-02-19 18:30:48 +00:00
|
|
|
if get_user_setting("playback.subs.custom") = "false"
|
|
|
|
m.top.suppressCaptions = false
|
|
|
|
else
|
|
|
|
m.top.suppressCaptions = true
|
|
|
|
toggleCaption()
|
|
|
|
end if
|
2023-02-05 08:07:01 +00:00
|
|
|
end sub
|
2023-02-02 03:16:25 +00:00
|
|
|
|
2023-01-27 00:03:09 +00:00
|
|
|
sub loadCaption()
|
2023-02-19 18:30:48 +00:00
|
|
|
if m.top.suppressCaptions
|
|
|
|
m.captionTask.url = m.top.currentSubtitleTrack
|
|
|
|
end if
|
2023-01-27 00:03:09 +00:00
|
|
|
end sub
|
|
|
|
|
|
|
|
sub toggleCaption()
|
2023-02-02 03:16:25 +00:00
|
|
|
m.captionTask.playerState = m.top.state + m.top.globalCaptionMode
|
2023-02-19 18:30:48 +00:00
|
|
|
if LCase(m.top.globalCaptionMode) = "on"
|
|
|
|
m.captionTask.playerState = m.top.state + m.top.globalCaptionMode + "w"
|
2023-02-02 03:16:25 +00:00
|
|
|
m.captionGroup.visible = true
|
|
|
|
else
|
|
|
|
m.captionGroup.visible = false
|
|
|
|
end if
|
2023-01-27 00:03:09 +00:00
|
|
|
end sub
|
|
|
|
|
|
|
|
sub updateCaption ()
|
2023-02-19 18:30:48 +00:00
|
|
|
m.captionGroup.removeChildrenIndex(m.captionGroup.getChildCount(), 0)
|
2023-02-02 03:16:25 +00:00
|
|
|
m.captionGroup.appendChildren(m.captionTask.currentCaption)
|
2022-08-27 06:27:45 +00:00
|
|
|
end sub
|
|
|
|
|
2022-11-18 02:23:09 +00:00
|
|
|
' Event handler for when video content field changes
|
2022-11-18 02:05:32 +00:00
|
|
|
sub onContentChange()
|
2022-11-21 14:25:34 +00:00
|
|
|
if not isValid(m.top.content) then return
|
|
|
|
|
2022-11-18 02:05:32 +00:00
|
|
|
m.top.observeField("position", "onPositionChanged")
|
|
|
|
|
2022-11-21 14:25:34 +00:00
|
|
|
end sub
|
|
|
|
|
|
|
|
sub onNextEpisodeDataLoaded()
|
2022-11-21 21:48:24 +00:00
|
|
|
m.checkedForNextEpisode = true
|
|
|
|
|
|
|
|
m.top.observeField("position", "onPositionChanged")
|
2022-11-18 02:05:32 +00:00
|
|
|
end sub
|
|
|
|
|
2022-09-07 04:06:10 +00:00
|
|
|
'
|
|
|
|
' Runs Next Episode button animation and sets focus to button
|
2022-11-21 01:18:23 +00:00
|
|
|
sub showNextEpisodeButton()
|
2023-03-22 18:10:07 +00:00
|
|
|
if m.global.userConfig.EnableNextEpisodeAutoPlay and not m.nextEpisodeButton.visible
|
2023-02-19 18:30:48 +00:00
|
|
|
m.showNextEpisodeButtonAnimation.control = "start"
|
|
|
|
m.nextEpisodeButton.setFocus(true)
|
|
|
|
m.nextEpisodeButton.visible = true
|
2022-09-07 04:06:10 +00:00
|
|
|
end if
|
|
|
|
end sub
|
|
|
|
|
|
|
|
'
|
|
|
|
'Update count down text
|
|
|
|
sub updateCount()
|
2023-04-11 21:33:45 +00:00
|
|
|
nextEpisodeCountdown = Int(m.top.duration - m.top.position)
|
2023-02-05 11:59:46 +00:00
|
|
|
if nextEpisodeCountdown < 0
|
|
|
|
nextEpisodeCountdown = 0
|
|
|
|
end if
|
|
|
|
m.nextEpisodeButton.text = tr("Next Episode") + " " + nextEpisodeCountdown.toStr()
|
2022-09-07 04:06:10 +00:00
|
|
|
end sub
|
|
|
|
|
|
|
|
'
|
|
|
|
' Runs hide Next Episode button animation and sets focus back to video
|
2022-11-21 01:18:23 +00:00
|
|
|
sub hideNextEpisodeButton()
|
|
|
|
m.hideNextEpisodeButtonAnimation.control = "start"
|
2022-09-07 04:06:10 +00:00
|
|
|
m.nextEpisodeButton.setFocus(false)
|
|
|
|
m.top.setFocus(true)
|
|
|
|
end sub
|
|
|
|
|
2022-11-21 01:18:23 +00:00
|
|
|
' Checks if we need to display the Next Episode button
|
|
|
|
sub checkTimeToDisplayNextEpisode()
|
2023-02-19 18:30:48 +00:00
|
|
|
if m.top.content.contenttype <> 4 then return
|
2023-04-11 21:33:45 +00:00
|
|
|
if m.nextupbuttonseconds = 0 then return
|
2023-02-19 18:30:48 +00:00
|
|
|
|
2023-04-11 21:33:45 +00:00
|
|
|
if int(m.top.position) >= (m.top.duration - m.nextupbuttonseconds)
|
2023-02-19 18:30:48 +00:00
|
|
|
showNextEpisodeButton()
|
|
|
|
updateCount()
|
|
|
|
return
|
|
|
|
end if
|
|
|
|
|
|
|
|
if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus()
|
|
|
|
m.nextEpisodeButton.visible = false
|
|
|
|
m.nextEpisodeButton.setFocus(false)
|
2022-11-07 04:35:02 +00:00
|
|
|
end if
|
|
|
|
end sub
|
|
|
|
|
|
|
|
' When Video Player state changes
|
|
|
|
sub onPositionChanged()
|
2023-03-26 01:52:12 +00:00
|
|
|
if isValid(m.captionTask)
|
|
|
|
m.captionTask.currentPos = Int(m.top.position * 1000)
|
|
|
|
end if
|
2023-02-19 18:30:48 +00:00
|
|
|
' Check if dialog is open
|
2022-11-15 21:14:05 +00:00
|
|
|
m.dialog = m.top.getScene().findNode("dialogBackground")
|
2022-11-18 02:05:32 +00:00
|
|
|
if not isValid(m.dialog)
|
2022-11-21 01:18:23 +00:00
|
|
|
checkTimeToDisplayNextEpisode()
|
2022-11-07 04:35:02 +00:00
|
|
|
end if
|
|
|
|
end sub
|
2022-09-07 04:06:10 +00:00
|
|
|
|
2020-05-24 09:33:07 +00:00
|
|
|
'
|
|
|
|
' When Video Player state changes
|
2021-07-09 20:08:32 +00:00
|
|
|
sub onState(msg)
|
2023-03-26 01:52:12 +00:00
|
|
|
if isValid(m.captionTask)
|
|
|
|
m.captionTask.playerState = m.top.state + m.top.globalCaptionMode
|
|
|
|
end if
|
2020-05-24 09:33:07 +00:00
|
|
|
' When buffering, start timer to monitor buffering process
|
2021-06-26 13:52:16 +00:00
|
|
|
if m.top.state = "buffering" and m.bufferCheckTimer <> invalid
|
2020-05-30 08:44:22 +00:00
|
|
|
|
2020-05-24 09:33:07 +00:00
|
|
|
' start timer
|
|
|
|
m.bufferCheckTimer.control = "start"
|
|
|
|
m.bufferCheckTimer.ObserveField("fire", "bufferCheck")
|
2021-06-26 13:52:16 +00:00
|
|
|
else if m.top.state = "error"
|
2022-07-04 09:31:28 +00:00
|
|
|
if not m.playReported and m.top.transcodeAvailable
|
|
|
|
m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding
|
|
|
|
else
|
2022-07-04 09:09:16 +00:00
|
|
|
' If an error was encountered, Display dialog
|
2023-02-09 00:26:02 +00:00
|
|
|
dialog = createObject("roSGNode", "PlaybackDialog")
|
2022-07-04 09:09:16 +00:00
|
|
|
dialog.title = tr("Error During Playback")
|
|
|
|
dialog.buttons = [tr("OK")]
|
|
|
|
dialog.message = tr("An error was encountered while playing this item.")
|
|
|
|
m.top.getScene().dialog = dialog
|
|
|
|
end if
|
2022-07-04 09:31:28 +00:00
|
|
|
|
2020-05-30 08:44:22 +00:00
|
|
|
' Stop playback and exit player
|
|
|
|
m.top.control = "stop"
|
|
|
|
m.top.backPressed = true
|
2021-09-05 02:43:00 +00:00
|
|
|
else if m.top.state = "playing"
|
2022-11-21 21:02:25 +00:00
|
|
|
' Check if next episde is available
|
|
|
|
if isValid(m.top.showID)
|
2022-11-21 21:48:24 +00:00
|
|
|
if m.top.showID <> "" and not m.checkedForNextEpisode and m.top.content.contenttype = 4
|
2022-11-21 21:02:25 +00:00
|
|
|
m.getNextEpisodeTask.showID = m.top.showID
|
|
|
|
m.getNextEpisodeTask.videoID = m.top.id
|
|
|
|
m.getNextEpisodeTask.control = "RUN"
|
|
|
|
end if
|
|
|
|
end if
|
|
|
|
|
2021-09-05 02:43:00 +00:00
|
|
|
if m.playReported = false
|
|
|
|
ReportPlayback("start")
|
|
|
|
m.playReported = true
|
|
|
|
else
|
|
|
|
ReportPlayback()
|
|
|
|
end if
|
2022-10-06 16:01:36 +00:00
|
|
|
m.playbackTimer.control = "start"
|
2021-09-05 02:43:00 +00:00
|
|
|
else if m.top.state = "paused"
|
|
|
|
m.playbackTimer.control = "stop"
|
|
|
|
ReportPlayback()
|
|
|
|
else if m.top.state = "stopped"
|
|
|
|
m.playbackTimer.control = "stop"
|
|
|
|
ReportPlayback("stop")
|
|
|
|
m.playReported = false
|
|
|
|
end if
|
|
|
|
|
|
|
|
end sub
|
|
|
|
|
|
|
|
'
|
|
|
|
' Report playback to server
|
|
|
|
sub ReportPlayback(state = "update" as string)
|
|
|
|
|
|
|
|
if m.top.position = invalid then return
|
|
|
|
|
|
|
|
params = {
|
2022-05-30 12:59:24 +00:00
|
|
|
"ItemId": m.top.id,
|
2021-09-05 02:43:00 +00:00
|
|
|
"PlaySessionId": m.top.PlaySessionId,
|
|
|
|
"PositionTicks": int(m.top.position) * 10000000&, 'Ensure a LongInteger is used
|
2022-05-30 13:00:14 +00:00
|
|
|
"IsPaused": (m.top.state = "paused")
|
2021-09-05 02:43:00 +00:00
|
|
|
}
|
|
|
|
if m.top.content.live
|
|
|
|
params.append({
|
|
|
|
"MediaSourceId": m.top.transcodeParams.MediaSourceId,
|
|
|
|
"LiveStreamId": m.top.transcodeParams.LiveStreamId
|
|
|
|
})
|
2022-05-11 15:56:33 +00:00
|
|
|
m.bufferCheckTimer.duration = 30
|
2020-05-24 09:33:07 +00:00
|
|
|
end if
|
|
|
|
|
2021-09-05 02:43:00 +00:00
|
|
|
' Report playstate via worker task
|
|
|
|
playstateTask = m.global.playstateTask
|
|
|
|
playstateTask.setFields({ status: state, params: params })
|
|
|
|
playstateTask.control = "RUN"
|
2020-05-24 09:33:07 +00:00
|
|
|
end sub
|
|
|
|
|
|
|
|
'
|
|
|
|
' Check the the buffering has not hung
|
|
|
|
sub bufferCheck(msg)
|
|
|
|
|
|
|
|
if m.top.state <> "buffering"
|
|
|
|
' If video is not buffering, stop timer
|
|
|
|
m.bufferCheckTimer.control = "stop"
|
|
|
|
m.bufferCheckTimer.unobserveField("fire")
|
|
|
|
return
|
|
|
|
end if
|
2021-06-26 13:52:16 +00:00
|
|
|
if m.top.bufferingStatus <> invalid
|
2020-05-24 09:33:07 +00:00
|
|
|
|
|
|
|
' Check that the buffering percentage is increasing
|
2021-06-26 13:52:16 +00:00
|
|
|
if m.top.bufferingStatus["percentage"] > m.bufferPercentage
|
2020-05-24 09:33:07 +00:00
|
|
|
m.bufferPercentage = m.top.bufferingStatus["percentage"]
|
2022-05-11 15:56:33 +00:00
|
|
|
else if m.top.content.live = true
|
|
|
|
m.top.callFunc("refresh")
|
2020-05-24 09:33:07 +00:00
|
|
|
else
|
|
|
|
' If buffering has stopped Display dialog
|
2023-02-09 00:26:02 +00:00
|
|
|
dialog = createObject("roSGNode", "PlaybackDialog")
|
2020-05-24 09:33:07 +00:00
|
|
|
dialog.title = tr("Error Retrieving Content")
|
|
|
|
dialog.buttons = [tr("OK")]
|
|
|
|
dialog.message = tr("There was an error retrieving the data for this item from the server.")
|
|
|
|
m.top.getScene().dialog = dialog
|
|
|
|
|
|
|
|
' Stop playback and exit player
|
|
|
|
m.top.control = "stop"
|
|
|
|
m.top.backPressed = true
|
|
|
|
end if
|
|
|
|
end if
|
|
|
|
|
|
|
|
end sub
|
|
|
|
|
2020-03-28 20:04:57 +00:00
|
|
|
function onKeyEvent(key as string, press as boolean) as boolean
|
2022-10-11 14:57:02 +00:00
|
|
|
|
2022-12-21 02:38:26 +00:00
|
|
|
if key = "OK" and m.nextEpisodeButton.hasfocus() and not m.top.trickPlayBar.visible
|
2022-11-03 01:18:16 +00:00
|
|
|
m.top.state = "finished"
|
2022-11-21 01:18:23 +00:00
|
|
|
hideNextEpisodeButton()
|
2022-11-03 01:18:16 +00:00
|
|
|
return true
|
2022-11-13 04:55:03 +00:00
|
|
|
else
|
|
|
|
'Hide Next Episode Button
|
2022-11-21 01:18:23 +00:00
|
|
|
if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus()
|
|
|
|
m.nextEpisodeButton.visible = false
|
|
|
|
m.nextEpisodeButton.setFocus(false)
|
|
|
|
m.top.setFocus(true)
|
|
|
|
end if
|
2022-08-27 06:27:45 +00:00
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if not press then return false
|
2020-03-28 20:04:57 +00:00
|
|
|
|
2022-09-07 04:06:10 +00:00
|
|
|
if key = "down"
|
2021-07-09 20:08:32 +00:00
|
|
|
m.top.selectSubtitlePressed = true
|
|
|
|
return true
|
2022-09-06 04:38:37 +00:00
|
|
|
else if key = "up"
|
|
|
|
m.top.selectPlaybackInfoPressed = true
|
|
|
|
return true
|
2022-12-21 22:05:06 +00:00
|
|
|
else if key = "OK"
|
2022-12-20 23:55:25 +00:00
|
|
|
' OK will play/pause depending on current state
|
2022-12-21 22:05:06 +00:00
|
|
|
' return false to allow selection during seeking
|
2022-12-20 23:55:25 +00:00
|
|
|
if m.top.state = "paused"
|
|
|
|
m.top.control = "resume"
|
2022-12-21 22:05:06 +00:00
|
|
|
return false
|
2022-12-20 23:55:25 +00:00
|
|
|
else if m.top.state = "playing"
|
|
|
|
m.top.control = "pause"
|
2022-12-21 22:05:06 +00:00
|
|
|
return false
|
2022-12-20 23:55:25 +00:00
|
|
|
end if
|
2021-07-09 20:08:32 +00:00
|
|
|
end if
|
2020-03-28 20:04:57 +00:00
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
return false
|
2020-03-28 20:04:57 +00:00
|
|
|
end function
|