Moved log statment so it will work when there is an exception
[pyTivo.git] / mind.py
blob85dc569a7cfc5662dfa931a97177653207cd187a
1 import cookielib
2 import urllib2
3 import urllib
4 import struct
5 import httplib
6 import xml.etree.ElementTree as ElementTree
7 import time
10 class Mind:
11 def __init__(self, username, password, debug=False):
12 self.__username = username
13 self.__password = password
15 self.__debug = debug
17 self.__cj = cookielib.CookieJar()
18 self.__opener = urllib2.build_opener(urllib2.HTTPSHandler(debuglevel=1), urllib2.HTTPCookieProcessor(self.__cj))
20 self.__login()
22 if not self.__pcBodySearch():
23 self.__pcBodyStore('pyTivo', True)
25 def pushVideo(self, tsn, url, description='test', duration='40000', size='3000000', title='test', subtitle='test'):
27 # It looks like tivo only supports one pc per house
28 pc_body_id = self.__pcBodySearch()[0]
29 offer_id, content_id = self.__bodyOfferModify(tsn, pc_body_id, description, duration, size, title, subtitle, url)
30 self.__subscribe(offer_id, content_id, tsn)
32 def bodyOfferSchedule(self, pc_body_id):
34 data = {'pcBodyId' : pc_body_id,}
35 r = urllib2.Request(
36 '/Steph%27s%20Videos/The%20Fairly%20Odd%20Parents%20-%20Channel%20Chasers.xvid-pyro.avi',
37 dictcode(data),
38 {'Content-Type' : 'x-tivo/dict-binary'}
40 result = self.__opener.open(r)
42 self.__log('bodyOfferSchedule\n%s\n\n%sg' % (data, result))
44 return result.read()
46 def __log(self, message):
47 if self.__debug:
48 print message
49 print
51 def __login(self):
53 data = {
54 'cams_security_domain' : 'tivocom',
55 'cams_login_config' : 'http',
56 'cams_cb_username' : self.__username,
57 'cams_cb_password' : self.__password,
58 'cams_original_url' : '/mind/mind7?type=infoGet'
61 r = urllib2.Request(
62 'https://mind.tivo.com:8181/mind/login',
63 urllib.urlencode(data)
65 try:
66 result = self.__opener.open(r)
67 except:
68 pass
70 self.__log('__login\n%s' % (data))
72 def __bodyOfferModify(self, tsn, pc_body_id, description, duration, size, title, subtitle, url):
74 data = {
75 'bodyId' : 'tsn:' + tsn,
76 'description' : description,
77 'duration' : duration,
78 'encodingType' : 'mpeg2ProgramStream',
79 'partnerId' : 'tivo:pt.3187',
80 'pcBodyId' : pc_body_id,
81 'publishDate' : time.strftime('%Y-%m-%d %H:%M%S', time.gmtime()),
82 'size' : size,
83 'source' : 'file:/C%3A%2FDocuments%20and%20Settings%2FStephanie%2FDesktop%2FVideo',
84 'state' : 'complete',
85 'subtitle' : subtitle,
86 'title' : title,
87 'url' : url,
89 r = urllib2.Request(
90 'https://mind.tivo.com:8181/mind/mind7?type=bodyOfferModify&bodyId=tsn:' + tsn,
91 dictcode(data),
92 {'Content-Type' : 'x-tivo/dict-binary'}
94 result = self.__opener.open(r)
96 xml = ElementTree.parse(result).find('.')
98 self.__log('__bodyOfferModify\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
100 if xml.findtext('state') != 'complete':
101 raise Exception(ElementTree.tostring(xml))
103 offer_id = xml.findtext('offerId')
104 content_id = offer_id.replace('of','ct')
106 return offer_id, content_id
109 def __subscribe(self, offer_id, content_id, tsn):
110 data = {
111 'bodyId' : 'tsn:' + tsn,
112 'idSetSource' : {
113 'contentId': content_id,
114 'offerId' : offer_id,
115 'type' : 'singleOfferSource',
117 'title' : 'pcBodySubscription',
118 'uiType' : 'cds',
121 r = urllib2.Request(
122 'https://mind.tivo.com:8181/mind/mind7?type=subscribe&bodyId=tsn:' + tsn,
123 dictcode(data),
124 {'Content-Type' : 'x-tivo/dict-binary'}
126 result = self.__opener.open(r)
128 xml = ElementTree.parse(result).find('.')
130 self.__log('__subscribe\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
132 return xml
134 def __pcBodySearch(self):
136 data = {}
137 r = urllib2.Request(
138 'https://mind.tivo.com:8181/mind/mind7?type=pcBodySearch',
139 dictcode(data),
140 {'Content-Type' : 'x-tivo/dict-binary'}
142 result = self.__opener.open(r)
144 xml = ElementTree.parse(result).find('.')
147 self.__log('__pcBodySearch\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
149 return [id.text for id in xml.findall('pcBody/pcBodyId')]
151 def __collectionIdSearch(self, url):
153 data = {'url' : url}
154 r = urllib2.Request(
155 'https://mind.tivo.com:8181/mind/mind7?type=collectionIdSearch',
156 dictcode(data),
157 {'Content-Type' : 'x-tivo/dict-binary'}
159 result = self.__opener.open(r)
161 xml = ElementTree.parse( result ).find('.')
162 collection_id = xml.findtext('collectionId')
164 self.__log('__collectionIdSearch\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
166 return collection_id
168 def __pcBodyStore(self, name, replace=False):
170 data = {
171 'name' : name,
172 'replaceExisting' : str(replace).lower(),
175 r = urllib2.Request(
176 'https://mind.tivo.com:8181/mind/mind7?type=pcBodyStore',
177 dictcode(data),
178 {'Content-Type' : 'x-tivo/dict-binary'}
180 result = self.__opener.open(r)
182 xml = ElementTree.parse(result).find('.')
184 self.__log('__pcBodySearch\n%s\n\n%s' % (data, ElementTree.tostring(xml)))
186 return xml
189 def dictcode(d):
190 """Helper to create x-tivo/dict-binary"""
191 output = []
193 keys = [str(k) for k in d]
194 keys.sort()
196 for k in keys:
197 v = d[k]
199 l = len(k) | 128
200 output.append( struct.pack('>B', l) )
201 output.append( k )
203 if isinstance(v, dict):
204 output.append( struct.pack('>B', 0x02) )
205 output.append( dictcode(v) )
207 else:
208 v = str(v)
209 output.append( struct.pack('>B', 0x01) )
210 l = len(v) | 128
211 output.append( struct.pack('>B', l) )
212 output.append( v )
214 output.append( struct.pack('>B', 0x00) )
216 output.append( struct.pack('>B', 0x80) )
218 return ''.join(output)
221 if __name__ == '__main__':
222 username = 'armooo@armooo.net'
223 password = 'in(into)'
224 tsn = '6520001802C0F2A'
225 url = 'http://10.0.1.52:9032/Steph%27s%20Videos/Weekend%20%28Godard%201967%29.avi'
227 mind = Mind(username, password, True)
228 mind.pushVideo(tsn, url)