merge unstable

This commit is contained in:
Charles Ewert 2023-10-30 18:04:09 -04:00
parent c22e6ca5cd
commit c3a8c2bfce
18 changed files with 167 additions and 94 deletions

View File

@ -1,6 +1,5 @@
import "pkg:/source/roku_modules/log/LogMixin.brs"
import "pkg:/source/utils/deviceCapabilities.brs"
import "pkg:/source/roku_modules/promises/promises.brs"
sub init()
m.log = log.Logger("SceneManager")
@ -79,19 +78,16 @@ end sub
sub popScene()
group = m.groups.pop()
if group <> invalid
if group.isSubType("JFGroup")
if group.isSubtype("JFGroup")
unregisterOverhangData(group)
else if group.isSubType("JFVideo")
else if group.isSubtype("JFVideo")
' Stop video to make sure app communicates stop playstate to server
group.control = "stop"
else if groupType = "Settings"
' update device profile after exiting the settings page - some settings affect the device profile
postDeviceProfile()
end if
group.visible = false
if group.isSubType("JFScreen")
if group.isSubtype("JFScreen")
group.callFunc("OnScreenHidden")
end if
else
@ -103,14 +99,6 @@ sub popScene()
if group <> invalid
registerOverhangData(group)
if group.subtype() = "Home"
currentTime = CreateObject("roDateTime").AsSeconds()
if group.timeLastRefresh = invalid or (currentTime - group.timeLastRefresh) > 20
group.timeLastRefresh = currentTime
group.callFunc("refresh")
end if
end if
group.visible = true
m.content.replaceChild(group, 0)
@ -148,6 +136,11 @@ end function
' Clear all content from group stack
sub clearScenes()
if m.content <> invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0)
for each group in m.groups
if group.subtype() = "JFScreen"
group.callFunc("OnScreenHidden")
end if
end for
m.groups = []
end sub

View File

@ -1,10 +1,14 @@
import "pkg:/source/api/baserequest.brs"
import "pkg:/source/utils/config.brs"
import "pkg:/source/utils/misc.brs"
import "pkg:/source/utils/deviceCapabilities.brs"
sub init()
m.isFirstRun = true
m.top.overhangTitle = "Home"
m.top.optionsAvailable = true
m.postTask = createObject("roSGNode", "PostTask")
if m.global.session.user.settings["ui.home.splashBackground"] = true
m.backdrop = m.top.findNode("backdrop")
m.backdrop.uri = buildURL("/Branding/Splashscreen?format=jpg&foregroundLayer=0.15&fillWidth=1280&width=1280&fillHeight=720&height=720&tag=splash")
@ -18,3 +22,27 @@ end sub
sub loadLibraries()
m.top.findNode("homeRows").callFunc("loadLibraries")
end sub
sub OnScreenShown()
if m.top.lastFocus <> invalid
m.top.lastFocus.setFocus(true)
else
m.top.setFocus(true)
end if
refresh()
' post the device profile the first time this screen is loaded
if m.isFirstRun
m.isFirstRun = false
m.postTask.arrayData = getDeviceCapabilities()
m.postTask.apiUrl = "/Sessions/Capabilities/Full"
m.postTask.control = "RUN"
m.postTask.observeField("responseCode", "postFinished")
end if
end sub
sub postFinished()
m.postTask.unobserveField("responseCode")
m.postTask.callFunc("emptyPostTask")
end sub

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Home" extends="JFGroup">
<component name="Home" extends="JFScreen">
<children>
<Poster id="backdrop" loadDisplayMode="scaleToZoom" width="1920" height="1200" />
<HomeRows id="homeRows" />
@ -8,7 +8,6 @@
<interface>
<field id="selectedItem" alias="homeRows.selectedItem" />
<field id="quickPlayNode" alias="homeRows.quickPlayNode" />
<field id="timeLastRefresh" type="integer" />
<function name="refresh" />
<function name="loadLibraries" />
</interface>

View File

@ -1,7 +1,8 @@
import "pkg:/source/utils/config.brs"
import "pkg:/source/utils/misc.brs"
import "pkg:/source/roku_modules/log/LogMixin.brs"
import "pkg:/source/api/sdk.bs"
' post device profile
import "pkg:/source/utils/deviceCapabilities.brs"
sub init()
m.log = log.Logger("Settings")
@ -28,6 +29,8 @@ sub init()
m.boolSetting.observeField("checkedItem", "boolSettingChanged")
m.radioSetting.observeField("checkedItem", "radioSettingChanged")
m.postTask = createObject("roSGNode", "PostTask")
' Load Configuration Tree
m.configTree = GetConfigTree()
LoadMenu({ children: m.configTree })
@ -202,6 +205,20 @@ sub radioSettingChanged()
set_user_setting(selectedSetting.settingName, m.radioSetting.content.getChild(m.radioSetting.checkedItem).id)
end sub
sub OnScreenHidden()
' some settings affect the device profile.
' assume there were changes and always post device profile when leaving the settings screen
m.postTask.arrayData = getDeviceCapabilities()
m.postTask.apiUrl = "/Sessions/Capabilities/Full"
m.postTask.control = "RUN"
m.postTask.observeField("responseCode", "postFinished")
end sub
sub postFinished()
m.postTask.unobserveField("responseCode")
m.postTask.callFunc("emptyPostTask")
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Settings" extends="JFGroup">
<component name="Settings" extends="JFScreen">
<children>
<Label id="path" translation="[95,175]" font="font:SmallestBoldSystemFont" />

