Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
jkoon2
Visitor

Category Leaf Ordering

I'm creating a channel based on the VideoPlayer Sample Channel, is there a way to control the display order of the categoryLeaf elements? The order on screen does not match the order in my feed. 
0 Kudos
7 REPLIES 7
genepensiero
Roku Guru

Re: Category Leaf Ordering

did you ever get an answer to this or figure it out? i'd love to hear. 
0 Kudos
destruk
Streaming Star

Re: Category Leaf Ordering

You will probably need to specify if it is the old SDK or the new Scenegraph version you're working with.  I think I read somewhere that if it's an associative array then the order will be randomized, so you'd need to sort them first?  But I don't remember exactly.

https://forums.roku.com/viewtopic.php?f ... ve#p556208

If you want them in a different order you should be able to add them individually to a new array before displaying to the screen - rather than using for each you can use a regular for loop -
Something like this -- note - this might not be exactly what you need, just off the top of my head

x=categoryleaf.count()-1
categoryleafcollection=[]
For i=0 to x
categoryleafcollection.push(categoryleaf)
Next
0 Kudos

Re: Category Leaf Ordering

Ditto, same issue... did you ever find a solution for this??! I haven't come up with one yet. Thanks!
0 Kudos

Re: Category Leaf Ordering

This is for the new SDK kit using Scene Graph and the new "Video Player" sample channel. 
I have tried using the .keys() trick to return a keyed associative array, but I haven't figured out how to properly implement that into the UriHandler.brs file. 
I have everything else finished and ready to go so that I can update our channel to run on the new Scene Graph platform, but still have to get this figured out!
I'm sure it is just a couple lines of code, but I can't figure it out. I'm not sure why they didn't put in sample code so those of us who want our category leafs added to the RowList in the same order as our XML files could easily do that! The previous SDK worked this way, but obviously it was very different.

Any help would be greatly appreciated!!
0 Kudos
newchannel
Roku Guru

Re: Category Leaf Ordering

I'm using the videoplayer channel master to migrate a channel over. I have the same problem...not showing in the same order as the XML. Read forum and have not found a fix. I'm still early in the migrating over stage though. The sample shows the three choices in a row and I'm still trying to figure out how to make changes to it. Migrating might not be as easy as the videoplayer master channel made it seem. A full example with deeplinking would have been helpful instead of a partial example. 
http://www.victoryNOWfilmsandtv.com
0 Kudos
newchannel
Roku Guru

Re: Category Leaf Ordering

Well, never did find out what is making the order of the items in the XML move around. So, since I only have 3 category leafs anyway, I just moved the order in one of the category leafs to get the result I wanted. Now, on to attempting the deeplinking and change artwork and see if this channel migration will pass the test.
http://www.victoryNOWfilmsandtv.com
0 Kudos
producer1
Reel Rookie

Re: Category Leaf Ordering

Same problem for me, can't find out how to implement     

.keys()

              

The code in my UriHandler.brs file is as follows:

 

sub init()
print "UriHandler.brs - [init]"
m.port = createObject("roMessagePort")
' fields for checking if content has been loaded
m.top.count = 0
m.top.numRows = 0
m.top.numRowsReceived = 0
m.top.numBadRequests = 0
m.top.contentSet = false
' Stores the content if not all requests are ready
m.top.ContentCache = createObject("roSGNode", "ContentNode")
m.top.Cache = createObject("roSGNode", "Node")
' setting callbacks for url request and response
m.top.observeField("request", m.port)
m.top.observeField("encodeRequest", m.port)
m.top.observeField("ContentCache", m.port)
' setting the task thread function
m.top.functionName = "go"
m.top.control = "RUN"
end sub

'Task function
sub go()
print "UriHandler.brs - [go]"
' Holds requests by id
m.jobsById = {}
' UriFetcher event loop
while true
msg = wait(0, m.port)
mt = type(msg)
print "--------------------------------------------------------------------------"
print "Received event type '"; mt; "'"
' If a request was made
if mt = "roSGNodeEvent"
if msg.getField()="request"
if addRequest(msg.getData()) <> true then print "Invalid request"
else if msg.getField()="encodeRequest"
if encodeRequest(msg.getData()) <> true then print "Invalid request"
else if msg.getField()="ContentCache"
updateContent()
else
print "Error: unrecognized field '"; msg.getField() ; "'"
end if
' If a response was received
else if mt="roUrlEvent"
processResponse(msg)
' Handle unexpected cases
else
print "Error: unrecognized event type '"; mt ; "'"
end if
end while
end sub

