1

We have developed a Roku channel using Roku VideoPlayer Sample Channel (https://github.com/rokudev/videoplayer-channel). Although a recent submittal to Roku was rejected for not providing a deep linking capability. The main.brs provides means to parse a request for a deep link which I've been able to implement to obtain my contentID and mediaType based on a curl command as follows:

curl -d '' 'http://192.168.1.24:8060/launch/dev?MediaType=special&contentID=49479'

The main.brs comments say to

launch/prep the content mapped to the contentID here.

We're using the xml files to provide the Roku "categories" screen and the screen for the listing after selecting an item from the categories screen (including the springboard screen). Within these xml files, we tag the contentID and mediaType of every video item.

I'm fairly new to the Roku development. While we've been able to create channels previously using their video channel template, I don't know how to "launch/prep the content mapped to the contentID". I've searched and tried various other calls (ie - playMedia(ContentID, Screen)), but I get errors on the debugger relating to "function call operator () attempted on non-function".

I would appreciate some instruction on how to jump to the springboard of the video based on the value of the contentID passed using the deep linking command. Or a means to play the video based on the contentID in the xml file.

Here's my main.brs:

sub Main(input as Dynamic)
  print "################"
  print "Start of Channel"
  print "################"
  ' Add deep linking support here. Input is an associative array containing
  ' parameters that the client defines. Examples include "options, contentID, etc."
  ' See guide here: https://sdkdocs.roku.com/display/sdkdoc/External+Control+Guide
  ' For example, if a user clicks on an ad for a movie that your app provides,
  ' you will have mapped that movie to a contentID and you can parse that ID
  ' out from the input parameter here.
  ' Call the service provider API to look up
  ' the content details, or right data from feed for id
  if input <> invalid
    print "Received Input -- write code here to check it!"
    if input.reason <> invalid
      if input.reason = "ad" then
        print "Channel launched from ad click"
        'do ad stuff here
      end if
    end if
    if input.contentID <> invalid
      m.contentID = input.contentID
      print "contentID is: " + input.contentID
      print "mediaType is: " + input.mediaType
      'launch/prep the content mapped to the contentID here

    end if
  end if
  showHeroScreen(input)
end sub

' Initializes the scene and shows the main homepage.
' Handles closing of the channel.
sub showHeroScreen(input as object)
  print "main.brs - [showHeroScreen]"
  screen = CreateObject("roSGScreen")
  m.port = CreateObject("roMessagePort")
  screen.setMessagePort(m.port)
  scene = screen.CreateScene("VideoScene")
  m.global = screen.getGlobalNode()
  'Deep link params
  m.global.addFields({ input: input })
  screen.show()

  while(true)
    msg = wait(0, m.port)
    msgType = type(msg)
    if msgType = "roSGScreenEvent"
      if msg.isScreenClosed() then return
    end if
  end while
end sub

I'm thinking if I can get the params for deep linking properly set prior to the screen.show call, it should work? I am able to output the outputID and mediaType values using the debugger when using the curl to call the deep link, but it just goes to the home screen without cueing up the video that was deep linked.

Any help is appreciated.

Steve Lacy
  • 31
  • 4
  • Possible duplicate of [How to implement Deep Linking in Roku SG application?](https://stackoverflow.com/questions/43315764/how-to-implement-deep-linking-in-roku-sg-application) – Jess Bowers Feb 02 '18 at 21:19
  • With some additional outside help, I was able to get the deep linking established. The deep linking was handled through the UriHandler.brs by checking for a result value then calling a separate function within UriHandlers.brs to execute the deep linking. – Steve Lacy Dec 17 '19 at 15:18

1 Answers1

1

Please check my GitHub REPO for simple Deep Linking Example.

Little explanation: First I int my main.brs like this:

sub Main(args as Dynamic) as Void

    showSGScreen(args)
end sub

"args" will be provided by Roku Firmware! In my showSGScreen Sub, you will find:

'DeepLinking
if args.contentId <> invalid AND args.mediaType <> invalid
    m.scene.contentDLId = args.contentId
    m.scene.mediaDPType = args.mediaType
    m.scene.deepLinkingLand = true
end if

Now check out my audiocontent.xml file:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<AudioContent>
  <audio actors = "Artist - Unknown" album ="Album - Unknown" title = "KISS FM - LIVE STREAM" streamformat = "es.aac-adts" url = "http://80.86.106.143:9128/kissfm.aacp" HDPosterUrl = "pkg:/images/radio_stations_img/kiss_fm.png" Rating = "true" TrackIDAudio = "1" ShortDescriptionLine1 = "short-form"/>
  <audio actors = "Artist - Unknown" album ="Album - Unknown" title = "TDI Radio - LIVE STREAM" streamformat = "mp3" url = "http://streaming.tdiradio.com:8000/tdiradiob" HDPosterUrl = "pkg:/images/radio_stations_img/tdi_radio.png" Rating = "true" TrackIDAudio = "2" ShortDescriptionLine1 = "short-form"/>
  <audio actors = "Artist - Unknown" album ="Album - Unknown" title = "Polskie Radio - LIVE STREAM" streamformat = "hls" url = "http://stream85.polskieradio.pl/omniaaxe/k11.stream/playlist.m3u8" HDPosterUrl = "pkg:/images/radio_stations_img/polskie_radio.png" Rating = "true" TrackIDAudio = "3" ShortDescriptionLine1 = "short-form"/>
  <audio actors = "Edgar Allan Yo and Shporky Pork" album ="Mony Pajton EP" title = "Niko kao Ja - MP3" streamformat = "mp3" url = "pkg:/mp3/Edgar_Allan_Yo_and_Shporky_Pork_Niko_Kao_Ja.mp3"    HDPosterUrl = "pkg:/images/mp3_img/mony_pajton.png" Rating = "false" TrackIDAudio = "4" ShortDescriptionLine1 = "short-form"/>
  <audio actors = "Edgar Allan Yo and Shporky Pork" album ="Mony Pajton EP" title = "Zatvaramo Krug - MP3" streamformat = "mp3" url = "pkg:/mp3/Edgar_Allan_Yo_and_Shporky_Pork_Zatvaramo_Krug.mp3" HDPosterUrl = "pkg:/images/mp3_img/mony_pajton.png" Rating = "false" TrackIDAudio = "5" ShortDescriptionLine1 = "short-form"/>
</AudioContent>

Notice "TrackIDAudio" property.

Now go to HomeSceen.brs file and take a look at this:

if m.audiolist.content.getChild(index).TrackIDAudio = m.contentId
                    m.audiolist.jumpToItem = index
                    m.audioPlayer.itemContent = m.audiolist.content.getChild(index)
                    m.audioPlayer.audioControl = "play"
                    m.audioPlayer.setFocus(true)
                    m.audioPlayer.visible = true 

                    exit for
end if

So here is where I check if m.contentId(this is actually args.contentId that we added back in the main.brs file to the HomeScene's top ) is the same as the TrackIDAudio from my LabelList. If they are the same, App Will play my item!

One thing, you can test your deep linking with this TOOL.

Also you should now that you will need to send Roku XML feed of your contentID's and MediaTypes so that they can link those items with your app when published.

So user click's on your item in Roku search, Roku sends contentId and MediaType that you have provided to them in the XML feed to the Roku firmware, ROKU firmware than puts contentId and MediaType in args and after that you do what you need with it. Deep linking tool mimics this.

Also you can find some more info about deeplinking on this link

***One item in my audiocontent.xml has a bad link. I did this intentionally so I could show what will happen if you play corrupted link. So please do not worry about it when playing around with the Repo.

***Please check this, regarding changes in your question: Ok, you can do it like this aswell: Delete this line m.global.addFields({ input: input }) and add this two:

m.global.addFields({inputContentID: input.contentID})
m.global.addFields({inputMediaType: input.mediaType})

Now you can check if this m.global variables are empty and if not, you can start your video immediately: You can check this when content for video Player is ready to be played by video player:

if Len(m.global.inputContentID) > 0 AND Len(m.global.inputMediaType) > 0

        //loop through your content and find an item that has same inputContentID as the one saved in m.global.inputContentID variable.If you find it, play the video.

        m.Video.control = "play"

        m.global.inputContentID = ""
        m.global.inputMediaType = ""
end if
U.Mitic
  • 744
  • 1
  • 6
  • 14
  • My main channel uses the video template so I don't even have the HomeScreen.brs in my components folder. I was having some trouble translating your example over to the video template example. I'm thinking if I could just figure out how to pass params properly to the video screen.show function, it could work? Thanks! – Steve Lacy Dec 26 '17 at 22:41
  • Hi, I have added few lines to my answer above. Hope it helps! – U.Mitic Dec 26 '17 at 23:33
  • I'm sorry but I'm still unable to translate your example over to the video example. I tried several things but they aren't working for me. I'll get errors like "Type Mismatch", or "Use of uninitialized variable" when trying to add the code to my SpringBoard.brs or VideoScene.brs code. I think I'm close, but it's not working for me. – Steve Lacy Jan 04 '18 at 23:12
  • Can you tell me for which variable you get "type mismatch" or "Use of uninitialized varible"? – U.Mitic Jan 04 '18 at 23:18
  • @SteveLacy Can you tell me which variable gave you "use of uninitialized varible" or "type mismatch" error? – U.Mitic Jan 04 '18 at 23:20
  • I was doing some simple things like having a print statement just after assigning the m.global.addFields({inputContentID: input.contentID}) with a line: print "contentID is: " + inputContentID within main.brs and got an error about uninitialized inputContentID. I'm not a brightscript developer, but I know other languages so I thought the simple print statement would work. I'm using the Roku video player template and creating the necessary XML via some server side php scripts. I was following the output via telnet for my channel trying to figure out where to load the conditional statement. – Steve Lacy Jan 05 '18 at 20:49
  • Ok, I got it...the reason why you have that error is you are printing "inputContentID" but to print data that you have added to the m.global.addFields({inputContentID: input.contentID}), you will have to print it like this: print "contentID is: " ; m.global.inputContentID . – U.Mitic Jan 05 '18 at 21:26
  • To understand this better, please read this: https://sdkdocs.roku.com/display/sdkdoc/SceneGraph+Data+Scoping – U.Mitic Jan 05 '18 at 21:33