# HTML5 TiVo-specific features



## davidblackledge (Sep 9, 2008)

Thanks to Riley Newson and Allanon, I did a little more investigation and now I know the following is available in TiVo HTML5 Apps.
I ran some code directly on my Roamio as well as on my Mini (which runs the same older version 12 of Opera as my Premiere) and got details.
_(the notations I'm using including javadoc-style comments might be a little odd, but hopefully it's clear)_
TiVo Client object:

```
/**
 * Asynchronously creates a Client object to access device, memory, tuner, action, etc. features
 * @param props is an object with a "ready" function that accepts the client object as parameter, and an "error" function that accepts a message as parameter.
 */
window.tivo.client.createClient (props)
// e.g.:
window.tivo.client.createClient( { 
  ready:function(client){
    // see below for functions in client object
  },
  error:function(msg){
  } 
} );
/// the client object returned to the ready function has the following functionality:
```
client device

```
/** this is presumedly an internal-use object to make the isPinSet and isPinValid functions work */
client.getParentalControl()
.parentalControlImpl ERROR ReferenceError: Security error: attempted to read protected variable

/** access to a device object with general functionality for this particular TiVo device */
client.getDevice()
.deviceImpl object:[object PluginObject]
.getManufacturer():TiVo
.getCompartment():
.getMonitorName ERROR TypeError: 'this.deviceImpl.getMonitorName' is not a function
.getDisplayInfo ERROR TypeError: 'this.deviceImpl.getDisplayInfo' is not a function
.getDisplayInfoObject ERROR TypeError: 'this.deviceImpl.getDisplayInfo' is not a function
/** generally "TCD" followed by the first 6 digits of the TSN/Serial Number */
.getModel():TCDA93000
/**
 * @provider presuming this is one of tivo.client.VodProvider
 * @return presuming an object that includes one of tivo.client.NodeGroupType
 */
.getNodeGroup(provider, callback)
/** the unique Tivo Service Number of this device - starts with the numeric portion of the Model */
.getSerialNumber():A93000XXXtsnXXX
/** @networkInterfaceType one of tivo.client.NetworkInterfaceType */
.getMacAddress ( networkInterfaceType )
.getNetworkId():0
.getConditionalAccessCardId():undefined // presuming this number is the cablecard identifier (undefined on mini)
.setClosedCaptionEnabled(enabled)
/**
 * Presumedly an asynchronous call where the callback function will be passed a boolean result
 * @pinType one of tivo.client.PinType
 */
.isPinSet ( pinType, callback )
/**
 * Presumedly an asynchronous call where the callback function will be passed a boolean result
 * @pinType one of tivo.client.PinType
 */
.isPinValid ( pinType, pin, callback )
/** @soundType one of tivo.client.TiVoSound  */
.playTiVoSound ( soundType )
.injectEmmData ( emmData, callback )
.getNavigationDirection():TRANSITION
.softwareMapChangeRequest (isUpgrade, callback)
.farFieldVoiceControlEnable (friendlyName, resetAuthentication)
.setFriendlyName (friendlyName)
```
client lineup

```
/** access to a Lineup object with channel listings plus channel and audio track change functionality */
client.getLineup()
.lineupImpl object:[object PluginObject]
.searchForChannelById ( id, callback )
.searchForChannelByNumber ( number, callback )
.searchForChannelByServiceId ( sid, callback )
.requestAllChannels ( cnt, callback )
.changeChannelById ( id, callback )
.changeChannelByNumber ( number, callback )
.changeChannelByServiceId ( sid, callback )
.requestCurrentAudioTrackInfo (callback)
.requestAvailableAudioTracksInfo (callback)
.changeAudioById ( id, callback )

/** access to a Tuner object which just provides access to the current channel tuning information */
client.getTuner()
.tunerImpl object:[object PluginObject]
.getCurrentChannel (callback)
```
client local data and memory

```
/** access to a LocalData object that presumedly stores/retrieves data specific to the running app */
client.getLocalData()
.localdataImpl object:[object PluginObject]
.storeLocalData ( appName, key, data, callback )
.removeLocalData ( appName, key, callback )
.searchLocalData ( appName, key, callback )

/** access to a Memory object to track what memory is available to the app */
client.getMemory()
.memoryImpl object:[object PluginObject]
.getMemoryInfo().memUsed number:4.28836
.getMemoryInfo().memAvail number:95.7116
.getMemoryInfo().memLimit number:100
.getGraphicsMemoryInfo().memUsed number:7.03133
.getGraphicsMemoryInfo().memAvail number:22.9687
.getGraphicsMemoryInfo().memLimit number:30
```
client logger