' Encode the url and call addRequest
function encodeRequest(request as Object) as Boolean
encoder = createObject("roUrlTransfer")
encodedStr = encoder.escape(request.strToEncode)
newParam = { uri: request.context.parameters.uri + encodedStr }
request.context.parameters = newParam
return addRequest(request)
end function

' @Params:
' request: an AA containing a "context" node
' Context node fields:
' parameters: the request parameters: Headers, Method, and Url
' num: the number related to the request
function addRequest(request as Object) as Boolean
print "UriHandler.brs - [addRequest]"
if type(request) = "roAssociativeArray"
context = request.context
if type(context) = "roSGNode"
parameters = context.parameters
if type(parameters)="roAssociativeArray"
headers = parameters.headers
method = parameters.method
uri = parameters.uri
if type(uri) = "roString"
urlXfer = createObject("roUrlTransfer")
urlXfer.SetCertificatesFile("common:/certs/ca-bundle.crt")
urlXfer.InitClientCertificates()
urlXfer.setUrl(uri)
urlXfer.setPort(m.port)
' Add headers to the request
for each header in headers
urlXfer.AddHeader(header, headers.lookup(header))
end for
' should transfer more stuff from parameters to urlXfer
idKey = stri(urlXfer.getIdentity()).trim()
'Make request based on request method
' AsyncGetToString returns false if the request couldn't be issued
if method = "POST" or method = "PUT" or method = "DELETE"
urlXfer.setRequest(method)
ok = urlXfer.AsyncPostFromString("")
else
ok = urlXfer.AsyncGetToString()
end if
if ok then
m.jobsById[idKey] = {
context: request,
xfer: urlXfer
}
else
print "Error: request couldn't be issued"
end if
print "Initiating transfer '"; idkey; "' for URI '"; uri; "'"; " succeeded: "; ok
else
print "Error: invalid uri: "; uri
m.top.numBadRequests++
end if
else
print "Error: parameters is the wrong type: " + type(parameters)
return false
end if
else
print "Error: context is the wrong type: " + type(context)
return false
end if
else
print "Error: request is the wrong type: " + type(request)
return false
end if
print "--------------------------------------------------------------------------"
return true
end function

'Received a response
sub processResponse(msg as Object)
print "UriHandler.brs - [processResponse]"
idKey = stri(msg.GetSourceIdentity()).trim()
job = m.jobsById[idKey]
if job <> invalid
context = job.context
parameters = context.context.parameters
jobnum = job.context.context.num
uri = parameters.uri
print "Response for transfer '"; idkey; "' for URI '"; uri; "'"
result = {
code: msg.GetResponseCode(),
headers: msg.GetResponseHeaders(),
content: msg.GetString(),
num: jobnum
}
' could handle various error codes, retry, etc. here
m.jobsById.delete(idKey)
job.context.context.response = result
if msg.GetResponseCode() = 200
if result.num = 3 or result.num = 4
parseFollowedContent(job)
else if result.num = 0
parseResponse(job)
else if result.num = 1
parseLeaf(job)
end if
else if msg.GetResponseCode() = 204 and result.num = -7
parseLogout(job)
else if msg.GetResponseCode() = 204 and result.num = -10
parseUnfollow(true)
else
if result.num > 0 and result.num < 3
m.top.numBadRequests++
m.top.numRowsReceived++
else
print "Error: status code was: " + (msg.GetResponseCode()).toStr()
end if
end if
else
print "Error: event for unknown job "; idkey
end if
print "--------------------------------------------------------------------------"
end sub

sub parseLeaf(job as object)
print "UriHandler.brs - [parseLeaf]"
result = job.context.context.response
str = result.content
num = result.num
title = job.context.context.title

xml = CreateObject("roXMLElement")

