2017-08-13 21:13:46 -07:00
|
|
|
import os
|
2017-08-13 18:42:16 -07:00
|
|
|
import logging
|
|
|
|
import cherrypy
|
2017-08-20 14:54:13 -07:00
|
|
|
from sqlite3 import IntegrityError
|
2017-08-13 18:56:13 -07:00
|
|
|
from pysonic.api import PysonicApi
|
2018-04-02 21:58:48 -07:00
|
|
|
from pysonic.library import PysonicLibrary
|
|
|
|
from pysonic.database import PysonicDatabase, DuplicateRootException
|
2017-08-13 18:42:16 -07:00
|
|
|
|
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
def main():
|
|
|
|
import argparse
|
|
|
|
import signal
|
2017-08-13 18:42:16 -07:00
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
parser = argparse.ArgumentParser(description="Pysonic music streaming server")
|
2017-08-13 18:42:16 -07:00
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
parser.add_argument('-p', '--port', default=8080, type=int, help="tcp port to listen on")
|
|
|
|
parser.add_argument('-d', '--dirs', required=True, nargs='+', help="new music dirs to share")
|
2017-08-15 20:26:03 -07:00
|
|
|
parser.add_argument('-u', '--user', nargs='+', type=lambda x: x.split(":"), default=[],
|
|
|
|
help="user:password pairs for auth")
|
|
|
|
parser.add_argument('--disable-auth', action="store_true", help="disable authentication")
|
2017-08-13 18:56:13 -07:00
|
|
|
parser.add_argument('-s', '--database-path', default="./db.sqlite", help="path to persistent sqlite database")
|
|
|
|
parser.add_argument('--debug', action="store_true", help="enable development options")
|
2017-08-13 22:08:40 -07:00
|
|
|
|
|
|
|
group = parser.add_argument_group("app options")
|
|
|
|
group.add_argument("--skip-transcode", action="store_true", help="instead of trancoding mp3s, send as-is")
|
2017-08-19 22:03:09 -07:00
|
|
|
group.add_argument("--no-rescan", action="store_true", help="don't perform simple scan on startup")
|
|
|
|
group.add_argument("--deep-rescap", action="store_true", help="perform deep scan (read id3 etc)")
|
|
|
|
group.add_argument("--enable-prune", action="store_true", help="enable removal of media not found on disk")
|
2017-08-13 22:08:40 -07:00
|
|
|
group.add_argument("--max-bitrate", type=int, default=320, help="maximum send bitrate")
|
2017-08-19 22:03:09 -07:00
|
|
|
group.add_argument("--enable-cors", action="store_true", help="add response headers to allow cors")
|
2017-08-13 22:08:40 -07:00
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
args = parser.parse_args()
|
2017-08-13 18:42:16 -07:00
|
|
|
|
2018-04-02 22:11:02 -07:00
|
|
|
logging.basicConfig(level=logging.INFO if args.debug else logging.WARNING,
|
|
|
|
format="%(asctime)-15s %(levelname)-8s %(filename)s:%(lineno)d %(message)s")
|
2017-08-13 18:42:16 -07:00
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
db = PysonicDatabase(path=args.database_path)
|
|
|
|
library = PysonicLibrary(db)
|
2017-08-13 21:13:46 -07:00
|
|
|
for dirname in args.dirs:
|
|
|
|
assert os.path.exists(dirname) and dirname.startswith("/"), "--dirs must be absolute paths and exist!"
|
|
|
|
try:
|
2018-04-02 22:11:02 -07:00
|
|
|
library.add_root_dir(dirname)
|
2017-08-13 21:13:46 -07:00
|
|
|
except DuplicateRootException:
|
|
|
|
pass
|
2017-08-13 18:56:13 -07:00
|
|
|
library.update()
|
2017-08-13 18:42:16 -07:00
|
|
|
|
2017-08-15 20:26:03 -07:00
|
|
|
for username, password in args.user:
|
2017-08-20 14:54:13 -07:00
|
|
|
try:
|
|
|
|
db.add_user(username, password)
|
|
|
|
except IntegrityError:
|
|
|
|
db.update_user(username, password)
|
2017-08-15 20:26:03 -07:00
|
|
|
|
2018-04-02 22:11:02 -07:00
|
|
|
# logging.warning("Libraries: {}".format([i["name"] for i in library.get_libraries()]))
|
|
|
|
# logging.warning("Artists: {}".format([i["name"] for i in library.get_artists()]))
|
|
|
|
# logging.warning("Albums: {}".format(len(library.get_albums())))
|
2017-08-13 21:13:46 -07:00
|
|
|
|
2017-08-15 21:40:38 -07:00
|
|
|
api = PysonicApi(db, library, args)
|
2017-08-15 20:26:03 -07:00
|
|
|
api_config = {}
|
|
|
|
if args.disable_auth:
|
|
|
|
logging.warning("starting up with auth disabled")
|
|
|
|
else:
|
2018-04-02 22:11:02 -07:00
|
|
|
def validate_password(realm, username, password):
|
|
|
|
print("I JUST VALIDATED {}:{} ({})".format(username, password, realm))
|
|
|
|
return True
|
|
|
|
|
2017-08-15 20:26:03 -07:00
|
|
|
api_config.update({'tools.auth_basic.on': True,
|
|
|
|
'tools.auth_basic.realm': 'pysonic',
|
2018-04-02 22:11:02 -07:00
|
|
|
'tools.auth_basic.checkpassword': validate_password})
|
2017-08-19 22:03:09 -07:00
|
|
|
if args.enable_cors:
|
|
|
|
def cors():
|
|
|
|
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
|
|
|
|
cherrypy.tools.cors = cherrypy.Tool('before_handler', cors)
|
|
|
|
api_config.update({'tools.cors.on': True})
|
|
|
|
|
2017-08-15 21:40:38 -07:00
|
|
|
cherrypy.tree.mount(api, '/rest/', {'/': api_config})
|
2017-08-15 20:26:03 -07:00
|
|
|
|
2017-08-13 18:42:16 -07:00
|
|
|
cherrypy.config.update({
|
|
|
|
'sessionFilter.on': True,
|
|
|
|
'tools.sessions.on': True,
|
|
|
|
'tools.sessions.locking': 'explicit',
|
|
|
|
'tools.sessions.timeout': 525600,
|
2017-08-13 21:13:46 -07:00
|
|
|
'tools.gzip.on': True,
|
2017-08-13 18:42:16 -07:00
|
|
|
'request.show_tracebacks': True,
|
2017-08-13 18:56:13 -07:00
|
|
|
'server.socket_port': args.port,
|
2017-08-13 18:42:16 -07:00
|
|
|
'server.thread_pool': 25,
|
|
|
|
'server.socket_host': '0.0.0.0',
|
|
|
|
'server.show_tracebacks': True,
|
|
|
|
'server.socket_timeout': 5,
|
|
|
|
'log.screen': False,
|
2017-08-13 18:56:13 -07:00
|
|
|
'engine.autoreload.on': args.debug
|
2017-08-13 18:42:16 -07:00
|
|
|
})
|
|
|
|
|
2017-08-13 18:56:13 -07:00
|
|
|
def signal_handler(signum, stack):
|
2017-08-13 21:13:46 -07:00
|
|
|
logging.critical('Got sig {}, exiting...'.format(signum))
|
2017-08-13 18:56:13 -07:00
|
|
|
cherrypy.engine.exit()
|
|
|
|
|
|
|
|
signal.signal(signal.SIGINT, signal_handler)
|
|
|
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
|
|
|
2017-08-13 18:42:16 -07:00
|
|
|
try:
|
|
|
|
cherrypy.engine.start()
|
|
|
|
cherrypy.engine.block()
|
|
|
|
finally:
|
2017-08-13 21:13:46 -07:00
|
|
|
logging.info("API has shut down")
|
2017-08-13 18:42:16 -07:00
|
|
|
cherrypy.engine.exit()
|
|
|
|
|
2018-04-02 22:11:02 -07:00
|
|
|
|
2017-08-13 18:42:16 -07:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|