```
/** access to a Logger object */
client.getLogger()
.loggerImpl object:[object PluginObject]
/** presumedly jsonStr includes one of tivo.client.MediaEventType */
.logMediaEvent(jsonStr)
/** presumedly jsonStr includes one of window.KeyEvent */
.logKeyEvent(jsonStr)
```
client action

```
/** access to an Action object with sone navigation functionality */
client.getAction()
.actionImpl object:[object PluginObject]
/**
 * @uri presumedly a ui destination such as x-tivo:classicui:playback or x-tivo:web:http://
 */
.uiNavigate(uri, params, allowReturn)
/** @jsonStr a JSON string that presumedly contains one of tivo.client.ShowcaseActionType */
.showcase(jsonStr)
```
Enumerations:

```
window.tivo.client.NetworkInterfaceType.
 CA_CARD string:ca_card; DOCSIS string:docsis; ETHERNET string:ethernet; EXTERNAL string:external; MOCA string:moca; WIRED string:wired; WIRELESS string:wireless
window.tivo.client.MediaEventType.
 LOAD number:0; PLAY number:1; PAUSE number:2; SEEK number:3; ENDED number:4
window.tivo.client.ShowcaseActionType.
 RFI number:0; SCROLLSH number:1
window.tivo.client.LeadGenMenuActionType.
 MENU_ACTION_SUBMIT ; MENU_ACTION_CANCEL ; MENU_ACTION_INFO
window.tivo.client.PinType.
 PARENTAL_CONTROL string:parental; PURCHASE_CONTROL string:purchase
window.tivo.client.TiVoSound.
 ALERT ; BONK ; DESELECT ; ERROR ; LEFT ; PAGE_DOWN ; PAGE_UP; RIGHT ; SELECT ; SHOWCASE_ENTER ; SHOWCASE_EXIT ; SIGNAL_TONE ;
 SLOW_DOWN_1 ; SPEED_UP_1; SPEED_UP_2; SPEED_UP_3; SPEED_UP_4; TAG_UP; THUMBS_DOWN; THUMBS_UP; TIVO; UP_DOWN
window.tivo.client.NodeGroupType.
 TSID ; TSID_LIST ; SERVICE_GROUP
window.tivo.client.VodProvider.
 VIRGIN ; ONO ; MAGNUM_OPUS
```
Not sure if tivo.core would ever be used directly except maybe the exit method? Likely just what everything else is based on.

```
window.tivo.core.extend (base, sub)
window.tivo.core.trace(msg)
window.tivo.core.exit()
window.tivo.core.trio object:[object Object]
window.tivo.core.mindrpc object:[object Object]
```
OIPF is a standard for this sort of stuff, I haven't looked into using it yet:

```
window.oipfObjectFactory.createVideoBroadcastObject()
window.oipfObjectFactory.createVideoMpegObject()
// the following are only on the Roamio, not Mini/Premiere:
window.oipfObjectFactory.createApplicationManagerObject function:[object createApplicationManagerObject]
window.oipfObjectFactory.createCSManager function:[object createCSManager]
window.oipfObjectFactory.createCapabilitiesObject function:[object createCapabilitiesObject]
window.oipfObjectFactory.createChannelConfig function:[object createChannelConfig]
window.oipfObjectFactory.createConfigurationObject function:[object createConfigurationObject]
window.oipfObjectFactory.createDownloadManagerObject function:[object createDownloadManagerObject]
window.oipfObjectFactory.createDownloadTriggerObject function:[object createDownloadTriggerObject]
window.oipfObjectFactory.createDrmAgentObject function:[object createDrmAgentObject]
window.oipfObjectFactory.createGatewayInfoObject function:[object createGatewayInfoObject]
window.oipfObjectFactory.createMediaSynchroniser function:[object createMediaSynchroniser]
window.oipfObjectFactory.createParentalControlManagerObject function:[object createParentalControlManagerObject]
window.oipfObjectFactory.createRecordingSchedulerObject function:[object createRecordingSchedulerObject]
window.oipfObjectFactory.createSearchManagerObject function:[object createSearchManagerObject]
window.oipfObjectFactory.debug function:[object debug]
window.oipfObjectFactory.isObjectSupported function:[object isObjectSupported]
```


----------



## davidblackledge (Sep 9, 2008)

The other important part is capturing remote control Key events.
There are inconsistent results if you don't capture them right (like with the keypress event), but if you do it like the following, both versions give the same results and capture all keys:

