#!/usr/bin/env python2 import os, mimetypes, json, cgi, recode, time, urllib, events from config import config from directory import Directory, File from session import Session class Application(object): # Application handlers def files(self, environ, start_response, path): full_path = os.path.join(config.get('music_root'), *path[1:]) if not os.path.exists(full_path) or '..' in path: start_response('404 Not Found', []) return [] 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: 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.path.exists(filename) 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') def cache(self, environ, start_response, path): args = cgi.FieldStorage(environ = environ) path = os.path.join(*path[1:]) track = args.getvalue('track') if 'track' in args else None cache_path = File(path, track = track).get_cache_path() if not os.path.exists(cache_path) or '..' in path: start_response('404 Not Found', []) return [] f = File(cache_path, True) return f.send(environ, start_response) # 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_recode(self, environ, start_response, path): args = cgi.FieldStorage(environ = environ) path = args.getvalue('path') if 'path' in args else None track = args.getvalue('track') if 'track' in args else None f = File(path, track = track) # see json_play() if not os.path.splitext(path)[1] in ('.mp3', '.ogg'): decoder = 'ffmpeg' encoder = config.get('encoder') f.start_recode(decoder, encoder) start_response('200 OK', [('Content-Type', 'text/plain')]) return [] def json_play(self, environ, start_response, path): args = cgi.FieldStorage(environ = environ) path = args.getvalue('path') track = args.getvalue('track') if 'track' in args else None f = File(path, track = track) # TODO: replace this with some sane logic if not os.path.splitext(path)[1] in ('.mp3', '.ogg'): cache_path = f.get_cache_path() decoder = 'ffmpeg' encoder = config.get('encoder') if not os.path.exists(cache_path): f.start_recode(decoder, encoder, environ['sessionid']) else: events.event_pub.play(environ['sessionid'], '/cache/{0}{1}'.format(path, ('?track=' + track if track else ''))) else: events.event_pub.play(environ['sessionid'], '/files/{0}'.format(path)) start_response('200 OK', [('Content-Type', 'text/plain')]) return [] handlers = { 'files': files, 'static': static, 'cache': cache, 'list': json_list, 'recode': json_recode, 'play': json_play, '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 Session(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()