summaryrefslogtreecommitdiff
path: root/app.py
blob: f28864685617a227d865e03e3db0f6f8accafecd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/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):
		path = os.path.join(*path[1:])
		cache_path = File(path).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
		decoder = args.getvalue('decoder') if 'decoder' in args else None
		encoder = args.getvalue('encoder') if 'encoder' in args else None

		f = File(path)
		f.start_recode(decoder, encoder, environ['sessionid'])

		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')

		f = File(path)
		# TODO: replace this with some sane logic
		if not os.path.splitext(path)[1] in ('.mp3', '.ogg'):
			cache_path = f.get_cache_path()
			decoder, encoder = ('ffmpeg',)*2
			if not os.path.exists(cache_path):
				f.start_recode(decoder, encoder, environ['sessionid'])
			else:
				events.event_pub.play(environ['sessionid'], '/cache/{0}'.format(path))
		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()