#!/usr/bin/env python3 """ Music streaming. """ import os import json import random import subprocess from urllib import parse from flask import Flask, Response, render_template, send_file, url_for, request, abort import database import buckler_flask FFMPEG_CMD = [ 'ffmpeg', '-y', '-loglevel', 'panic', '-i', '', '-b:a', '64k', '-f', 'opus', '-' ] app = Flask(__name__) app.session_interface = buckler_flask.BucklerSessionInterface() app.before_request(buckler_flask.require_auth) database.init_database() @app.route('/') def index(): """Main index page.""" artists = database.get_all_artists() return render_template('index.html', **locals()) @app.route('/select') def select(): """Retrieve information about an artist, album or track.""" artist = request.args.get('artist') album = request.args.get('album') discnumber = request.args.get('discnumber') tracknumber = request.args.get('tracknumber') if tracknumber: result = database.get_track(artist, album, discnumber, tracknumber) if not result: return ("Valid artist, album, discnumber and tracknumber " "parameters must be supplied.") else: result.pop('filepath') elif album: result = database.get_album_tracks(artist, album) if not result: return "Valid artist and album parameters must be supplied." elif artist: result = database.get_artist_albums(artist) if not result: return "Valid artist parameter must be supplied." else: return "Invalid query." return json.dumps(result) @app.route('/select/random') def select_random(): """ Selects a random track. """ track = database.get_random_track() track.pop('filepath') return json.dumps(track) @app.route('/stream') def stream(): """View for the raw audio file.""" artist = parse.unquote(request.args.get('artist')) album = parse.unquote(request.args.get('album')) discnumber = parse.unquote(request.args.get('discnumber')) tracknumber = parse.unquote(request.args.get('tracknumber')) track = database.get_track(artist, album, discnumber, tracknumber) if not track: return "Track does not exist." FFMPEG_CMD[5] = track['filepath'] def generate(): with subprocess.Popen(FFMPEG_CMD, stdout=subprocess.PIPE) as proc: data = proc.stdout.read(1024) while data: yield data data = proc.stdout.read(1024) return Response(generate(), mimetype="audio/ogg") @app.route('/coverart') def coverart(): """View for the raw audio file.""" artist = parse.unquote(request.args.get('artist')) album = parse.unquote(request.args.get('album')) discnumber = parse.unquote(request.args.get('discnumber')) tracknumber = parse.unquote(request.args.get('tracknumber')) track = database.get_track(artist, album, discnumber, tracknumber) if not track: return "Track does not exist." cover_path = os.path.join(os.path.dirname(track['filepath']), 'folder.jpg') if os.path.isfile(cover_path): return send_file(cover_path) else: return "No cover art for this track found." if __name__ == "__main__": import sys if len(sys.argv) > 1: database.build_library(database.MUSIC_DIR) app.run(host='0.0.0.0', port=5150)