Inspired by finding the GitHub repository for a Roku channel for Jellyfin, I decided to try to write a “channel” (app) to view PeerTube videos on my RokuTV.
PeerTube API
PeerTube has a pretty well documented API. Ignoring details about logging in as a registered user, all the calls needed for creating client use HTTP GET requests that return JSON data. So if there are any questions about the documents it is easy to use a terminal with wget
to make an API call and then look at the results with a text editor.
The API is built around the needs of the PeerTube’s JavaScript based web browser client and how it presents data. So there are a few things that need more calls than I’d like. For example, the call to return details about a specific video doesn’t return the full description nor the the subtitles available so three separate requests need to be made.
But in general the API is well designed and documented. Based on my limited interaction with the team via their GitHub issues, they are responsive to questions and suggestions. A very nicely run project!
Roku Development
I have mixed feelings on this. Roku does some things in ways that I’d not seen in the 40 years I spent in firmware and software development. That is/was a bit off putting. On the other hand, it is tailored to creating Roku channels and does a fairly good job of that.
Inside a Roku Channel
A Roku channel basically consists of a directory tree, in a fairly prescribed format, that is turned into a ZIP file. Inside that ZIP file there are text files, images and possibly some other channel specific resource files. At a minimum there is:
- A
key=value
style manifest text file. This gives the channel’s name, version, location of images to be used for channel graphics and the size/resolution of the screen assumed for layout purposes. - One or more Brightscript source code files.
- For newer “Scenegraph” based channels there are XML files for each “object” where an object can be a display screen, element within a display screen, or a task, etc.
Brightscript
The procedural language Roku uses is called “Brightscript” and seems to be based on Basic, a language I thought died back in the 1980s. But here it is enhanced with associative arrays and object extensions.
One downside of having a unique language is there are few, if any, non-Roku libraries of useful routines. When developing for an Android device if the extensive Android Java libraries don’t have what you need then there is a myriad of plain old Java libraries that you can probably use.
The upside of not having all those libraries is you don’t have to spend a long time searching for the library that has the best solution for your specific problem. If it isn’t in the Roku developer docs (a far smaller set of docs than Google has for Android) then it probably doesn’t exist.
The built-in Roku functions are definitely designed for the specific purpose of getting video content over the Internet and playing it on a TV screen. It only takes a few lines of code and a simple XML layout definition to play a “hello world” video.
Scenegraph
Roku requires newly developed channels to use “Scenegraph” which is basically a way of specifying object components in your channel by XML. It apparently is possible to implement the object methods by including the required Brightscript within some CDATA inside the XML but I found things got lexically weird so I have separate XML and Brightscript files with the XML file having a <script>
directive to pull in the procedural code that implement the object’s methods.
Scenegraph display and “content” objects contain the information needed for the Roku OS to render the various screens and menus your channel’s users interact with. The object tree structure and order of rendering is pretty clear making it fairly easy to design screens without a fancy development environment.
Development Cycle
All that is needed for development is a text editor, a image editor, a way to create a ZIP file and a web browser. There is no desktop based compilation stage which is strange to me.
The first step is to put a Roku device into “developer mode” using the Roku remote control.
After that the iterations are:
- Make edits.
- ZIP up the directory tree for your channel.
- Upload/side load to Roku device.
A lexical and initial syntax check of the ZIP package is performed by the Roku device when you side load the ZIP file. The uploads can be done with curl
so you can create a make file where a make install
will ZIP everything up and push it to the device. See the Jellyfin project’s Roku repository for an example of how to do this.
Now you can run the development “build”.
Brightscript is an interpreted language so there is no detection of any semantic errors or even some syntax errors until the there is an attempt to execute the actual statements.
So, for example if you accidentally have something like
if (mispelled_array_name = 7))
The mismatched parens will be found on upload/side load. But the undefined (mispelled) variable won’t be caught until execution. Once you fix the spelling your next iteration will notify you that there is a type mismatch on comparison of an array and an integer. All of these things would normally be caught at compile time in a more traditional development environment especially if using a strongly typed language.
This fun edit, upload, run and repeat cycle is broken up by the Roku device rebooting, seeming at random, after it detects an error in your channel code. Not every time. Probably not even most of the time. Just often enough to be really, really annoying.
Did I mention that unless you acquire the smallest TV and Roku device you can find to fit on your work desk, you are likely to be doing all this development work in your living room on the big screen TV? A room more designed for lounging than for concentrated working.
General Observations
In comparison to developing for Android:
- The lack of a conventional compiler, linker tool chain means that some typographical errors usually found by a compiler may not be caught until much later in the cycle. While testing of any software is required, it seems to me that the Roku environment makes this a bit harder than usual: I don’t see how to create the classical unit test suite to verify individual components outside of the final product. You are going to have to do nearly all the testing via the user interface and there may be code in corner cases that is hard to exercise.
- Roku screen layout is much easier than on Android. This is largely due to the target platform as Roku is designed for televisions. Your display is either an old “standard definition” (pretty rare nowadays) or something that has a 16:9 aspect ratio. Roku doesn’t need to worry about a myriad of display aspect ratios and the ability to rotate a device between portrait and landscape mode. You specify the resolution your design uses (HD for 720, FHD for 1080) and Roku will scale it up or down as needed depending if the device is 4K, 1080p, 720p, etc. So pick the resolution you want to work with then specify the locations of everything in pixels.
- The Roku model for background processing is pretty straight forward. Create a task object, set up one or more “watchers” on the things it can set (defined by its interface) and let it run. Android allows your app to create background services, etc. that are active when your app is not running in the foreground. None of that complexity in the Roku environment. If your channel/app is not running then nothing in it is running in the background
- A reasonably complete Roku channel ZIP file comes in at a couple hundred kilobytes. This is a fraction of the size of any of the simple Android apps I wrote despite all the source code being in the file as opposed to having compiled binaries. This is largely due to not linking to huge libraries. The functions you need to create a Roku app are baked into the Roku device and your don’t need a lot of extra libraries to do the job.
- The Roku developer agreement seems to be a bit more strict that Google’s. They really want the channel and its content to load in a reasonable amount of time. They want to be able to assure that the channel/app has only content that is legal and appropriate. Without that the channel can’t be certified (which is apparently done with a manual review) and put in their channel store. For that reason, my channel will remain a “private” or “uncertified” channel that can only be installed by use of a code: I don’t control the PeerTube instances so I can’t control the provisioning of their server nor the content they host on it.
- For internationalization and localization, you want to provide language dependent strings for the various menus and displays in your app or channel. Android has a scheme where your display definitions specify a string ID and you have a set of string files for each app supported language. In the string files each string is identified by the ID. The language the user has selected determines which string file is used to pull the strings, by ID, used on your display. No procedural code is needed as it is baked into the system. Roku’s approach is a little different: You can use either a TS or XLIFF files (both are XML) but it takes the full original en_US string as its key. This isn’t too bad for short things like the text on a button but it does use more space than a simple string ID. If you have some help or explanatory text then the
<source>
data (keys) can get quite large. At present Roku is limited to a total 7 translations for 6 languages: Two dialects of English, and one dialect each for French, Spanish, German, Italian and Portuguese while Android (and PeerTube) can handle a full iso639-1 set of language codes. I’ve elected to only support UI elements in languages that Roku supports. - For display, Android seems to have a pretty full internationalized font set. Throw Chinese, Russian, Greek, Arabic, etc. at it and you get a reasonable looking display output. Roku’s built in “system font” set seems to only support Latin based alphabets, you get boxes with X’s in them for anything else. There is a facility where you can include a customized TTF font for other language support. Since PeerTube videos could be from anywhere in the world with any language in the title, description, and tags you need to have a custom TTF that supports all languages in the world. The GNU FreeFont that I looked at has a 1.3 MB san serif TTF file and a 415 KB bold san serif TTF file. But Roku apparently only works with font files under about 40 KB in size. I am not sure what the solution is to this issue.
Branding, deployment and release
PeerTube Requirements
The PeerTube project has given me favorable comments on my Roku channel but made two points clear:
- They do not have the resources to support clients for all the different environments they hope will eventually appear. They cannot and will not take ownership of the code for this Roku channel. They did solicit and accept a pull request to put a information about PeerVue and a link to it in their third party applications page.
- They don’t want confusing branding, so my PeerTube channel can’t be named PeerTube. Or really even have PeerTube as part of the name. My corollary to this is that my branding needs to have a different graphical look too.
Based on that I’ve named the channel “PeerVue” and had custom graphics designed for it. This, I think, satisfies the IP requirements laid down by the PeerTube project.
Roku Requirements
On the Roku side, the Roku developer’s agreement requires that:
10.3. You will not, without Roku’s prior permission, (a) include any web browser(s) in your Application, or enable end users to enter web addresses into your Application, (b) permit your Application to interact with third party applications, third party logins (e.g., Facebook SSO), or voice-controlled platforms, (c) include any guide or similar search and discovery feature within your Application that identifies third party services outside your Application where Content may be available, or (d) provide access to other Applications within your Application.
To deal with that I created a lightly curated list of known PeerTube instances for inclusion in the channel then only allow the user to select an instance off the list. This will require maintenance as PeerTube instances come and go.
A channel can be released as “private” or “uncertified” with very few requirements. Simply let people know that the private channel code is “PEERVUE” and they can use their Roku account management page to add the channel to their devices.
But for a channel to be found in the normal channel store it needs to be certified. Certification requires, among other things, that:
- Certain performance and technical criteria must be achieved including but not limited to:
- Time from channel launch to when all content is available on. This time is to be measured on what are apparently some of the lower performance model Roku devices.
- Time from when play is initiated to when the video actually starts. Again measured on specific low performance devices.
- Quality/resolution of the video and audio.
- Certain legal conditions must be maintained including but not limited to:
- No illegal content.
- Clear mechanisms for keeping children from accessing inappropriate content.
- No violations of intellectual property.
- All the above varying based on the laws of the locale the account is registered in.
PeerVue is a general purpose PeerTube viewer I have no control over the provisioning or content of any instance other than the one I personally run. So this channel will likely never make it into the normal Roku channel store.