Mind RPC PartnerID x does not have access to operation offerSearch

Discussion in 'Developers Corner' started by Eric2XU, Mar 26, 2016.

  1. Eric2XU

    Eric2XU New Member

    15
    0
    Mar 18, 2016

    Advertisements

    So I figured out how to write a node.js tls connection to the TiVo using this code:

    Code:
    var tls = require('tls');
    var fs = require('fs');
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
    
    var options = {
    	host : "192.168.1.1"
    	,rejectUnauthorized: false
    	,port : 1413
    	,pfx : fs.readFileSync('c:\\temp\\xxxxxxxx.p12')
    	,passphrase : "xxxxxxxx"
    	,ca : [fs.readFileSync('c:\\temp\\tivo.ca'), fs.readFileSync('c:\\temp\\tivo.int')]
    	,secureProtocol: "TLSv1_1_method"
    };
    
    var sessionID = Math.floor(Math.random() * (2612256 - 2539520) + 2539520).toString(16)
    var eol = "\r\n";
    
    
    var header = "Type: request" + eol;
    header = header + "RpcId: 1" + eol;
    header = header + "SchemaVersion: 17" + eol;
    header = header + "Content-Type: application/json" + eol;
    header = header + "RequestType: bodyAuthenticate" + eol;
    header = header + "ResponseCount: single" + eol;
    header = header + "BodyId: " + eol;
    header = header + "X-ApplicationName: Quicksilver" + eol;
    header = header + "X-ApplicationVersion: 1.2" + eol;
    header = header + "X-ApplicationSessionId: 0x" + sessionID + eol;
    header = header + eol;
    
    var body = '{"type":"bodyAuthenticate","credential":{"type":"makCredential","key":"0123456789"}}' + "\n"
    
    var firstline = "MRPC/2 " + header.length + " " + body.length + eol
    
    
    var client = this;
    client.socket = tls.connect(options, function () {
    	client.socket.setEncoding('utf8');
    	client.socket.write(firstline + header + body);
    	
    	var data = "";
    	
    	client.socket.on('data', function (chunk) {
    		data += chunk;
    		console.log(data);
    	});
    
    	client.socket.on('end', function () {
    		client.socket.end();
    		
    	});
    
    	client.socket.on('error', function (err) {
    		console.log("Error during TLS request");
    		console.log(err);
    		client.socket.end();
    	});
    	
    });
    
    Sure enough it responds with:
    Code:
    MRPC/2 75 119
    Content-Type: application/json
    IsFinal: true
    RpcId: 1
    Type: response
    
    {"message": "Authentication successful", "status": "success", "type": "bodyAuthenticateResponse", "mediaAccessKey": ""}
    
    However when I try to run this:
    Code:
    MRPC/2 230 75
    
    Type: request
    RpcId: 1
    SchemaVersion: 17
    Content-Type: application/json
    RequestType: offerSearch
    ResponseCount: single
    BodyId:
    X-ApplicationName: Quicksilver
    X-ApplicationVersion: 1.2
    X-ApplicationSessionId: 0x26f44a
    
    {"type": "offerSearch","title": "The Daily Show","orderBy": ["startTime"]}
    
    I get back:
    Code:
    {"code": "routingError", "text": "PartnerId 3976 does not have access to operation offerSearch.", "type": "error"}
    So my first question to anyone that has experience with MindRPC, does this error message mean that the IOS app doesnt have the rights to do a simple search? Or does it mean I am not stringing my first bodyAuthenticate correctly with my second query to request do the search.

    Given its specific about a partnerID I am going to assume the IOS app cert I am using doesnt have rights to search. If that is the case, is there another way I can search for a show name? I noticed kmttg pulls the entire collection (which takes a long time), is that the only way to get the data?

    Could someone help me with what command is needed to pull all data if that is what is needed (I will cache it locally every "x" mins if needed).

    Finally while I have your attention, do you know the specific rpc command needed to start playing a specific show?

    Thanks in advance!!
     
  2. moyekj

    moyekj Well-Known Member

    12,208
    859
    Jan 23, 2006
    Mission...
    BodyId can't be empty for "offerSearch". Needs to be "tsn:xxxxxx"
     
  3. Eric2XU

    Eric2XU New Member

    15
    0
    Mar 18, 2016
    I just tried sliding in the BodyID as tsn:xxxxx and still got the same message.

    Here is what I sent (I slightly changed my TSN)

    Code:
    MRPC/2 249 75
    
    Type: request
    RpcId: 1
    SchemaVersion: 17
    Content-Type: application/json
    RequestType: offerSearch
    ResponseCount: single
    BodyId: tsn:3480001501FAAB7
    X-ApplicationName: Quicksilver
    X-ApplicationVersion: 1.2
    X-ApplicationSessionId: 0x26e30d
    
    {"type": "offerSearch","title": "The Daily Show","orderBy": ["startTime"]}
    
    And this is what I got back:

    Code:
    MRPC/2 75 114
    Content-Type: application/json
    IsFinal: true
    RpcId: 1
    Type: response
    
    {"code": "routingError", "text": "PartnerId 3976 does not have access to operation offerSearch.", "type": "error"}
    Any other ideas? Or is there some other command I can use to gather all shows and do you know the command to play a show by id?
     
  4. moyekj

    moyekj Well-Known Member

    12,208
    859
    Jan 23, 2006
    Mission...
    To play a show on a local TiVo you need it's recordingId, so offerSearch isn't what you want anyway. You need to obtain list of shows on the TiVo using repeated "recordingFolderItemSearch" calls with offset incremented until you get no further results to get full list of shows:
    Code:
    {"flatten":true,"offset":0,"bodyId":"tsn:xxxx","type":"recordingFolderItemSearch"}
    
    Then to play a show using it's recordingId:
    Code:
    {"type":"uiNavigate","uri":"x-tivo:classicui:playback","parameters":{"fUseTrioId":"true","fHideBannerOnEnter":"true","recordingId":"tivo:rc.xxxxxxxxx"}}
    
    NOTE: Playing back a SKIP enabled show the above way prevents SkipMode from working. (Same problem exists if you start playback of a show from iOS/Android apps).

    Also it looks like you're not incrementing RpcId with subsequent calls which I think you need to do.
     
  5. Eric2XU

    Eric2XU New Member

    15
    0
    Mar 18, 2016

    Advertisements

    thx moyekj, sadly same error, I guess I must be doing something wrong?

    Here is what I submit:

    Code:
    MRPC/2 263 94
    
    Type: request
    RpcId: 3
    SchemaVersion: 17
    Content-Type: application/json
    RequestType: recordingFolderItemSearch
    ResponseCount: single
    BodyId: tsn:6480001701FCC2
    X-ApplicationName: Quicksilver
    X-ApplicationVersion: 1.2
    X-ApplicationSessionId: 0x27521a
    
    {"flatten":true,"offset":0,"bodyId":"tsn:6480001701FCC2","type":"recordingFolderItemSearch"}
    
    This is what I get back

    Code:
    MRPC/2 75 128
    Content-Type: application/json
    IsFinal: true
    RpcId: 3
    Type: response
    
    {"code": "routingError", "text": "PartnerId 3976 does not have access to operation recordingFolderItemSearch.", "type": "error"}
     
  6. moyekj

    moyekj Well-Known Member

    12,208
    859
    Jan 23, 2006
    Mission...
    Probably issue with certificate you are using then. Also note I sent you a PM on a somewhat unrelated matter.

    Also, tsn 648 you list above is a series 3 TiVo which doesn't support direct RPC communication...
     
  7. Eric2XU

    Eric2XU New Member

    15
    0
    Mar 18, 2016
    Just sent back the PM, I figured out I wasnt at the 10 required posts that were required to respond to a PM.

    I had changed my TSN to not post my real one publicly. Also I am using a Roamio.

    Do you know if its common to see that style of error message as a catch all message. Figuring out if it knows who I am (emulating a IOS app) or if I am just not saying the right things would be helpful to know which way to troubleshoot next.
     
  8. Eric2XU

    Eric2XU New Member

    15
    0
    Mar 18, 2016
    Another update, made alot of progress. I was able to get past the partner x doesnt have rights. Sure enough I wasnt linking my bodyAuthenticate request with subsequent requests over the same socket.

    For anyone that would like to interact with TiVo via a Node.js script I will post my semi-functional code below.

    However my larger issue is now back to good old fashioned mis-understanding of the API.

    I am able to run this:
    Code:
    {"flatten":false,"offset":0,"bodyId":"tsn:xxxxxxxxxxx","type":"recordingFolderItemSearch"}
    Note: I set flatten to false because setting to true is 1) slow and 2) returns malformed JSON which I can not parse effectively with built in node.js libraries. This shouldn't be an issue though, I am able to get the show's parent folder ID and could go back to the TiVo to get a listing of recordings specific to that folder ID.

    Sure enough I get back all the parent folder ID's. So for example one of my parent folders looks like this:
    Code:
    { bodyId: 'tsn:xxxxxxxxxxxxxx',
           childRecordingId: 'tivo:rc.109822539',
           recordingFolderItemId: 'tivo:rf.109822539',
           startTime: '2016-03-31 04:01:00',
           title: 'At Midnight With Chris Hardwick',
           newItems: 1,
           collectionId: 'tivo:cl.334914484',
           collectionType: 'series',
           transportType: 'stream',
           contentId: 'tivo:ct.341991971',
           subscriptionIdentifier: [Object],
           isAdult: false,
           recordingStreamProhibited: false,
           recordingTransferProhibited: false,
           percentWatched: 0,
           type: 'recordingFolderItem' },
    Next I try to go back to the TiVo to get a listing of each shows on the DVR with that recordingFolderItemId or childRecordingId (they are the same ID). This is where I am failing.

    Using this:
    Code:
    {"orderBy": ["startTime"],"type": "recordingFolderItemSearch","bodyId": "tsn:xxxxxxxxxxxxx","note": ["recordingForChildRecordingId"],"parentRecordingFolderItemId": "tivo:rf.109822539"}
    All I get back is:
    Code:
    { type: 'recordingFolderItemList' }
    So theres a bit of "now what". I inch closer but yet seem so far away puzzled by why TiVo's api is so barbaric. Going to see if anyone out there has any ideas because my next move is to manually parse the all shows JSON which is going to be very sloppy and slow.

    ---------------------
    Node.js Code for talking to the TiVo:
    Code:
    var tls = require('tls');
    var fs = require('fs');
    var async = require('async');
    
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
    
    var options = {
    	host : "192.168.1.1"
    	,rejectUnauthorized: false
    	,port : 1413
    	,pfx : fs.readFileSync('c:\\temp\\xxxxxx.p12')
    	,passphrase : "xxxxxx"
    	,ca : [fs.readFileSync('c:\\temp\\tivo.ca'), fs.readFileSync('c:\\temp\\tivo.int')]
    	,secureProtocol: "TLSv1_1_method"
    };
    
    var sessionID = Math.floor(Math.random() * (2612256 - 2539520) + 2539520).toString(16)
    var eol = "\r\n";
    var RpcId = 0
    
    function buildPlayload(type,body) {
    	RpcId++
    	var header = "Type: request" + eol;
    	header = header + "RpcId: " + RpcId + eol;
    	header = header + "SchemaVersion: 17" + eol;
    	header = header + "Content-Type: application/json" + eol;
    	header = header + "RequestType: " + type + eol;
    	header = header + "ResponseCount: single" + eol;
    	header = header + "BodyId: " + eol;
    	header = header + "X-ApplicationName: Quicksilver" + eol;
    	header = header + "X-ApplicationVersion: 1.2" + eol;
    	header = header + "X-ApplicationSessionId: 0x" + sessionID + eol;
    	header = header + eol;
    
    	var bodyline = body + "\n"
    
    	var firstline = "MRPC/2 " + header.length + " " + bodyline.length + eol
    
    	return firstline + header + bodyline
    }
    
    
    function RPCRequest(payloadData, callback) {
    	var client = this;
    	var responseData = "";
    	var bodyAuth = buildPlayload('bodyAuthenticate', '{"type":"bodyAuthenticate","credential":{"type":"makCredential","key":"4685330376"}}');
    	var payload = buildPlayload(payloadData[0], payloadData[1])
    	
    	client.socket = tls.connect(options, function () {
    		client.socket.setEncoding('utf8');
    		client.socket.write(bodyAuth);
    		setTimeout(function () { client.socket.write(payload); }, 300);
    		
    		client.socket.on('data', function (chunk) {
    			callback(chunk);	
    		});
    		
    		client.socket.on('end', function () {
    			console.log("--------CONNECTION ENDED-----------")
    		});
    		
    		client.socket.on('error', function (err) {
    			console.log("Error during TLS request");
    			console.log(err);
    			client.socket.end();
    		});
    	
    	});
    }
    
    function parseTiVosMess(dataStream) { 
    	headerInfo = dataStream.split("\r\n", 1).toString()
    	version = (headerInfo.split(" ", 3))[0]
    	headerSize = parseInt((headerInfo.split(" ", 3))[1]) + headerInfo.length
    	bodySize = (headerInfo.split(" ", 3))[2]
    	body = JSON.parse(dataStream.substring(parseInt(headerSize), dataStream.length).trim());
    	return body
    }
    
    
    // Examples
    //var tivoReq = ['bodyAuthenticate', '{"type":"bodyAuthenticate","credential":{"type":"makCredential","key":"4685330376"}}']
    //var tivoReq = ['bodyConfigSearch', '{ "type": "bodyConfigSearch", "bodyId": ""}']
    //var tivoReq = ['recordingFolderItemSearch', '{"flatten":true,"offset":0,"bodyId":"tsn:xxxxxxxxxx","type":"recordingFolderItemSearch"}']
    //var tivoReq = ['offerSearch', '{"bodyId":"tsn:xxxxxxxxxx","type": "offerSearch","title": "The Daily Show","orderBy": ["startTime"]}']
    
    
    ///////////////////////////////
    ////
    //// TiVo Command Next Line
    ////
    /////////////////////////////////
    
    var tivoReq = ['recordingFolderItemSearch', '{"orderBy": ["startTime"],"type": "recordingFolderItemSearch","bodyId": "tsn:xxxxxxxxxx","note": ["recordingForChildRecordingId"],"parentRecordingFolderItemId": "tivo:rf.109822539"}']
    RPCRequest(tivoReq, function (daData) {
    	myJSON = parseTiVosMess(daData);
    	console.dir(myJSON);
    })
     

Share This Page

spam firewall

Advertisements