-
-
Notifications
You must be signed in to change notification settings - Fork 1
General ‐ Stations ‐ Adding New
In order to add a new station, we need to understand if it's within an existing app, or a new one. In the latter situation, it will also depend upon what steps are required to get to the live content and start playing.
Let's look at a situation like with the PBS subnets. Each of the apps has a configuration/plugin already set up with its steps, and this is what is assigned to those stations.


The critical difference between these stations is an area for a certain repeating looping step, like pressing down. This can be seen in the code:


In the case of PBS, all we need for a new station is the same configuration/plugin, but with the ADBTuner URL or Identifier or Roku Bridge Plugin List Position field set to the number of times we want to go through the loop.


Thus, for another subnet, the number would be the next value. This is also true among many other cases where the existing configurations/plugins can be used, even if they have extra steps. For instance, AMC on ADBTuner uses the same configuration and settings as A&E even though technically the first step of pressing Up is unnecessary. More aptly, a different app from the same provider will usually also have the same navigation layout, and therefore existing configurations/plugins can be used. As an example, A&E Global Media apps A&E, History, and FYI all use the same configuration/plugin, but Lifetime has a different set due to its layout.
Like Lifetime, in some situations (such as a net new provider and app) a new configuration/plugin is needed for differing steps or additions to existing ones. To begin, it is necessary to track each one of the button presses to get to the live content, which in turn will yield what should be in a configuration.
If the new necessary actions are similar to an existing one with just some slight changes, in ADBTuner you could just click Clone to get a copy of all its contents as a starting point.

Most critical to this process is the the uuid. This is a randomly generated unique identifier, so we want to make sure we always have one that differs completely from the others. This is how ADBTuner knows that there are individual and differing configurations available. By doing the clone action, you technically don't have to worry about this because it automatically assigns a new uuid.
Roku Bridge does not have a comparable function, but you can just edit a plugin in any text editor (although preferably a Python editor like Visual Studios) as a starting point.

