diff --git a/README.md b/README.md index ee6f7e7..85a22a5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Stream some music. ## Requirements Python 3.6+ FFmpeg compiled with `--enable-libopus` -Python packages: `flask gunicorn mutagen` +Python packages: `flask gunicorn mutagen Flask-RESTful` ## Install 1. Get on the floor diff --git a/musik.py b/musik.py index 31fd2b1..0753bc3 100755 --- a/musik.py +++ b/musik.py @@ -9,6 +9,7 @@ import subprocess from urllib import parse from flask import Flask, Response, render_template, send_file +from flask_restful import reqparse, abort, Api, Resource import mutagen MUSIC_DIR = "/mnt/music/Music" @@ -71,18 +72,73 @@ def init_library(): app = Flask(__name__) +api = Api(app) tracks = init_library() @app.route('/') def index(): """Main index page.""" - nav_items = list(set(t.artist for t in tracks)) - nav_items.sort() - nav_items = [item + '/' for item in nav_items] - cd = "/" + artist = list(set(t.artist for t in tracks)) + artist.sort() return render_template('index.html', **locals()) +parser = reqparse.RequestParser() +parser.add_argument('artist') +parser.add_argument('album') +parser.add_argument('track') + +def validate_select_args(args): + """ + If a track is specified, both artist and album must also be specified. + If an album is specified, the artist must also be specified. + """ + if args.get('track'): + if not args.get('artist') or not args.get('album'): + abort(400, message="Artist and album must also be specified.") + elif args.get('album'): + if not args.get('artist'): + abort(400, message="Artist must also be specified.") + elif not args.get('artist'): + abort(400, message="You must specify at least an artist.") + +class Selection(Resource): + def get(self): + global tracks + args = parser.parse_args() + print(args) + validate_select_args(args) + + if args.get('track'): + track = [t for t in tracks + if (t.title == args.get('track') and + t.album == args.get('album') and + t.artist == args.get('artist'))] + if not track: + abort(404, message="Track does not exist.") + else: + return vars(track[0]) + + elif args.get('album'): + tracks = [t for t in tracks + if (t.album == args.get('album') and + t.artist == args.get('artist'))] + if not tracks: + abort(404, message="Album does not exist.") + else: + return [t.title for t in tracks] + + elif args.get('artist'): + albums = list(set(t.album for t in tracks + if t.artist == args.get('artist'))) + if not albums: + abort(404, message="Artist does not exist.") + else: + return sorted(albums) + +api.add_resource(Selection, '/select') + + @app.route('/stream/') def stream(track): """View for the raw audio file.""" diff --git a/static/musik.css b/static/musik.css index 83d51a4..b937ae7 100644 --- a/static/musik.css +++ b/static/musik.css @@ -21,16 +21,41 @@ img { #navigationContainer { flex: auto; overflow: auto; + display: flex; + flex-direction: row; + height: 100%; border-top: 2px solid #ccc; border-bottom: 2px solid #ccc; } -#currentDirectory { - padding-left: 0.5em; +#selectArtistContainer { + height: 100%; + width: 100%; } -#navItems { - list-style-type: none; +#selectArtist { + height: 100%; + width: 100%; +} + +#selectAlbumContainer { + height: 100%; + width: 100%; +} + +#selectAlbum { + height: 100%; + width: 100%; +} + +#selectTrackContainer { + height: 100%; + width: 100%; +} + +#selectTrack { + height: 100%; + width: 100%; } #playerContainer { diff --git a/templates/index.html b/templates/index.html index f75e268..fd03ee0 100644 --- a/templates/index.html +++ b/templates/index.html @@ -10,12 +10,22 @@

Musik