View File

@ -0,0 +1,74 @@
import "pkg:/source/api/baserequest.brs"
sub init()
m.top.functionName = "postItems"
end sub
sub postItems()
if m.top.apiUrl <> ""
if m.top.arrayData.count() > 0 and m.top.stringData = ""
print "PostTask Started - Posting array to " + m.top.apiUrl
req = APIRequest(m.top.apiUrl)
req.SetRequest("POST")
httpResponse = asyncPost(req, FormatJson(m.top.arrayData))
m.top.responseCode = httpResponse
print "PostTask Finished. " + m.top.apiUrl + " Response = " + httpResponse.toStr()
else if m.top.arrayData.count() = 0 and m.top.stringData <> ""
print "PostTask Started - Posting string(" + m.top.stringData + ") to " + m.top.apiUrl
req = APIRequest(m.top.apiUrl)
req.SetRequest("POST")
httpResponse = asyncPost(req, m.top.stringData)
m.top.responseCode = httpResponse
print "PostTask Finished. " + m.top.apiUrl + " Response = " + httpResponse.toStr()
else
print "ERROR processing data for PostTask"
end if
else
print "ERROR in PostTask. Invalid API URL provided"
end if
end sub
' Post data and wait for response code
function asyncPost(req, data = "" as string) as integer
' response code 0 means there was an error
respCode = 0
req.setMessagePort(CreateObject("roMessagePort"))
req.AddHeader("Content-Type", "application/json")
req.AsyncPostFromString(data)
' wait up to m.top.timeoutSeconds for a response
' NOTE: wait() uses milliseconds - multiply by 1000 to convert
resp = wait(m.top.timeoutSeconds * 1000, req.GetMessagePort())
respString = resp.GetString()
if respString <> invalid and respString <> ""
m.top.responseBody = ParseJson(respString)
print "m.top.responseBody=", m.top.responseBody
end if
respCode = resp.GetResponseCode()
if respCode < 0
' there was an unexpected error
m.top.failureReason = resp.GetFailureReason()
else if respCode >= 200 and respCode < 300
' save response headers if they're available
m.top.responseHeaders = resp.GetResponseHeaders()
end if
return respCode
end function
' Revert PostTask to default state
sub emptyPostTask()
' These should match the defaults set in PostTask.xml
m.top.apiUrl = ""
m.top.timeoutSeconds = 30
m.top.arrayData = {}
m.top.stringData = ""
m.top.responseCode = invalid
m.top.responseBody = {}
m.top.responseHeaders = {}
m.top.failureReason = ""
end sub

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="PostTask" extends="Task">
<interface>
<field id="apiUrl" type="string" />
<field id="timeoutSeconds" type="integer" value="30" />
<field id="arrayData" type="assocarray" value="{}" />
<field id="stringData" type="string" value="" />
<field id="responseCode" type="integer" />
<field id="responseBody" type="assocarray" value="{}" />
<field id="responseHeaders" type="assocarray" value="{}" />
<field id="failureReason" type="string" value="" />
<function name="emptyPostTask" />
</interface>
</component>

View File

@ -1,27 +0,0 @@
import "pkg:/source/roku_modules/promises/promises.brs"
sub init()
m.top.functionName = "resolve"
m.input = invalid
end sub
function getPromise(input = invalid as dynamic) as object
m.input = input
m.top.promise = promises.create()
m.top.control = "run"
return m.top.promise
end function
' Override me
function exec(input = invalid as dynamic) as dynamic
throw "Not implemented"
end function
sub resolve()
try
result = exec(m.input)
promises.resolve(result, m.top.promise)
catch e
promises.reject(e, m.top.promise)
end try
end sub

View File

@ -1,6 +0,0 @@
<component name="PromiseTask" extends="Task">
<interface>
<field id="promise" type="node" />
<function name="getPromise" />
</interface>
</component>

View File

@ -1,6 +0,0 @@
import "pkg:/source/roku_modules/rokurequests/Requests.brs"
function exec(input as object) as dynamic
print "input=", input
return Requests.request(input.method, input.url, input.params)
end function

