diff options
Diffstat (limited to 'app.py')
-rwxr-xr-x | app.py | 112 |
1 files changed, 112 insertions, 0 deletions
@@ -0,0 +1,112 @@ +#!/usr/bin/env python2 + +import os, mimetypes, json, cgi, recode, time, urllib, events, threading + +from config import config +from directory import Directory, File + +class Application(object): + # Application handlers + + def files(self, environ, start_response, path): + full_path = os.path.join(config.get('music_root'), *path[1:]) + rel_path = os.path.join(*path[1:] or '.') + if os.path.isdir(full_path): + start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8')]) + return (str(x) for x in Directory(rel_path).listdir()) + else: + args = cgi.FieldStorage(environ = environ) + + decoder = args.getvalue('decoder') if 'decoder' in args else None + encoder = args.getvalue('encoder') if 'encoder' in args else None + + if decoder and encoder: + cache_file = File(rel_path).get_cache_file() + return File(cache_file, True).send(environ, start_response) + else: + return File(rel_path).send(environ, start_response) + + def static(self, environ, start_response, path): + filename = os.path.join('static', *path[1:]) + + if not os.access(filename, os.F_OK) or '..' in path: + start_response('404 Not Found', []) + return [] + + mime = mimetypes.guess_type(filename, strict = False)[0] or 'application/octet-stream' + start_response('200 OK', [('Content-Type', mime)]) + return open(filename, 'rb') + + + # JSON handlers + + def json_list(self, environ, start_response, path): + args = cgi.FieldStorage(environ = environ) + directory = args.getvalue('directory') if 'directory' in args else '/' + d = Directory(directory) + + contents = d.listdir() + + start_response('200 OK', [('Content-Type', 'text/plain')]) + s = json.dumps([x.json() for x in contents]) + return s + + def json_cache(self, environ, start_response, path): + args = cgi.FieldStorage(environ = environ) + path = args.getvalue('path') if 'path' in args else None + decoder = args.getvalue('decoder') if 'decoder' in args else None + encoder = args.getvalue('encoder') if 'encoder' in args else None + + f = File(path) + t = threading.Thread(target = f.recode, args = (decoder, encoder)) + t.start() + + start_response('200 OK', [('Content-Type', 'text/plain')]) + return [] + + def json_is_cached(self, environ, start_response, path): + args = cgi.FieldStorage(environ = environ) + path = args.getvalue('path') if 'path' in args else None + + cache_file = os.path.join(config.get('cache_dir'), path) + cache_file = os.path.splitext(cache_file)[0] + '.mp3' + + start_response('200 OK', [('Content-Type', 'text/plain')]) + return json.dumps(os.path.exists(cache_file)) + + handlers = { + 'files': files, + 'static': static, + 'list': json_list, + 'cache': json_cache, + 'is_cached': json_is_cached, + 'events': events.EventSubscriber, + } + + # WSGI handler + + def __call__(self, environ, start_response): + path = urllib.unquote(environ['PATH_INFO']) + path = path.split('/')[1:] + module = path[0] or None + if not module: + module = 'static' + path = ['static', 'index.html'] + + if module in self.handlers: + return self.handlers[module](self, environ, start_response, path) + + start_response('404 Not Found', [('Content-Type', 'text/plain')]) + return [str(path)] + +if __name__ == '__main__': + import sys + if len(sys.argv) == 3: + from flup.server.fcgi import WSGIServer + WSGIServer(Application(), bindAddress = (sys.argv[1], int(sys.argv[2]))).run() + else: + from wsgiref.simple_server import make_server, WSGIServer + # enable IPv6 + WSGIServer.address_family |= 10 + httpd = make_server('', 8000, Application()) + httpd.serve_forever() |