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