Hello, I am trying to get a content from the web using Task. The Sub works great, except I am having difficulty returning the value from the function. Can somebody help me.
<?xml version="1.0" encoding="utf-8" ?>
<component name = "postergridCR" extends = "Task" >
<interface>
<field id = "postergriduri" type = "string" />
<field id = "postergridcontent" type = "string"/>
</interface>
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.top.functionName = "getContent"
end sub
sub getContent()
readInternet = createObject("roUrlTransfer")
readInternet.setUrl(m.top.postergriduri)
postergridcontent = readInternet.GetToString()
m.top.postergridcontent = postergridcontent
end sub
]]>
</script>
</component>
I am trying to return the content from the above function
function getwebcontent(webpage as string)
m.myObj = createObject("RoSGNode", "postergridCR")
m.myObj.postergriduri=webpage
m.myObj.functionName="getcontent"
m.myObj.control = "RUN"
return m.myObj.postergridcontent <<======== How do I return the content ??
end function
I will wait around for another 15 mins or so and see if you respond.
In case I miss you here is one way and forgive me but I like to use a more standardized code if you will. contentreader.xml
<?xml version = "1.0" encoding = "utf-8" ?>
<component name = "ContentReader" extends = "Task" >
<interface>
<field id = "contenturi" type = "uri" />
<field id = "content" type = "node" />
</interface>
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.top.functionName = "getcontent"
end sub
sub getcontent()
content = createObject("roSGNode", "ContentNode")
contentxml = createObject("roXMLElement")
readInternet = createObject("roUrlTransfer")
readInternet.setUrl(m.top.contenturi)
contentxml.parse(readInternet.GetToString())
if contentxml.getName()="Content"
for each item in contentxml.GetNamedElements("item")
itemcontent = content.createChild("ContentNode")
itemcontent.setFields(item.getAttributes())
end for
end if
m.top.content = content
end sub
]]>
</script>
</component>
the.xml
<component name = "SimplePosterGrid" extends = "Scene" initialFocus = "postergrid" >
<interface>
<field id="itemContent" type="node" onChange="showpostergrid"/>
</interface>
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.postergrid = m.top.findNode("PosterGrid")
m.readPosterGridTask = createObject("roSGNode", "ContentReader")
m.readPosterGridTask.contenturi = "http://yourfilehere.xml"
m.readPosterGridTask.observeField("content", "showpostergrid")
m.readPosterGridTask.control = "RUN"
end sub
sub showpostergrid()
m.postergrid.content = m.readPosterGridTask.content
m.postergrid.setFocus(true)
end sub
]]>
</script>
<children>
<PosterGrid
id = "PosterGrid"
basePosterSize = "[ 375, 225 ]"
numColumns = "4"
numRows = "3"
itemSpacing = "[ 50, 75 ]" />
</children>
</component>
You probably want to set an observer on the task and break your function up into 2 pieces; Instead of this
sub getContent()
readInternet = createObject("roUrlTransfer")
readInternet.setUrl(m.top.postergriduri)
postergridcontent = readInternet.GetToString()
m.top.postergridcontent = postergridcontent
end sub
Do something like this:
sub getContent()
m.readInternet = createObject("roUrlTransferTask")
m.readInternet.observeField("content","contentSet")
m.readInternet.Url = m.top.postergriduri
end sub
sub contentSet
m.top.postergridcontent = m.readInternet.content
end sub
The task needs to have a top level field “content” that it sets once it has received and processed the server response. As soon as the task sets “content” field (m.top.content from within the task), your brs will pick it up and assign to its own postergridcontent field.
I did what you recommended but got the following error. Also on your code, where is readinternet.getString() ?
Member function not found in BrightScript Component or interface. (runtime error &hf4) in pkg:/components/MainScene/task.xml(22)
022: readInternet.observeField(“content”,“contentSet”)
New field id added
<interface>
<field id = "postergriduri" type = "string" />
<field id = "postergridcontent" type = "string"/>
<field id = "content" type = "string" />
</interface>
Also on your code, where is readinternet.getString() ?
That belongs in the task, not in the render thread.
As far as that error, you’d have to include more of your code. It works on my Roku
Thank you. Sorry I think I need more help here. Here is my code.
getContent() is in task, and I still don’t get it why .getString() is not there. Also not sure where is "roURLtransferTask " object from on your code. Sorry I am a noob
Task.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name = "postergridCR" extends = "Task" >
<interface>
<field id = "postergriduri" type = "string" />
<field id = "postergridcontent" type = "string"/>
<field id = "content" type = "string" />
</interface>
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.top.functionName = "getData"
end sub
sub getContent()
m.readInternet = createObject("roUrlTransfer")
m.readInternet.observeField("content","contentSet")
m.readInternet.Url = m.top.postergriduri
end sub
sub contentSet()
m.top.postergridcontent = m.readInternet.content
end sub
]]>
</script>
</component>
scenegraph.brs
getwebcontent ("http://example.com")
function getwebcontent(webpage as string)
m.myObj = createObject("RoSGNode", "postergridCR")
m.myObj.postergriduri=webpage
m.myObj.functionName="getcontent"
m.myObj.control = "RUN"
return m.myObj.postergridcontent
end function
Think I goofed you up by giving you render thread code mixed in with your task code, and now you put the render thread code into the task.
This stuff belongs in your page brs (not task brs) the task brs will have the getString you’re asking about.
function getwebcontent(webpage as string)
m.myObj = createObject("RoSGNode", "postergridCR")
m.myObj.postergriduri=webpage
m.myObj.functionName="getcontent"
m.myObj.observeField("postergridcontent","gotContent") '<===================== CREATE OBSERVER BEFORE RUN'
m.myObj.control = "RUN"
end function
sub gotContent()
content = m.myObj.postergridcontent '<================== callback triggered when task sets m.top.postergridcontent'
end sub
Thank you very much, I am almost there but something is not working. gotContent() works and m.top.content value is set.
sub gotContent()
m.top.content = m.haamro.HTTPcontent
print m.top.content <======== This works
end sub
However, when I use getWebcontent function from other function/sub, m.top.content is set invalid. Is it because of the time it is taking to load the content ?
function myotherfunction(url)
getWebContent (url)
print m.top.content <======= this does not work
end function
Although you say it works, I’m not certain you’re doing it right without seeing the rest of the code. this wasn’t mentioned earlier; Is m.haamro your task and inside that task it’s setting m.top.HTTPcontent ?
m.haamro.HTTPcontent
In the last case where it isn’t working, it’s because you are trying to look at m.top.content immediately instead of waiting for the content to be set in the “gotContent” callback.
<component name = "haamroContent" extends = "Task" >
<interface>
<field id = "HTTPurl" type = "string" />
<field id = "HTTPcontent" type = "string" />
</interface>
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.top.functionName = "getData"
end sub
function getData()
url = m.top.HTTPurl
http = createObject("roUrlTransfer")
http.RetainBodyOnError(true)
port = createObject("roMessagePort")
http.setPort(port)
http.setCertificatesFile("common:/certs/ca-bundle.crt")
http.InitClientCertificates()
http.enablehostverification(false)
http.enablepeerverification(false)
http.setUrl(url)
if http.AsyncGetToString() Then
msg = wait(10000, port)
if (type(msg) = "roUrlEvent")
'HTTP response code can be <0 for Roku-defined errors
if (msg.getresponsecode() > 0 and msg.getresponsecode() < 400)
m.top.HTTPcontent = msg.getstring()
else
? "feed load failed: "; msg.getfailurereason();" "; msg.getresponsecode();" "; m.top.HTTPurl
m.top.HTTPcontent = ""
end if
http.asynccancel()
else if (msg = invalid)
? "feed load failed."
m.top.HTTPcontent =""
http.asynccancel()
end if
end if
end function
]]>
</script>
</component>
myfunction.brs
function getHTMLContent(webpage as string)
m.haamro = createObject("RoSGNode", "haamroContent")
m.haamro.HTTPurl=webpage
m.haamro.functionName="getdata"
m.haamro.ObserveField("HTTPcontent","gotContent")
m.haamro.control = "RUN"
end function
sub gotContent()
m.top.content = m.haamro.HTTPcontent '<================== callback triggered // content is set on Scene (myfunction.xml) where I will be using my function
print m.top.content <--- this is working and prints the output
end sub
function GrabWOD(webpage as string) <==== This is the function I am trying to call from other functions
getHTMLcontent(webpage) <-- calling my getHTMLcontent function, which triggers gotContent
html=m.top.content <-- isn't m.top.content now set ??
print html <-- not working
return html <-- not working
end function
I think you’re almost there, But you can’t expect m.top.content to be set immediately after you call the task. You need to wait for a callback and process it there.
html=m.top.content ← isn’t m.top.content now set ??
no, result will be in “m.haamro.HTTPcontent” in “gotContent” sub, not here, and not in “m.top.content”. If you don’t want to / can’t re-use gotContent sub, then you can set a new different observer on m.haamro to handle the response differently than gotContent:
m.haamro.ObserveField("HTTPcontent","newDifferentFunction")
...
sub newDifferentFunction()
m.top.content = m.haamro.HTTPcontent
' or '
html = m.haamro.HTTPcontent
print html
end sub
Here is the more complete solution with your code:
function getHTMLContent(webpage as string)
m.haamro = createObject("RoSGNode", "haamroContent")
m.haamro.HTTPurl=webpage
m.haamro.functionName="getdata"
m.haamro.ObserveField("HTTPcontent","gotContent")
m.haamro.control = "RUN"
end function
sub gotContent()
m.top.content = m.haamro.HTTPcontent
print m.top.content '<--- this is working and prints the output'
end sub
function GrabWOD(webpage as string)
m.haamro.HTTPurl=webpage
m.haamro.ObserveField("HTTPcontent","newDifferentFunction")
m.haamro.control = "RUN"
' This function can never see the response from the task, it has to use the observeField callback to get it'
end function
sub newDifferentFunction()
m.top.content = m.haamro.HTTPcontent
' or '
html = m.haamro.HTTPcontent
print html
end sub
Getting HTTPcontent works great ! Thank you very much for making it possible. But how do I return the HTTPContent value from the function itself so that I can use it elsewhere
function show_web_content (webpage)
......
return webcontent
end function
function getHTMLContent(webpage as string) <=== HTTPcontent is not set yet so I cannot return its value from this function
m.haamro = createObject("RoSGNode", "haamroContent")
m.haamro.HTTPurl=webpage
m.haamro.functionName="getdata"
m.haamro.ObserveField("HTTPcontent","gotContent")
m.haamro.control = "RUN"
end function
function gotContent() <=== this function is called from above, so not sure how do I return the value from this function to the main function that is making HTTP Request.
m.top.content = m.haamro.HTTPcontent
print m.top.content
end function
Are you calling this code from Main or from a node?
Assuming this is inside a node, then after you assign m.top.content to the current node’s (lets call it NODE) content field, that will be visible externally via NODE.content
Would need to see more code / what you’re trying to do to give you exact steps.
Maybe this will help, from inside a node the fields are referenced by “m.top.FIELDNAME” and from outside the same node, the fields can be retrieved via NODE.FIELDNAME where NODE is the node object, usually preceded by “m.” so it can be referenced throughout the current scope.