HTML5 TiVo-specific features

Discussion in 'Developers Corner' started by davidblackledge, Jul 6, 2019.

  1. davidblackledge

    davidblackledge Registered lÜser

    549
    31
    Sep 9, 2008
    NM
    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:
    Code:
    /**
     * 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
    Code:
    /** 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
    Code:
    /** 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
    Code:
    /** 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
    Code:
    /** 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
    Code:
    /** 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:
    Code:
    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.
    Code:
    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:
    Code:
    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]
    
     
  2. davidblackledge

    davidblackledge Registered lÜser

    549
    31
    Sep 9, 2008
    NM
    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:
    Code:
    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.
     
  3. davidblackledge

    davidblackledge Registered lÜser

    549
    31
    Sep 9, 2008
    NM
    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.
     
  4. Dan203

    Dan203 Super Moderator Staff Member TCF Club

    46,892
    4,185
    Apr 17, 2000
    Nevada
    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 likes this.
  5. davidblackledge

    davidblackledge Registered lÜser

    549
    31
    Sep 9, 2008
    NM
    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.
     
  6. Dan203

    Dan203 Super Moderator Staff Member TCF Club

    46,892
    4,185
    Apr 17, 2000
    Nevada
    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?
     
  7. davidblackledge

    davidblackledge Registered lÜser

    549
    31
    Sep 9, 2008
    NM
    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.
     

Share This Page