Thread function to download from TiVo
[pyTivo/krkeegan.git] / plugins / admin / admin.py
blobd732e8e031b111f99756c5d6aaee40f27fc10cdb
1 import os, socket, re, sys, ConfigParser, config, time
2 import urllib2, cookielib, thread
3 from xml.dom import minidom
4 from ConfigParser import NoOptionError
5 from Cheetah.Template import Template
6 from plugin import Plugin
7 from urllib import unquote_plus, quote, unquote
8 from xml.sax.saxutils import escape
9 from lrucache import LRUCache
11 SCRIPTDIR = os.path.dirname(__file__)
13 CLASS_NAME = 'Admin'
15 p = os.path.dirname(__file__)
16 p = p.split(os.path.sep)
17 p.pop()
18 p.pop()
19 p = os.path.sep.join(p)
20 config_file_path = os.path.join(p, 'pyTivo.conf')
22 status = {}
24 class Admin(Plugin):
25 CONTENT_TYPE = 'text/html'
27 def Reset(self, handler, query):
28 config.reset()
29 handler.server.reset()
31 subcname = query['Container'][0]
32 cname = subcname.split('/')[0]
33 handler.send_response(200)
34 handler.end_headers()
35 t = Template(file=os.path.join(SCRIPTDIR,'templates', 'redirect.tmpl'))
36 t.container = cname
37 t.text = '<h3>The pyTivo Server has been soft reset.</h3> <br>pyTivo has reloaded the pyTivo.conf file and all changed should now be in effect.'
38 handler.wfile.write(t)
40 def Admin(self, handler, query):
41 #Read config file new each time in case there was any outside edits
42 config = ConfigParser.ConfigParser()
43 config.read(config_file_path)
45 shares_data = []
46 for section in config.sections():
47 if not(section.startswith('_tivo_') or section.startswith('Server')):
48 if not(config.has_option(section,'type')):
49 shares_data.append((section, dict(config.items(section, raw=True))))
50 elif config.get(section,'type').lower() != 'admin':
51 shares_data.append((section, dict(config.items(section, raw=True))))
53 subcname = query['Container'][0]
54 cname = subcname.split('/')[0]
55 handler.send_response(200)
56 handler.end_headers()
57 t = Template(file=os.path.join(SCRIPTDIR,'templates', 'settings.tmpl'))
58 t.container = cname
59 t.server_data = dict(config.items('Server', raw=True))
60 t.server_known = ["port", "guid", "ffmpeg", "beacon", "hack83", "debug", \
61 "optres", "audio_br", "video_br", "max_video_br", "width",\
62 "height", "ffmpeg_prams", "bufsize", "precache"]
63 t.shares_data = shares_data
64 t.shares_known = ["type", "path", "auto_subshares"]
65 t.tivos_data = [ (section, dict(config.items(section, raw=True))) for section in config.sections() \
66 if section.startswith('_tivo_')]
67 t.tivos_known = ["aspect169", "audio_br", "video_br", "width", "height", "ffmpeg_prams", "shares"]
68 handler.wfile.write(t)
70 def UpdateSettings(self, handler, query):
71 config = ConfigParser.ConfigParser()
72 config.read(config_file_path)
73 for key in query:
74 if key.startswith('Server.'):
75 section, option = key.split('.')
76 if option == "new__setting":
77 new_setting = query[key][0]
78 continue
79 if option == "new__value":
80 new_value = query[key][0]
81 continue
82 if query[key][0] == " ":
83 config.remove_option(section, option)
84 else:
85 config.set(section, option, query[key][0])
86 if not(new_setting == ' ' and new_value == ' '):
87 config.set('Server', new_setting, new_value)
89 sections = query['Section_Map'][0].split(']')
90 sections.pop() #last item is junk
91 for section in sections:
92 ID, name = section.split('|')
93 if query[ID][0] == "Delete_Me":
94 config.remove_section(name)
95 continue
96 if query[ID][0] != name:
97 config.remove_section(name)
98 config.add_section(query[ID][0])
99 for key in query:
100 if key.startswith(ID + '.'):
101 junk, option = key.split('.')
102 if option == "new__setting":
103 new_setting = query[key][0]
104 continue
105 if option == "new__value":
106 new_value = query[key][0]
107 continue
108 if query[key][0] == " ":
109 config.remove_option(query[ID][0], option)
110 else:
111 config.set(query[ID][0], option, query[key][0])
112 if not(new_setting == ' ' and new_value == ' '):
113 config.set(query[ID][0], new_setting, new_value)
114 if query['new_Section'][0] != " ":
115 config.add_section(query['new_Section'][0])
116 f = open(config_file_path, "w")
117 config.write(f)
118 f.close()
120 subcname = query['Container'][0]
121 cname = subcname.split('/')[0]
122 handler.send_response(200)
123 handler.end_headers()
124 t = Template(file=os.path.join(SCRIPTDIR,'templates', 'redirect.tmpl'))
125 t.container = cname
126 t.text = '<h3>Your Settings have been saved.</h3> <br>You settings have been saved to the pyTivo.conf file. However you will need to do a <b>Soft Reset</b> before these changes will take effect.'
127 handler.wfile.write(t)
129 def NPL(self, handler, query):
130 folder = '/NowPlaying'
131 if 'Folder' in query:
132 folder += '/' + str(query['Folder'][0])
133 theurl = 'https://192.168.1.150/TiVoConnect?Command=QueryContainer&Container=' + folder
135 password = '' #TiVo MAK
137 r=urllib2.Request(theurl)
138 auth_handler = urllib2.HTTPDigestAuthHandler()
139 auth_handler.add_password('TiVo DVR', '192.168.1.150', 'tivo', password)
140 opener = urllib2.build_opener(auth_handler)
141 urllib2.install_opener(opener)
143 try:
144 handle = urllib2.urlopen(r)
145 except IOError, e:
146 print "Possibly wrong Media Access Key, or IP address for your TiVo."
147 handler.send_response(404)
148 handler.end_headers()
149 return
150 thepage = handle.read()
152 xmldoc = minidom.parseString(thepage)
153 items = xmldoc.getElementsByTagName('Item')
155 data = []
156 for item in items:
157 entry = {}
158 entry['Title'] = item.getElementsByTagName("Title")[0].firstChild.data
159 entry['ContentType'] = item.getElementsByTagName("ContentType")[0].firstChild.data
160 if (len(item.getElementsByTagName("UniqueId")) >= 1):
161 entry['UniqueId'] = item.getElementsByTagName("UniqueId")[0].firstChild.data
162 if entry['ContentType'] == 'x-tivo-container/folder':
163 entry['TotalItems'] = item.getElementsByTagName("TotalItems")[0].firstChild.data
164 entry['LastChangeDate'] = item.getElementsByTagName("LastChangeDate")[0].firstChild.data
165 entry['LastChangeDate'] = time.strftime("%b %d, %Y", time.localtime(int(entry['LastChangeDate'], 16)))
166 else:
167 link = item.getElementsByTagName("Links")[0]
168 if (len(link.getElementsByTagName("CustomIcon")) >= 1):
169 entry['Icon'] = link.getElementsByTagName("CustomIcon")[0].getElementsByTagName("Url")[0].firstChild.data
170 keys = ['SourceSize', 'Duration', 'CaptureDate', 'EpisodeTitle', 'Description', 'SourceChannel', 'SourceStation']
171 for key in keys:
172 try:
173 entry[key] = item.getElementsByTagName(key)[0].firstChild.data
174 except:
175 entry[key] = ''
176 entry['SourceSize'] = "%.3f GB" % float(float(entry['SourceSize'])/(1024*1024*1024))
177 entry['Duration'] = str(int(entry['Duration'])/(60*60*1000)).zfill(2) + ':' \
178 + str((int(entry['Duration'])/60*1000)%60).zfill(2) + ':' \
179 + str((int(entry['Duration'])/1000)%60).zfill(2)
180 entry['CaptureDate'] = time.strftime("%b %d, %Y", time.localtime(int(entry['CaptureDate'], 16)))
182 data.append(entry)
184 subcname = query['Container'][0]
185 cname = subcname.split('/')[0]
186 handler.send_response(200)
187 handler.end_headers()
188 t = Template(file=os.path.join(SCRIPTDIR,'templates', 'npl.tmpl'))
189 t.subfolder = False
190 if folder != '/NowPlaying':
191 t.subfolder = True
192 t.container = cname
193 t.data = data
194 handler.wfile.write(t)
196 def ToGo(self, handler, query):
197 theurl = "http://192.168.1.150/download/Survivor%20Micronesia%20--%20Fans%20vs.%20Favorites.TiVo?Container=%2FNowPlaying&id=385244"
198 password = '' #TiVo MAK
199 tivoIP = '192.168.1.150'
200 outfile = "video.tivo"
202 status[theurl] = {'running':True, 'error':'', 'rate':''}
204 thread.start_new_thread(get_tivo_file, (theurl, password, tivoIP, outfile))
207 def get_tivo_file(url, mak, tivoIP, outfile):
208 global status
209 cj = cookielib.LWPCookieJar()
211 r=urllib2.Request(url)
212 auth_handler = urllib2.HTTPDigestAuthHandler()
213 auth_handler.add_password('TiVo DVR', tivoIP, 'tivo', mak)
214 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), auth_handler)
215 urllib2.install_opener(opener)
217 try:
218 handle = urllib2.urlopen(r)
219 except IOError, e:
220 #If we get "Too many transfers error" try a second time. For some reason
221 #urllib2 does not properly close connections when a transfer is canceled.
222 if e.code == 503:
223 try:
224 handle = urllib2.urlopen(r)
225 except IOError, e:
226 status[url]['running'] = False
227 status[url]['error'] = e.code
228 return
229 else:
230 status[url]['running'] = False
231 status[url]['error'] = e.code
232 return
234 f = open(outfile, 'wb')
235 kilobytes = 0
236 start_time = time.time()
237 output = handle.read(1024)
238 while status[url]['running'] and output != '':
239 kilobytes += 1
240 f.write(output)
241 if ((time.time() - start_time) >= 5):
242 status[url]['rate'] = int(kilobytes/(time.time() - start_time))
243 kilobytes = 0
244 start_time = time.time()
245 output = handle.read(1024)
246 status[url]['running'] = False
247 handle.close()
248 f.close()
249 return