```
window.addEventListener("keydown", function(e) {
  // act on preferably the e.key string (or else the numeric e.keyCode)... see below
 ...
  e.preventDefault();
  e.stopPropogation();
});
window.addEventListener("keyup", function(e) {
  ...
  e.preventDefault();
  e.stopPropogation();
});
```
Keys:
Virtual Key (VK) constant names are on the window object for Roamio, but are on the window.KeyEvent object (and therefore on the passed in event object) on Opera 12 (Mini/Premiere). They should match the event.keyCode field.
String names are the event.key field value.

VK_ESCAPE (27) "Esc" // this is used by both the replay and "back" labeled buttons.
VK_INFO (457) "Info"
VK_STORE_FAVORITE_0 (429) "StoreFavorite0" // thumbs up
VK_CLEAR_FAVORITE_0 (437) "ClearFavorite0" // thumbs down
VK_LEFT (37) "Left"
VK_UP (38) "Up"
VK_RIGHT (39) "Right"
VK_DOWN (40) "Down"
VK_ENTER (13) "Enter" // both "select" and "enter" labeled buttons
VK_REWIND (412) "MediaRewind"
VK_PLAY (415) "MediaPlay"
VK_FAST_FWD (417) "FastFwd" // no "Media" prefix on the key string
VK_RECORD (416) "MediaRecord" // button apparently sends VK_V on keypress in Opera 12 Tivos which is why you want to use keyup/down

VK_PLAY_PAUSE (463) "MediaPlayPause" // Pause
VK_PLAY_SPEED_DOWN (419) "PlaySpeedDown" // Slow
VK_TRACK_NEXT (425) "MediaTrackNext" // Channel/Page Up (yes, up)

VK_TRACK_PREV (424) "MediaTrackPrevious" // Channel/Page Down (yes, down)
VK_RED (403) "Red" // Action C
VK_GREEN (404) "Green" // Action D
VK_YELLOW (405) "Yellow" // Action A
VK_BLUE (406) "Blue" // Action B
VK_0 (48) "0"
VK_1 ... VK_8

VK_9 (57) "9"
VK_CLEAR (12) "Clear"
NO KEY EVENT is generated for the advance/skip/"(-)" key, unfortunately.
the "zoom"/"aspect"/"window" key forcibly exits the app, so there is no key event.


----------



## davidblackledge (Sep 9, 2008)

davidblackledge said:


> VK_ESCAPE (27) "Esc" // this is used by both the replay and "back" labeled buttons.


By the way, this is contrary to the Opera TV / VewD standard that since 2012 has stated all devices will include a remote button press of VK_BACK_SPACE (which on the TiVo constants is the value 8) and more recently the alternative VK_BACK (value 461 on TiVos). And I thought I had an app that was working following their standard on a TiVo so I'm not sure if the TiVo implementation has changed or if I am just confused.
Either way, you're better off handling VK_BACK_SPACE and VK_BACK along with VK_ESCAPE.

Zoom/Aspect/Window must work as the standard VK_EXIT based on the VewD standard.


----------



## Dan203 (Apr 17, 2000)

I'm not sure I'd put a lot of effort into an HTML5 app right now. TiVo's newest MSO product runs on Android TV and there is some speculation that the next retail device might as well. If that's the case then the future will be Adroid TV apps. Although I guess if you did develop something in HTML5 you could use a Cordova type wrapper to make it function as an AdroidTV app as well.


----------



## davidblackledge (Sep 9, 2008)

Dan203 said:


> I'm not sure I'd put a lot of effort into an HTML5 app right now


That said, if you want to make something that works on a current TiVo, it's probably the best choice, especially with this added access to the TiVo features. 
I wouldn't think there is much of a chance that current TiVos will get Android TV functionality.


----------



## Dan203 (Apr 17, 2000)

Probably not.

Do you know if the Opera browser used on TiVo supports HTML5 frameworks like Angular, React or Vue? Or do you have to write raw HTML5/javascript?


----------



## davidblackledge (Sep 9, 2008)

I haven't kept up with all the libraries, but generally speaking every framework is just a .js file or two to include on your page, it's just a question of whether that library was written simply enough to be compatible with opera 12 (for the mini/premiere lowest common denominator).

Apparently, Opera 12 is ECMAScript 5.1 compliant, but not ECMAScript 6.

A quick search seems to say:
Angular is only tested on opera 15, and there was some documented issue with opera 12.
React isn't real clear, but I guess they'd require some "polyfill" libraries to work on older browsers like this. That'd probably work for Angular, too.
Vue requires Ecmascript 5, so that should be OK.


----------

