RESET_MSG is not used here.
[pyTivo/TheBayer.git] / plugins / togo / togo.py
blob2d2e10188fe622c07d1cfca328d4e48a8102a4ec
1 import cookielib
2 import logging
3 import os
4 import thread
5 import time
6 import urllib2
7 import urlparse
8 from urllib import quote, unquote
9 from xml.dom import minidom
11 from Cheetah.Template import Template
13 import config
14 from metadata import tag_data, from_container
15 from plugin import EncodeUnicode, Plugin
17 SCRIPTDIR = os.path.dirname(__file__)
19 CLASS_NAME = 'ToGo'
21 # Some error/status message templates
23 MISSING = """<h3>Missing Data.</h3> <br>
24 You must set both "tivo_mak" and "togo_path" before using this
25 function.<br>
26 The <a href="%s">ToGo</a> page
27 will reload in 10 seconds."""
29 TRANS_INIT = """<h3>Transfer Initiated.</h3> <br>
30 Your selected transfer has been initiated.<br>
31 The <a href="%s">ToGo</a> page
32 will reload in 3 seconds."""
34 TRANS_STOP = """<h3>Transfer Stopped.</h3> <br>
35 Your transfer has been stopped.<br>
36 The <a href="%s">ToGo</a> page
37 will reload in 3 seconds."""
39 UNABLE = """<h3>Unable to Connect to TiVo.</h3> <br>
40 pyTivo was unable to connect to the TiVo at %s</br>
41 This most likely caused by an incorrect Media Access Key. Please return
42 to the ToGo page and double check your Media Access Key.<br>
43 The <a href="%s">ToGo</a> page will
44 reload in 20 seconds."""
46 # Preload the templates
47 trname = os.path.join(SCRIPTDIR, 'templates', 'redirect.tmpl')
48 tnname = os.path.join(SCRIPTDIR, 'templates', 'npl.tmpl')
49 REDIRECT_TEMPLATE = file(trname, 'rb').read()
50 NPL_TEMPLATE = file(tnname, 'rb').read()
52 status = {} # Global variable to control download threads
53 tivo_cache = {} # Cache of TiVo NPL
55 class ToGo(Plugin):
56 CONTENT_TYPE = 'text/html'
58 def NPL(self, handler, query):
59 shows_per_page = 50 # Change this to alter the number of shows returned
60 cname = query['Container'][0].split('/')[0]
61 folder = ''
62 tivo_mak = config.get_server('tivo_mak')
63 togo_path = config.get_server('togo_path')
64 for name, data in config.getShares():
65 if togo_path == name:
66 togo_path = data.get('path')
68 if 'TiVo' in query:
69 tivoIP = query['TiVo'][0]
70 theurl = ('https://' + tivoIP +
71 '/TiVoConnect?Command=QueryContainer&ItemCount=' +
72 str(shows_per_page) + '&Container=/NowPlaying')
73 if 'Folder' in query:
74 folder += query['Folder'][0]
75 theurl += '/' + folder
76 if 'AnchorItem' in query:
77 theurl += '&AnchorItem=' + quote(query['AnchorItem'][0])
78 if 'AnchorOffset' in query:
79 theurl += '&AnchorOffset=' + query['AnchorOffset'][0]
81 r = urllib2.Request(theurl)
82 auth_handler = urllib2.HTTPDigestAuthHandler()
83 auth_handler.add_password('TiVo DVR', tivoIP, 'tivo', tivo_mak)
84 opener = urllib2.build_opener(auth_handler)
85 urllib2.install_opener(opener)
87 if (theurl not in tivo_cache or
88 (time.time() - tivo_cache[theurl]['thepage_time']) >= 60):
89 # if page is not cached or old then retreive it
90 try:
91 page = urllib2.urlopen(r)
92 except IOError, e:
93 t = Template(REDIRECT_TEMPLATE)
94 t.time = '20'
95 t.url = '/TiVoConnect?Command=NPL&Container=' + quote(cname)
96 t.text = UNABLE % t.url
97 handler.send_response(200)
98 handler.send_header('Content-Type', 'text/html')
99 handler.end_headers()
100 handler.wfile.write(t)
101 return
102 tivo_cache[theurl] = {'thepage': minidom.parse(page),
103 'thepage_time': time.time()}
104 page.close()
106 xmldoc = tivo_cache[theurl]['thepage']
107 items = xmldoc.getElementsByTagName('Item')
108 TotalItems = tag_data(xmldoc, 'Details/TotalItems')
109 ItemStart = tag_data(xmldoc, 'ItemStart')
110 ItemCount = tag_data(xmldoc, 'ItemCount')
111 FirstAnchor = tag_data(items[0], 'Links/Content/Url')
113 data = []
114 for item in items:
115 entry = {}
116 entry['ContentType'] = tag_data(item, 'ContentType')
117 for tag in ('CopyProtected', 'UniqueId'):
118 value = tag_data(item, tag)
119 if value:
120 entry[tag] = value
121 if entry['ContentType'] == 'x-tivo-container/folder':
122 entry['Title'] = tag_data(item, 'Title')
123 entry['TotalItems'] = tag_data(item, 'TotalItems')
124 lc = int(tag_data(item, 'LastChangeDate'), 16)
125 entry['LastChangeDate'] = time.strftime('%b %d, %Y',
126 time.localtime(lc))
127 else:
128 entry.update(from_container(item))
129 keys = {'Icon': 'Links/CustomIcon/Url',
130 'Url': 'Links/Content/Url',
131 'SourceSize': 'Details/SourceSize',
132 'Duration': 'Details/Duration',
133 'CaptureDate': 'Details/CaptureDate'}
134 for key in keys:
135 value = tag_data(item, keys[key])
136 if value:
137 entry[key] = value
139 entry['SourceSize'] = ( '%.3f GB' %
140 (float(entry['SourceSize']) / (1024 ** 3)) )
142 dur = int(entry['Duration']) / 1000
143 entry['Duration'] = ( '%02d:%02d:%02d' %
144 (dur / 3600, (dur % 3600) / 60, dur % 60) )
146 entry['CaptureDate'] = time.strftime('%b %d, %Y',
147 time.localtime(int(entry['CaptureDate'], 16)))
149 data.append(entry)
150 else:
151 data = []
152 tivoIP = ''
153 TotalItems = 0
154 ItemStart = 0
155 ItemCount = 0
156 FirstAnchor = ''
158 cname = query['Container'][0].split('/')[0]
159 t = Template(NPL_TEMPLATE, filter=EncodeUnicode)
160 t.quote = quote
161 t.folder = folder
162 t.status = status
163 t.tivo_mak = tivo_mak
164 t.togo_path = togo_path
165 t.tivos = config.tivos
166 t.tivo_names = config.tivo_names
167 t.tivoIP = tivoIP
168 t.container = cname
169 t.data = data
170 t.len = len
171 t.TotalItems = int(TotalItems)
172 t.ItemStart = int(ItemStart)
173 t.ItemCount = int(ItemCount)
174 t.FirstAnchor = quote(FirstAnchor)
175 t.shows_per_page = shows_per_page
176 t.my_url = handler.path
177 handler.send_response(200)
178 handler.send_header('Content-Type', 'text/html')
179 handler.end_headers()
180 handler.wfile.write(t)
182 def get_tivo_file(self, url, mak, togo_path):
183 # global status
184 cj = cookielib.LWPCookieJar()
186 parse_url = urlparse.urlparse(url)
188 name = unquote(parse_url[2])[10:].split('.')
189 name.insert(-1," - " + unquote(parse_url[4]).split("id=")[1] + ".")
190 outfile = os.path.join(togo_path, "".join(name))
192 r = urllib2.Request(url)
193 auth_handler = urllib2.HTTPDigestAuthHandler()
194 auth_handler.add_password('TiVo DVR', parse_url[1], 'tivo', mak)
195 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj),
196 auth_handler)
197 urllib2.install_opener(opener)
199 try:
200 handle = urllib2.urlopen(r)
201 except IOError, e:
202 status[url]['running'] = False
203 status[url]['error'] = e.code
204 return
206 f = open(outfile, 'wb')
207 length = 0
208 start_time = time.time()
209 try:
210 while status[url]['running']:
211 output = handle.read(1024000)
212 if not output:
213 break
214 length += len(output)
215 f.write(output)
216 now = time.time()
217 elapsed = now - start_time
218 if elapsed >= 5:
219 status[url]['rate'] = int(length / elapsed) / 1024
220 status[url]['size'] += length
221 length = 0
222 start_time = now
223 if status[url]['running']:
224 status[url]['finished'] = True
225 except Exception, msg:
226 logging.getLogger('pyTivo.togo').info(msg)
227 status[url]['running'] = False
228 handle.close()
229 f.close()
231 def ToGo(self, handler, query):
232 cname = query['Container'][0].split('/')[0]
233 tivoIP = query['TiVo'][0]
234 tivo_mak = config.get_server('tivo_mak')
235 togo_path = config.get_server('togo_path')
236 for name, data in config.getShares():
237 if togo_path == name:
238 togo_path = data.get('path')
239 t = Template(REDIRECT_TEMPLATE)
240 t.url = query['Redirect'][0]
241 params = (t.url)
242 if tivo_mak and togo_path:
243 theurl = query['Url'][0]
244 status[theurl] = {'running': True, 'error': '', 'rate': '',
245 'size': 0, 'finished': False}
246 thread.start_new_thread(ToGo.get_tivo_file,
247 (self, theurl, tivo_mak, togo_path))
248 t.time = '3'
249 t.text = TRANS_INIT % params
250 else:
251 t.time = '10'
252 t.text = MISSING % params
253 handler.send_response(200)
254 handler.send_header('Content-Type', 'text/html')
255 handler.end_headers()
256 handler.wfile.write(t)
258 def ToGoStop(self, handler, query):
259 theurl = query['Url'][0]
260 status[theurl]['running'] = False
262 cname = query['Container'][0].split('/')[0]
263 tivoIP = query['TiVo'][0]
264 t = Template(REDIRECT_TEMPLATE)
265 t.time = '3'
266 t.url = query['Redirect'][0]
267 t.text = TRANS_STOP % (t.url)
268 handler.send_response(200)
269 handler.send_header('Content-Type', 'text/html')
270 handler.end_headers()
271 handler.wfile.write(t)