Omit the "subtitle" field from pushes if empty -- no more empty strings
[pyTivo/wmcbrine.git] / httpserver.py
bloba3b9eda75cdfe3fec29ca576358c7bc6e00217af
1 import BaseHTTPServer
2 import SocketServer
3 import logging
4 import os
5 import re
6 import socket
7 import time
8 from cgi import parse_qs
9 from urllib import unquote_plus, quote, unquote
10 from urlparse import urlparse
11 from xml.sax.saxutils import escape
13 from Cheetah.Template import Template
14 import config
15 from plugin import GetPlugin
17 SCRIPTDIR = os.path.dirname(__file__)
19 class TivoHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
20 containers = {}
22 def __init__(self, server_address, RequestHandlerClass):
23 BaseHTTPServer.HTTPServer.__init__(self, server_address,
24 RequestHandlerClass)
25 self.daemon_threads = True
27 def add_container(self, name, settings):
28 if name in self.containers or name == 'TiVoConnect':
29 raise "Container Name in use"
30 try:
31 settings['content_type'] = GetPlugin(settings['type']).CONTENT_TYPE
32 self.containers[name] = settings
33 except KeyError:
34 print 'Unable to add container', name
36 def reset(self):
37 self.containers.clear()
38 for section, settings in config.getShares():
39 self.add_container(section, settings)
41 def set_beacon(self, beacon):
42 self.beacon = beacon
44 class TivoHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
45 tivos = {}
46 tivo_names = {}
48 def address_string(self):
49 host, port = self.client_address[:2]
50 return host
52 def do_GET(self):
53 tsn = self.headers.getheader('TiVo_TCD_ID',
54 self.headers.getheader('tsn', ''))
55 if tsn:
56 ip = self.address_string()
57 self.tivos[tsn] = ip
59 if not tsn in self.tivo_names:
60 self.tivo_names[tsn] = self.server.beacon.get_name(ip)
62 basepath = unquote_plus(self.path).split('/')[1]
64 ## Get File
65 for name, container in self.server.containers.items():
66 if basepath == name:
67 plugin = GetPlugin(container['type'])
68 plugin.send_file(self, container, name)
69 return
71 ## Not a file not a TiVo command fuck them
72 if not self.path.startswith('/TiVoConnect'):
73 self.infopage()
74 return
76 o = urlparse("http://fake.host" + self.path)
77 query = parse_qs(o[4])
79 mname = False
80 if 'Command' in query and len(query['Command']) >= 1:
82 command = query['Command'][0]
84 # If we are looking at the root container
85 if (command == "QueryContainer" and
86 (not 'Container' in query or query['Container'][0] == '/')):
87 self.root_container()
88 return
90 if 'Container' in query:
91 # Dispatch to the container plugin
92 basepath = unquote(query['Container'][0].split('/')[0])
93 for name, container in self.server.containers.items():
94 if basepath == name:
95 plugin = GetPlugin(container['type'])
96 if hasattr(plugin, command):
97 method = getattr(plugin, command)
98 method(self, query)
99 return
100 else:
101 break
103 # If we made it here it means we couldn't match the request to
104 # anything.
105 self.unsupported(query)
107 def root_container(self):
108 tsn = self.headers.getheader('TiVo_TCD_ID', '')
109 tsnshares = config.getShares(tsn)
110 tsncontainers = {}
111 for section, settings in tsnshares:
112 try:
113 settings['content_type'] = \
114 GetPlugin(settings['type']).CONTENT_TYPE
115 tsncontainers[section] = settings
116 except Exception, msg:
117 print section, '-', msg
118 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
119 'root_container.tmpl'))
120 t.containers = tsncontainers
121 t.hostname = socket.gethostname()
122 t.escape = escape
123 t.quote = quote
124 self.send_response(200)
125 self.end_headers()
126 self.wfile.write(t)
128 def infopage(self):
129 self.send_response(200)
130 self.send_header('Content-type', 'text/html')
131 self.end_headers()
132 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
133 'info_page.tmpl'))
134 t.admin = ''
135 for section, settings in config.getShares():
136 if 'type' in settings and settings['type'] == 'admin':
137 t.admin += ('<a href="/TiVoConnect?Command=Admin&Container=' +
138 quote(section) +
139 '">pyTivo Web Configuration</a><br>' +
140 '<a href="/TiVoConnect?Command=NPL&Container=' +
141 quote(section) + '">pyTivo ToGo</a><br>')
142 if t.admin == '':
143 t.admin = ('<br><b>No Admin plugin installed in pyTivo.conf</b>' +
144 '<br> If you wish to use the admin plugin add the ' +
145 'following lines to pyTivo.conf<br><br>' +
146 '[Admin]<br>type=admin')
148 t.shares = 'Video shares:<br/>'
149 for section, settings in config.getShares():
150 if settings.get('type') == 'video':
151 t.shares += ('<a href="TiVoConnect?Command=QueryContainer&' +
152 'Container=' + quote(section) + '">' + section +
153 '</a><br/>')
155 self.wfile.write(t)
157 def unsupported(self, query):
158 self.send_response(404)
159 self.send_header('Content-type', 'text/html')
160 self.end_headers()
161 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
162 'unsupported.tmpl'))
163 t.query = query
164 self.wfile.write(t)
166 if __name__ == '__main__':
167 def start_server():
168 httpd = TivoHTTPServer(('', 9032), TivoHTTPHandler)
169 httpd.add_container('test', 'x-container/tivo-videos',
170 r'C:\Documents and Settings\Armooo' +
171 r'\Desktop\pyTivo\test')
172 httpd.serve_forever()
174 start_server()