if xml.parse(result.content)
if xml.feed <> invalid
row = CreateObject("roSGNode", "ContentNode")
row.title = title
for each element in xml.getChildElements()
if element.getChildElements() <> invalid
contentNode = CreateObject("roSGNode","ContentNode")
contentNode.hdposterurl = element@hdImg
contentNode.sdposterurl = element@sdImg
for each child in element.getchildElements()
if child.getname() = "title"
contentNode.title = child.getText()
else if child.getname() = "contentId"
contentnode.episodeNumber = child.gettext()
else if child.getname() = "genres"
contentnode.categories = child.getText()
else if child.getname() = "streamFormat"
contentnode.streamFormat = child.gettext()
'else if child.getname() = "contentQuality"
'' contentnode.contentQuality = child.gettext()
else if child.getname() = "media"
for each item in child.getchildElements()
if item.getname() = "streamQuality"
contentnode.rating = item.gettext()
else if item.getname() = "streamBitrate"
contentNode.maxBandWidth = item.gettext().toint()
else if item.getname() = "streamUrl"
contentNode.url = item.gettext()
else
print "WHY AM I HERE: " ; item.getName() ; item.getText()
end if
end for
else if child.getname() = "synopsis"
contentnode.description = child.gettext()
else if child.getname() = "genres"
contentnode.shortdescriptionline1 = child.gettext()
else if child.getname() = "runtime"
contentnode.shortdescriptionline2 = child.gettext()
end if
end for
row.appendChild(contentNode)
end if
end for
if m.top.contentcache.hasfield(m.top.numRowsReceived.tostr()) then m.top.numRowsReceived++
contentAA = {}
contentAA[m.top.numRowsReceived.toStr()] = row
m.top.contentCache.addFields(contentAA)
end if
end if
end sub

' For loading rowlist content
sub parseResponse(job as object)
print "UriHandler.brs - [parseResponse]"
result = job.context.context.response
str = result.content
num = result.num

xml = CreateObject("roXMLElement")
if xml.parse(result.content)
if xml.category <> invalid
if xml.category[0].GetName() = "category"
print "begin category node parsing"

 

categories = xml.GetChildElements()
print "number of categories: " + categories.Count().toStr()

'@ operator:
'The @ operator can be used on an roXMLElement to return a named attribute.
'It is always case insensitive (altho XML is technically case sensitive).
'When used on an roXMLList, the @ operator will return a value only if
'the list contains exactly one element.
contentRoot = CreateObject("roSGNode","ContentNode")
contentRow = CreateObject("roSGNode","ContentNode")
'Create a category node for each category'
for each category in categories
if category.getname() = "banner_ad"
print "skipped banner_ad"
else if category.getname() = "category"
contentNode = CreateObject("roSGNode","ContentNode")
print "category: " + category@title + " | " + category@description
aa = {}
aa.title = category@title
aa.description = category@description
aa.shortdescriptionline1 = category@title
aa.shortdescriptionline2 = category@description
aa.sdPosterUrl = category@sd_img
aa.hdposterurl = category@hd_img
m.count = 0
categoryLeaves = category.getChildElements()
for each leaf in categoryLeaves
subAA = {}
subAA.title = leaf@title
subAA.url = leaf@feed
a = {}
a[subAA.title] = subAA
AddAndSetFields(contentNode, a)
m.count++
end for
AddAndSetFields(contentNode,{count: m.count})
AddAndSetFields(contentNode, aa)
contentRow.appendChild(contentNode)
end if
end for
contentRoot.appendChild(contentRow)
m.top.content = contentRoot
end if
end if
end if
print "done with parseResponse"
end sub


' Callback function for when content has finished parsing
sub updateContent()
print "UriHandler.brs - [updateContent]"
if m.top.contentSet return
if m.top.numRows - 1 = m.top.numRowsReceived
parent = createObject("roSGNode", "ContentNode")
for i = (m.top.numRows - m.top.numCurrentRows) to m.top.numRowsReceived
parent.appendchild(m.top.contentCache.getField(i.toStr()))
end for
print "All content has finished loading"
m.top.contentSet = true
m.top.categorycontent = parent
itemToCache = {}
itemToCache[m.top.category] = parent
AddAndSetFields(m.top.cache, itemToCache)
else
print "Not all content has finished loading yet"
end if
end sub

 

 

Any help would be greatly appreciated. Thanks again! 

0 Kudos
Need Assistance?
Welcome to the Roku Community! Feel free to search our Community for answers or post your question to get help.

Become a Roku Streaming Expert!

Share your expertise, help fellow streamers, and unlock exclusive rewards as part of the Roku Community. Learn more.