Adding back in failed plugin errors
[pyTivo/krkeegan.git] / mind.py
blob825b368881689ccb3c2d563d25620b285977f2d7
1 import cookielib
2 import urllib2
3 import urllib
4 import struct
5 import httplib
6 import time
7 import warnings
9 try:
10 import xml.etree.ElementTree as ElementTree
11 except ImportError:
12 try:
13 import elementtree.ElementTree as ElementTree
14 except ImportError:
15 warnings.warn('Python 2.5 or higher or elementtree is needed to use the TivoPush')
17 if 'ElementTree' not in locals():
19 class Mind:
20 def __init__(self, *arg, **karg):
21 raise Exception('Python 2.5 or higher or elementtree is needed to use the TivoPush')
23 else:
25 class Mind:
26 def __init__(self, username, password, debug=False):
27 self.__username = username
28 self.__password = password
30 self.__debug = debug
32 self.__cj = cookielib.CookieJar()
33 self.__opener = urllib2.build_opener(urllib2.HTTPSHandler(debuglevel=1), urllib2.HTTPCookieProcessor(self.__cj))
35 self.__login()
37 if not self.__pcBodySearch():
38 self.__pcBodyStore('pyTivo', True)
40 def pushVideo(self, tsn, url, description='test', duration='40000', size='3000000', title='test', subtitle='test'):
42 # It looks like tivo only supports one pc per house
43 pc_body_id = self.__pcBodySearch()[0]
44 offer_id, content_id = self.__bodyOfferModify(tsn, pc_body_id, description, duration, size, title, subtitle, url)
45 self.__subscribe(offer_id, content_id, tsn)
47 def bodyOfferSchedule(self, pc_body_id):
49 data = {'pcBodyId' : pc_body_id,}
50 r = urllib2.Request(
51 '/Steph%27s%20Videos/The%20Fairly%20Odd%20Parents%20-%20Channel%20Chasers.xvid-pyro.avi',
52 dictcode(data),
53 {'Content-Type' : 'x-tivo/dict-binary'}
55 result = self.__opener.open(r)
57 self.__log('bodyOfferSchedule\n%s\n\n%sg' % (data, result))
59 return result.read()
61 def __log(self, message):
62 if self.__debug:
63 print message
64 print
66 def __login(self):
68 data = {
69 'cams_security_domain' : 'tivocom',
70 'cams_login_config' : 'http',
71 'cams_cb_username' : self.__username,
72 'cams_cb_password' : self.__password,
73 'cams_original_url' : '/mind/mind7?type=infoGet'
76 r = urllib2.Request(
77 'https://mind.tivo.com:8181/mind/login',
78 urllib.urlencode(data)
80 try:
81 result = self.__opener.open(r)
82 except:
83 pass
85 self.__log('__login\n%s' % (data))
87 def __bodyOfferModify(self, tsn, pc_body_id, description, duration, size, title, subtitle, url):
89 data = {
90 'bodyId' : 'tsn:' + tsn,
91 'description' : description,
92 'duration' : duration,
93 'encodingType' : 'mpeg2ProgramStream',
94 'partnerId' : 'tivo:pt.3187',
95 'pcBodyId' : pc_body_id,
96 'publishDate' : time.strftime('%Y-%m-%d %H:%M%S', time.gmtime()),
97 'size' : size,
98 'source' : 'file:/C%3A%2FDocuments%20and%20Settings%2FStephanie%2FDesktop%2FVideo',
99 'state' : 'complete',
100 'subtitle' : subtitle,
101 'title' : title,
102 'url' : url,
104 r = urllib2.Request(
105 'https://mind.tivo.com:8181/mind/mind7?type=bodyOfferModify&bodyId=tsn:' + tsn,
106 dictcode(data),
107 {'Content-Type' : 'x-tivo/dict-binary'}
109 result = self.__opener.open(r)
111 xml = ElementTree.parse(result).find('.')
113 self.__log('__bodyOfferModify\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
115 if xml.findtext('state') != 'complete':
116 raise Exception(ElementTree.tostring(xml))
118 offer_id = xml.findtext('offerId')
119 content_id = offer_id.replace('of','ct')
121 return offer_id, content_id
124 def __subscribe(self, offer_id, content_id, tsn):
125 data = {
126 'bodyId' : 'tsn:' + tsn,
127 'idSetSource' : {
128 'contentId': content_id,
129 'offerId' : offer_id,
130 'type' : 'singleOfferSource',
132 'title' : 'pcBodySubscription',
133 'uiType' : 'cds',
136 r = urllib2.Request(
137 'https://mind.tivo.com:8181/mind/mind7?type=subscribe&bodyId=tsn:' + tsn,
138 dictcode(data),
139 {'Content-Type' : 'x-tivo/dict-binary'}
141 result = self.__opener.open(r)
143 xml = ElementTree.parse(result).find('.')
145 self.__log('__subscribe\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
147 return xml
149 def __pcBodySearch(self):
151 data = {}
152 r = urllib2.Request(
153 'https://mind.tivo.com:8181/mind/mind7?type=pcBodySearch',
154 dictcode(data),
155 {'Content-Type' : 'x-tivo/dict-binary'}
157 result = self.__opener.open(r)
159 xml = ElementTree.parse(result).find('.')
162 self.__log('__pcBodySearch\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
164 return [id.text for id in xml.findall('pcBody/pcBodyId')]
166 def __collectionIdSearch(self, url):
168 data = {'url' : url}
169 r = urllib2.Request(
170 'https://mind.tivo.com:8181/mind/mind7?type=collectionIdSearch',
171 dictcode(data),
172 {'Content-Type' : 'x-tivo/dict-binary'}
174 result = self.__opener.open(r)
176 xml = ElementTree.parse( result ).find('.')
177 collection_id = xml.findtext('collectionId')
179 self.__log('__collectionIdSearch\n%s\n\n%sg' % (data, ElementTree.tostring(xml)))
181 return collection_id
183 def __pcBodyStore(self, name, replace=False):
185 data = {
186 'name' : name,
187 'replaceExisting' : str(replace).lower(),
190 r = urllib2.Request(
191 'https://mind.tivo.com:8181/mind/mind7?type=pcBodyStore',
192 dictcode(data),
193 {'Content-Type' : 'x-tivo/dict-binary'}
195 result = self.__opener.open(r)
197 xml = ElementTree.parse(result).find('.')
199 self.__log('__pcBodySearch\n%s\n\n%s' % (data, ElementTree.tostring(xml)))
201 return xml
204 def dictcode(d):
205 """Helper to create x-tivo/dict-binary"""
206 output = []
208 keys = [str(k) for k in d]
209 keys.sort()
211 for k in keys:
212 v = d[k]
214 l = len(k) | 128
215 output.append( struct.pack('>B', l) )
216 output.append( k )
218 if isinstance(v, dict):
219 output.append( struct.pack('>B', 0x02) )
220 output.append( dictcode(v) )
222 else:
223 v = str(v)
224 output.append( struct.pack('>B', 0x01) )
225 l = len(v) | 128
226 output.append( struct.pack('>B', l) )
227 output.append( v )
229 output.append( struct.pack('>B', 0x00) )
231 output.append( struct.pack('>B', 0x80) )
233 return ''.join(output)
236 if __name__ == '__main__':
237 username = 'armooo@armooo.net'
238 password = 'in(into)'
239 tsn = '6520001802C0F2A'
240 url = 'http://10.0.1.52:9032/Steph%27s%20Videos/Weekend%20%28Godard%201967%29.avi'
242 mind = Mind(username, password, True)
243 mind.pushVideo(tsn, url)