From 5027df9739e905098ee65f26d8229a9c55f84925 Mon Sep 17 00:00:00 2001 From: Jason Michalski Date: Sun, 6 Apr 2008 00:54:26 -0500 Subject: [PATCH] Updated to support webvideo --- mind.py | 197 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 148 insertions(+), 49 deletions(-) diff --git a/mind.py b/mind.py index 7441373..86a9134 100644 --- a/mind.py +++ b/mind.py @@ -2,31 +2,32 @@ import cookielib import urllib2 import urllib import struct -import httplib +import httplib import time import warnings import itertools +import config try: - import xml.etree.ElementTree as ElementTree + import xml.etree.ElementTree as ElementTree except ImportError: try: import elementtree.ElementTree as ElementTree except ImportError: warnings.warn('Python 2.5 or higher or elementtree is needed to use the TivoPush') - + if 'ElementTree' not in locals(): class Mind: def __init__(self, *arg, **karg): raise Exception('Python 2.5 or higher or elementtree is needed to use the TivoPush') - + else: class Mind: def __init__(self, username, password, debug=False): self.__username = username - self.__password = password + self.__password = password self.__debug = debug @@ -38,26 +39,86 @@ else: if not self.__pcBodySearch(): self.__pcBodyStore('pyTivo', True) - def pushVideo(self, tsn, url, description='test', duration='40000', size='3000000', title='test', subtitle='test'): - + def pushVideo(self, tsn, url, description, duration, size, title, subtitle): + data = { + 'bodyId' : 'tsn:' + tsn, + 'description' : description, + 'duration' : duration, + 'encodingType' : 'mpeg2ProgramStream', + 'partnerId' : 'tivo:pt.3187', + 'pcBodyId' : pc_body_id, + 'publishDate' : time.strftime('%Y-%m-%d %H:%M%S', time.gmtime()), + 'size' : size, + 'source' : 'file:/C%3A%2FDocuments%20and%20Settings%2FStephanie%2FDesktop%2FVideo', + 'state' : 'complete', + 'subtitle' : subtitle, + 'title' : title, + 'url' : url, + } + # It looks like tivo only supports one pc per house pc_body_id = self.__pcBodySearch()[0] - offer_id, content_id = self.__bodyOfferModify(tsn, pc_body_id, description, duration, size, title, subtitle, url) + offer_id, content_id = self.__bodyOfferModify(data) self.__subscribe(offer_id, content_id, tsn) - def bodyOfferSchedule(self, pc_body_id): + def getDownloadRequests(self): + NEEDED_VALUES = [ + 'bodyId', + 'bodyOfferId', + 'description', + 'partnerId', + 'pcBodyId', + 'publishDate', + 'source', + 'state', + 'subscriptionId', + 'subtitle', + 'title', + 'url', + ] - data = {'pcBodyId' : pc_body_id,} - r = urllib2.Request( - '/Steph%27s%20Videos/The%20Fairly%20Odd%20Parents%20-%20Channel%20Chasers.xvid-pyro.avi', - dictcode(data), - {'Content-Type' : 'x-tivo/dict-binary'} - ) - result = self.__opener.open(r) + # It looks like tivo only supports one pc per house + pc_body_id = self.__pcBodySearch()[0] + + requests = [] + offer_list = self.__bodyOfferSchedule(pc_body_id) + + for offer in offer_list.findall('bodyOffer'): + d = {} + if offer.findtext('state') != 'scheduled': + continue + + for n in NEEDED_VALUES: + d[n] = offer.findtext(n) + requests.append(d) + + return requests + + def completeDownloadRequest(self, request): + request['encodingType'] = 'mpeg2ProgramStream' + request['state'] = 'complete' + request['type'] = 'bodyOfferModify' + request['updateDate'] = time.strftime('%Y-%m-%d %H:%M%S', time.gmtime()) + + offer_id, content_id = self.__bodyOfferModify(request) + self.__subscribe(offer_id, content_id, request['bodyId'][4:]) + + + def getXMPPLoginInfo(self): + # It looks like tivo only supports one pc per house + pc_body_id = self.__pcBodySearch()[0] - self.__log('bodyOfferSchedule\n%s\n\n%sg' % (data, result)) + xml = self.__bodyXmppInfoGet(pc_body_id) - return result.read() + results = {} + results['server'] = xml.findtext('server') + results['port'] = int(xml.findtext('port')) + results['username'] = xml.findtext('xmppId') + + for sendPresence in xml.findall('sendPresence'): + results.setdefault('presence_list', []).append(sendPresence.text) + + return results def __log(self, message): if self.__debug: @@ -75,7 +136,7 @@ else: } r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/login', + 'https://mind.tivo.com:8181/mind/login', urllib.urlencode(data) ) try: @@ -85,32 +146,17 @@ else: self.__log('__login\n%s' % (data)) - def __bodyOfferModify(self, tsn, pc_body_id, description, duration, size, title, subtitle, url): - - data = { - 'bodyId' : 'tsn:' + tsn, - 'description' : description, - 'duration' : duration, - 'encodingType' : 'mpeg2ProgramStream', - 'partnerId' : 'tivo:pt.3187', - 'pcBodyId' : pc_body_id, - 'publishDate' : time.strftime('%Y-%m-%d %H:%M%S', time.gmtime()), - 'size' : size, - 'source' : 'file:/C%3A%2FDocuments%20and%20Settings%2FStephanie%2FDesktop%2FVideo', - 'state' : 'complete', - 'subtitle' : subtitle, - 'title' : title, - 'url' : url, - } + def __bodyOfferModify(self, data): + """Create an offer""" r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/mind7?type=bodyOfferModify&bodyId=tsn:' + tsn, + 'https://mind.tivo.com:8181/mind/mind7?type=bodyOfferModify&bodyId=' + data['bodyId'], dictcode(data), {'Content-Type' : 'x-tivo/dict-binary'} ) result = self.__opener.open(r) xml = ElementTree.parse(result).find('.') - + self.__log('__bodyOfferModify\n%s\n\n%sg' % (data, ElementTree.tostring(xml))) if xml.findtext('state') != 'complete': @@ -123,6 +169,7 @@ else: def __subscribe(self, offer_id, content_id, tsn): + """Push the offer to the tivo""" data = { 'bodyId' : 'tsn:' + tsn, 'idSetSource' : { @@ -133,9 +180,9 @@ else: 'title' : 'pcBodySubscription', 'uiType' : 'cds', } - + r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/mind7?type=subscribe&bodyId=tsn:' + tsn, + 'https://mind.tivo.com:8181/mind/mind7?type=subscribe&bodyId=tsn:' + tsn, dictcode(data), {'Content-Type' : 'x-tivo/dict-binary'} ) @@ -147,11 +194,29 @@ else: return xml + def __bodyOfferSchedule(self, pc_body_id): + """Get pending stuff for this pc""" + + data = {'pcBodyId' : pc_body_id,} + r = urllib2.Request( + 'https://mind.tivo.com:8181/mind/mind7?type=bodyOfferSchedule', + dictcode(data), + {'Content-Type' : 'x-tivo/dict-binary'} + ) + result = self.__opener.open(r) + + xml = ElementTree.parse(result).find('.') + + self.__log('bodyOfferSchedule\n%s\n\n%sg' % (data, ElementTree.tostring(xml))) + + return xml + def __pcBodySearch(self): + """Find PCS""" data = {} r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/mind7?type=pcBodySearch', + 'https://mind.tivo.com:8181/mind/mind7?type=pcBodySearch', dictcode(data), {'Content-Type' : 'x-tivo/dict-binary'} ) @@ -165,10 +230,11 @@ else: return [id.text for id in xml.findall('pcBody/pcBodyId')] def __collectionIdSearch(self, url): + """Find collection ids""" data = {'url' : url} r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/mind7?type=collectionIdSearch', + 'https://mind.tivo.com:8181/mind/mind7?type=collectionIdSearch', dictcode(data), {'Content-Type' : 'x-tivo/dict-binary'} ) @@ -182,15 +248,16 @@ else: return collection_id def __pcBodyStore(self, name, replace=False): - + """Setup a new PC""" + data = { 'name' : name, 'replaceExisting' : str(replace).lower(), } r = urllib2.Request( - 'https://mind.tivo.com:8181/mind/mind7?type=pcBodyStore', - dictcode(data), + 'https://mind.tivo.com:8181/mind/mind7?type=pcBodyStore', + dictcode(data), {'Content-Type' : 'x-tivo/dict-binary'} ) result = self.__opener.open(r) @@ -201,6 +268,26 @@ else: return xml + def __bodyXmppInfoGet(self, body_id): + + data = { + 'bodyId' : body_id, + } + + r = urllib2.Request( + 'https://mind.tivo.com:8181/mind/mind7?type=bodyXmppInfoGet&bodyId=' + body_id, + dictcode(data), + {'Content-Type' : 'x-tivo/dict-binary'} + ) + + result = self.__opener.open(r) + + xml = ElementTree.parse(result).find('.') + + self.__log('__bodyXmppInfoGe\n%s\n\n%s' % (data, ElementTree.tostring(xml))) + + return xml + def dictcode(d): """Helper to create x-tivo/dict-binary""" @@ -220,9 +307,9 @@ else: output.append( dictcode(v) ) else: - v = str(v) + v = unicode(v).encode('utf-8') output.append( struct.pack('>B', 0x01) ) - output.append( varint( len(v) ) ) + output.append( varint( len(v) ) ) output.append( v ) output.append( struct.pack('>B', 0x00) ) @@ -238,7 +325,7 @@ else: while i: bits.append(i & 0x01) i = i >> 1 - + if not bits: output = [0] else: @@ -248,7 +335,7 @@ else: byte = 0 mybits = bits[:7] del bits[:7] - + for bit, p in zip(mybits, itertools.count()): byte += bit * (2 ** p) @@ -257,3 +344,15 @@ else: output[-1] = output[-1] | 0x80 return ''.join([chr(b) for b in output]) + +def getMind(): + username = config.getTivoUsername() + password = config.getTivoPassword() + + if not username or not password: + raise Exception("tivo_username and tivo_password required") + + m = Mind(username, password, True) + + return m + -- 2.11.4.GIT