2018-09-12 13:04:00 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
Music streaming.
|
|
|
|
"""
|
2018-09-13 14:22:27 -04:00
|
|
|
import os
|
|
|
|
import json
|
2018-09-14 08:02:24 -04:00
|
|
|
import random
|
2018-09-12 13:04:00 -04:00
|
|
|
import subprocess
|
2018-09-13 14:22:27 -04:00
|
|
|
from urllib import parse
|
2018-09-12 13:04:00 -04:00
|
|
|
|
2018-09-20 10:00:07 -04:00
|
|
|
from flask import Flask, Response, render_template, send_file
|
2018-09-13 14:22:27 -04:00
|
|
|
from werkzeug.utils import secure_filename
|
2018-09-12 13:04:00 -04:00
|
|
|
|
2018-09-13 14:22:27 -04:00
|
|
|
MUSIC_DIR = "/mnt/music/Music"
|
2018-09-14 08:02:24 -04:00
|
|
|
MUSIC_EXT = ['flac', 'mp3', 'wav', 'm4a']
|
2018-09-12 13:04:00 -04:00
|
|
|
FFMPEG_CMD = [
|
|
|
|
'ffmpeg', '-y',
|
|
|
|
'-loglevel', 'panic',
|
|
|
|
'-i', '',
|
|
|
|
'-codec:a', 'libopus',
|
|
|
|
'-b:a', '64k',
|
|
|
|
'-f', 'opus',
|
|
|
|
'-'
|
|
|
|
]
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
|
def index():
|
|
|
|
"""Main index page."""
|
2018-09-13 14:22:27 -04:00
|
|
|
nav_items = os.listdir(MUSIC_DIR)
|
|
|
|
nav_items.sort()
|
|
|
|
nav_items = [item + '/' for item in nav_items]
|
|
|
|
initial_track = "/Accept/Accept - Balls to the Wall (1983) [FLAC] {74321 93214 2}/01 - Balls to the Wall.flac"
|
2018-09-20 10:00:07 -04:00
|
|
|
initial_cover = "/Accept/Accept - Balls to the Wall (1983) [FLAC] {74321 93214 2}/folder.jpg"
|
2018-09-13 14:22:27 -04:00
|
|
|
cd = "/"
|
|
|
|
return render_template('index.html', **locals())
|
2018-09-12 13:04:00 -04:00
|
|
|
|
|
|
|
|
2018-09-13 14:22:27 -04:00
|
|
|
@app.route('/stream/<path:track>')
|
2018-09-12 13:04:00 -04:00
|
|
|
def stream(track):
|
|
|
|
"""View for the raw audio file."""
|
2018-09-13 14:22:27 -04:00
|
|
|
path = os.path.join(MUSIC_DIR, track)
|
|
|
|
path = os.path.abspath(path)
|
|
|
|
if not path.startswith(MUSIC_DIR):
|
|
|
|
return "False"
|
|
|
|
if not os.path.isfile(path):
|
|
|
|
return "False"
|
|
|
|
FFMPEG_CMD[5] = path
|
2018-09-12 13:04:00 -04:00
|
|
|
|
|
|
|
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")
|
|
|
|
|
|
|
|
|
2018-09-13 14:22:27 -04:00
|
|
|
@app.route('/get_dir/<path:directory>/')
|
|
|
|
def get_dir(directory):
|
|
|
|
"""Returns the contents of the requested directory."""
|
|
|
|
directory = directory.replace("DOTDOT", "..")
|
|
|
|
directory = os.path.join(MUSIC_DIR, directory)
|
|
|
|
directory = os.path.abspath(directory)
|
|
|
|
if not directory.startswith(MUSIC_DIR):
|
|
|
|
return "False"
|
|
|
|
if not os.path.isdir(directory):
|
|
|
|
return "False"
|
|
|
|
|
|
|
|
nav_items = os.listdir(directory)
|
|
|
|
nav_items.sort()
|
|
|
|
if directory != MUSIC_DIR:
|
|
|
|
nav_items = [".."] + nav_items
|
|
|
|
|
|
|
|
nav_items_new = []
|
|
|
|
for item in nav_items:
|
|
|
|
if os.path.isdir(os.path.join(directory, item)):
|
|
|
|
item += '/'
|
|
|
|
nav_items_new.append(item)
|
|
|
|
nav_items_new = [directory.replace(MUSIC_DIR, '') + '/'] + nav_items_new
|
|
|
|
|
|
|
|
return json.dumps(nav_items_new)
|
|
|
|
|
|
|
|
|
2018-09-14 08:02:24 -04:00
|
|
|
@app.route('/get_shuffle')
|
|
|
|
def shuffle():
|
2018-09-20 10:00:07 -04:00
|
|
|
"""Returns a randomly selected track from the library."""
|
2018-09-14 08:02:24 -04:00
|
|
|
item = random.choice(os.listdir(MUSIC_DIR))
|
|
|
|
path = os.path.join(MUSIC_DIR, item)
|
2018-09-14 11:00:10 -04:00
|
|
|
n = 0
|
|
|
|
while not item.rpartition('.')[2] in MUSIC_EXT:
|
|
|
|
n += 1
|
2018-09-14 08:02:24 -04:00
|
|
|
item = random.choice(os.listdir(path))
|
|
|
|
if os.path.isdir(os.path.join(path, item)):
|
|
|
|
path = os.path.join(path, item)
|
2018-09-14 11:00:10 -04:00
|
|
|
if n == 5:
|
|
|
|
item = random.choice(os.listdir(MUSIC_DIR))
|
|
|
|
path = os.path.join(MUSIC_DIR, item)
|
|
|
|
n = 0
|
|
|
|
path = os.path.join(path, item)
|
2018-09-14 08:02:24 -04:00
|
|
|
return path.replace(MUSIC_DIR, '')
|
|
|
|
|
|
|
|
|
2018-09-20 10:00:07 -04:00
|
|
|
@app.route('/album_cover/<path:cover>')
|
|
|
|
def album_cover(cover):
|
|
|
|
"""View for the raw audio file."""
|
|
|
|
path = os.path.join(MUSIC_DIR, cover)
|
|
|
|
path = os.path.abspath(path)
|
|
|
|
if not path.startswith(MUSIC_DIR):
|
|
|
|
return "False"
|
|
|
|
if not os.path.isfile(path):
|
|
|
|
return "False"
|
|
|
|
|
|
|
|
return send_file(path)
|
|
|
|
|
|
|
|
|
2018-09-12 13:04:00 -04:00
|
|
|
if __name__ == "__main__":
|
|
|
|
app.run(host='0.0.0.0', port=5150)
|