View File

@ -1,2 +0,0 @@
<component name="RequestPromiseTask" extends="PromiseTask">
</component>

13
package-lock.json generated
View File

@ -15,8 +15,6 @@
"brighterscript-formatter": "1.6.34",
"intKeyboard": "npm:integer-keyboard@1.0.12",
"log": "npm:roku-log@0.11.1",
"promises": "npm:@rokucommunity/promises@0.1.0",
"roku-requests": "1.2.0",
"sob": "npm:slide-out-button@1.0.1"
},
"devDependencies": {
@ -4225,12 +4223,6 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/promises": {
"name": "@rokucommunity/promises",
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@rokucommunity/promises/-/promises-0.1.0.tgz",
"integrity": "sha512-FOPtEnHXfShwhrQiGSksTK0AQt5+rxcqpP6hg0U3Dx7WbMpL9PEd3udJhQteg3Iy2/GF858vYLcwdG8YdOloYw=="
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@ -4921,11 +4913,6 @@
"integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==",
"dev": true
},
"node_modules/roku-requests": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/roku-requests/-/roku-requests-1.2.0.tgz",
"integrity": "sha512-X6XakmJwxT8H+YNvjZOwH+k8rmYpD5o47k37WyZJ/brrSD6cw9xbNdxO203nz6jpso4maQJGwSJvLGZpzSQ0AA=="
},
"node_modules/rooibos-roku": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/rooibos-roku/-/rooibos-roku-5.8.0.tgz",

View File

@ -8,15 +8,8 @@
"brighterscript-formatter": "1.6.34",
"intKeyboard": "npm:integer-keyboard@1.0.12",
"log": "npm:roku-log@0.11.1",
"promises": "npm:@rokucommunity/promises@0.1.0",
"roku-requests": "1.2.0",
"sob": "npm:slide-out-button@1.0.1"
},
"ropm": {
"noprefix": [
"roku-requests"
]
},
"devDependencies": {
"@rokucommunity/bslint": "0.8.11",
"brighterscript": "0.65.8",

View File

@ -632,16 +632,6 @@ sub Main (args as dynamic) as void
if event.exitedScreensaver = true
sceneManager.callFunc("resetTime")
group = sceneManager.callFunc("getActiveScene")
if isValid(group) and isValid(group.subtype())
' refresh the current view
if group.subtype() = "Home"
currentTime = CreateObject("roDateTime").AsSeconds()
group.timeLastRefresh = currentTime
group.callFunc("refresh")
end if
' todo: add other screens to be refreshed - movie detail, tv series, episode list etc.
end if
else if isValid(event.audioGuideEnabled)
tmpGlobalDevice = m.global.device
tmpGlobalDevice.AddReplace("isaudioguideenabled", event.audioGuideEnabled)

View File

@ -73,7 +73,6 @@ sub AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx
MarkItemWatched(video.id)
video.content.watched = not video.content.watched
group = m.scene.focusedChild
group.timeLastRefresh = CreateObject("roDateTime").AsSeconds()
group.callFunc("refresh")
video.content = invalid
return

View File

@ -195,7 +195,13 @@ sub setCertificateAuthority(request as object) as void
end sub
' Takes and returns a roUrlTransfer object after adding a Jellyfin "Authorization" header
function authRequest(request as object) as object
function authRequest(req as object) as object
req.AddHeader("Authorization", buildAuthHeader())
return req
end function
' Returns a string containing the "Authorization" header payload
function buildAuthHeader() as string
QUOTE = Chr(34)
auth = "MediaBrowser" + " Client=" + QUOTE + "Jellyfin Roku" + QUOTE
auth = auth + ", Device=" + QUOTE + m.global.device.name + " (" + m.global.device.model + ")" + QUOTE
@ -211,6 +217,5 @@ function authRequest(request as object) as object
auth = auth + ", Token=" + QUOTE + m.global.session.user.authToken + QUOTE
end if
request.AddHeader("Authorization", auth)
return request
return auth
end function

View File

@ -959,6 +959,12 @@ function removeDecimals(value as string) as string
return value
end function
' Post the deviceProfile to the server
sub postDeviceProfile()
profile = getDeviceCapabilities()
printDeviceProfile(profile)
end sub
' Print out the deviceProfile for debugging
sub printDeviceProfile(profile as object)
print "profile =", profile

View File

@ -107,6 +107,11 @@ namespace session
tmpSessionServer.AddReplace("isLocalHTTPS", isLocalServerHTTPS)
' update global server session using the temp array
session.Update("server", tmpSessionServer)
if m.global.app.isDev
print "m.global.session.server = ", m.global.session.server
end if
return true
end function
end namespace