Either way, for the purposes of this project and sharing, the preferred naming structure (as well as uuid value) is 0AppPlay-####-0000-0000-APP000000000 where #### is the station group numbering and APP is the app name, taking over extra zeros as needed. After that, no matter what you are looking to do, the steps are relatively the same. Start off by modifying the name row in ADBTuner or the app_name variable in Roku Bridge so that it contains a value to represent the app that is going to be used. This is how we ended up this things like:
"name": "App Play - PBS",
super().__init__(app_id="23353", app_name="App Play - PBS")
Then it is just a matter of what button presses you need to happen. For Android TV, these are generally KEYCODE_DPAD_xxxx functions like UP, DOWN, LEFT, RIGHT, and CENTER, but there is a possibility of other presses that could be useful. A complete list can be found here. Roku works much the same, although the codes are just things like Up, Down, Left, Right, and Select. That, and a few other potential ones, can be found here.
Further, as noted before, you can (and should) also use loops, which is what would be useful here for repetitive motions:
{
"ADB_LOOP": {
"iterations": "||TARGET_URL_OR_IDENTIFIER||",
"commands": [
"input keyevent KEYCODE_DPAD_DOWN",
"sleep 2"
]
}
},
if list_position >= 1:
for i in range(list_position):
sequence.append("Down")
sequence.append({"wait": 2})
Note the sleep and wait shown, which is the pause between button presses. Some apps may require more or less time depending upon how responsive they are. Generally, we want to be more careful than what is necessary.
WARNING: For ADBTuner, the total time, including app startup, should be less than 60 seconds. If it takes more time, the program may assume the process failed and releases the tuner. Although this has been addressed in recent versions, it's still generally recommended to make sure your total process time stays well below this threshold to be safe, leaving plenty of contingency in case there are any hiccups. Roku Bridge doesn't have this limitation, and due to Roku's architecture, some of the stations already take well beyond this length.
In the end, though, we’ll end up with a new configuration that looks like this...
{
"name": "App Play - PBS",
"author": "babsonnexus",
"version": "2026.05.10.1534",
"description": "Force stops an app, opens that app, and then moves in a specific pattern to get to an item to play. Use the 'URL or Identifier' field for the number of loops to run in the station selection step(s).",
"uuid": "0AppPlay-1400-0000-0000-PBS000000000",
"global_options": {
"wait_for_video_playback_detection": false,
"use_fixed_delay": true,
"fixed_delay_seconds": 1,
"check_for_and_clear_whos_watching_prompts": false,
"wait_after_post_playback_start_commands_seconds": 0
},
"pre_tune_commands": [
"input keyevent KEYCODE_MEDIA_STOP",
"am force-stop '||TARGET_PACKAGE_NAME||'"
],
"tune_commands": [
"adbtuner_open_app '||TARGET_PACKAGE_NAME||'",
"sleep 10",
"input keyevent KEYCODE_DPAD_LEFT",
"sleep 2",
"input keyevent KEYCODE_DPAD_DOWN",
"sleep 2",
"input keyevent KEYCODE_DPAD_CENTER",
"sleep 5",
"input keyevent KEYCODE_DPAD_LEFT",
"sleep 2",
{
"ADB_LOOP": {
"iterations": "||TARGET_URL_OR_IDENTIFIER||",
"commands": [
"input keyevent KEYCODE_DPAD_DOWN",
"sleep 2"
]
}
},
"input keyevent KEYCODE_DPAD_CENTER"
],
"post_playback_start_commands": [],
"post_tune_commands": [
"input keyevent KEYCODE_MEDIA_STOP",
"input keyevent KEYCODE_MEDIA_PAUSE",
"input keyevent KEYCODE_HOME",
"am force-stop '||TARGET_PACKAGE_NAME||'"
]
}
... or a new plugin like this:
# HDMI Encode Native Apps - Roku Bridge
# https://babsonnexus.github.io/hdmi-encoder-native-apps
# v2026.05.14.1813
from .base_plugin import BaseAppPlugin
import logging
class AppPlay_1400_0000_0000_PBS000000000(BaseAppPlugin):
def __init__(self):
super().__init__(app_id="23353", app_name="App Play - PBS")
def tune_channel(self, roku_ip, channel_data):
# Base station tuning
logging.info(f"[{self.app_name} Plugin] Tuning to '{channel_data.get('name')}'.")
plugin_data = channel_data.get('plugin_data', {})
list_position = plugin_data.get('list_position')
try:
list_position = int(list_position)
except (ValueError, TypeError):
list_position = 0
# Custom station tuning
sequence = []
sequence.append({"wait": 10})
for i in range(4):
sequence.append("Back")
sequence.append({"wait": 1})
sequence.append("Left")
sequence.append({"wait": 2})
sequence.append("Down")
sequence.append({"wait": 2})
sequence.append("Select")
sequence.append({"wait": 5})
if list_position >= 1:
for i in range(list_position):
sequence.append("Down")
sequence.append({"wait": 2})
sequence.append("Select")
return sequence
Save the configuration/plugin, upload it if necessary, and then it will be available to select with the new station you make.


Please note that in ADBTuner, even though these configurations are in alphabetical order, it can be a bit tricky finding the one you want if there are a lot of them. It is recommended to use the search field to narrow this down.

Roku Bridge does not have something like this at this time, so hunting will be your best option.
With that, you can go about filling in the fields for the stations you are creating. Of key importance, in ADBTuner, when creating the station, be sure to put some textual value in the URL or Identifier field. It doesn’t matter much, just something like http://thing.com will do.

Then, once you add the station, edit it again to change the URL or Identifier to a number, that value being the number of times to go through the loop, if you are following the process as shown above. Roku Bridge accepts numbers out of the box, but will not save a zero. The plugins have been written to assuming no value is equal to zero.
After that, all you need to do is click Preview in ADBTuner or run Live TV Preview in Roku Bridge and confirm it is working as expected, making any adjustments to the configuration/plugin as necessary. Otherwise, it will be available in whatever tool you use the next time you update the m3u playlist.
© Basil Junction Publishing
Notice: This open-source solution is provided without licenses or warranties.