wow asyncio (fix shit)
This commit is contained in:
parent
ec60817409
commit
e63652b0f7
2 changed files with 82 additions and 68 deletions
149
app.py
149
app.py
|
@ -1,3 +1,4 @@
|
|||
from asyncio.streams import StreamReader, StreamWriter
|
||||
import re
|
||||
from typing import Any, Mapping
|
||||
from flask import Flask, render_template, request, send_file, jsonify
|
||||
|
@ -6,9 +7,9 @@ import subprocess
|
|||
import signal
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import socket
|
||||
import json
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
|
||||
mpv_pidfile = Path(tempfile.gettempdir()).joinpath("laas_mpv.pidfile")
|
||||
mpv_socket = Path(tempfile.gettempdir()).joinpath("mpvsocket")
|
||||
|
@ -34,7 +35,7 @@ def cleanup_unclean():
|
|||
|
||||
|
||||
def shutdown(status: int = 0):
|
||||
playback_stop()
|
||||
mpv_stop()
|
||||
os._exit(status)
|
||||
|
||||
|
||||
|
@ -43,25 +44,36 @@ def sigh(signum: int, _frame):
|
|||
shutdown(status)
|
||||
|
||||
|
||||
def playback_start():
|
||||
async def mpv_start(args: list[str] = ["--idle"]):
|
||||
global mpv_process
|
||||
mpv_process = subprocess.Popen(
|
||||
[
|
||||
"mpv",
|
||||
f"--input-ipc-server={mpv_socket}",
|
||||
"--shuffle",
|
||||
# "--loop-playlist",
|
||||
"--no-video",
|
||||
f"--volume={volume}",
|
||||
str(music_path),
|
||||
*args,
|
||||
],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
open(mpv_pidfile, "w").write(str(mpv_process.pid))
|
||||
|
||||
while not mpv_socket.exists():
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
def playback_stop():
|
||||
|
||||
async def playback_start(args: list[str] = ["--idle"]):
|
||||
return await mpv_start(
|
||||
args=[
|
||||
"--shuffle",
|
||||
# "--loop-playlist",
|
||||
str(music_path),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def mpv_stop():
|
||||
global mpv_process
|
||||
if mpv_process is not None:
|
||||
mpv_process.terminate()
|
||||
|
@ -71,7 +83,7 @@ def playback_stop():
|
|||
mpv_pidfile.unlink()
|
||||
|
||||
|
||||
def is_playing():
|
||||
def mpv_running():
|
||||
global mpv_process
|
||||
running = mpv_process is not None
|
||||
if mpv_process is not None:
|
||||
|
@ -81,30 +93,33 @@ def is_playing():
|
|||
return running
|
||||
|
||||
|
||||
def mpv_socket_open() -> socket.socket | None:
|
||||
if is_playing():
|
||||
sock = socket.socket(socket.AF_UNIX)
|
||||
async def mpv_socket_open() -> tuple[StreamReader, StreamWriter] | None:
|
||||
async def socket_open_helper():
|
||||
while True:
|
||||
try:
|
||||
sock.connect(str(mpv_socket).encode())
|
||||
break
|
||||
except (ConnectionRefusedError, FileNotFoundError):
|
||||
return await asyncio.open_unix_connection(mpv_socket)
|
||||
except ConnectionRefusedError:
|
||||
pass
|
||||
|
||||
return sock
|
||||
if mpv_running():
|
||||
try:
|
||||
return await asyncio.wait_for(socket_open_helper(), timeout=3)
|
||||
except asyncio.TimeoutError:
|
||||
mpv_stop()
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def mpv_socket_command(
|
||||
sock: socket.socket, command: dict[str, Any]
|
||||
) -> Mapping[str, Any]:
|
||||
sock.send((json.dumps(command) + "\n").encode())
|
||||
async def mpv_socket_command(
|
||||
reader: StreamReader, writer: StreamWriter, command: dict[str, Any]
|
||||
) -> Mapping[str, Any] | None:
|
||||
if writer.is_closing():
|
||||
return
|
||||
|
||||
reply = b""
|
||||
while (data := sock.recv(1)) != b"\n":
|
||||
reply += data
|
||||
writer.write((json.dumps(command) + "\n").encode())
|
||||
await writer.drain()
|
||||
|
||||
reply = await reader.readline()
|
||||
return json.loads(reply.decode())
|
||||
|
||||
|
||||
|
@ -118,20 +133,20 @@ def sizeof_fmt(num, suffix="B"):
|
|||
|
||||
@app.route("/", methods=["GET"])
|
||||
def route_interface():
|
||||
return render_template("player.html", playing=is_playing())
|
||||
return render_template("player.html", playing=mpv_running())
|
||||
|
||||
|
||||
@app.route("/", methods=["POST"])
|
||||
def route_toggle():
|
||||
async def route_toggle():
|
||||
global mpv_process
|
||||
if is_playing():
|
||||
if mpv_running():
|
||||
print("Stopping Audio Playback..")
|
||||
playback_stop()
|
||||
mpv_stop()
|
||||
else:
|
||||
print("Starting Audio Playback..")
|
||||
playback_start()
|
||||
await playback_start()
|
||||
|
||||
return render_template("player.html", playing=is_playing())
|
||||
return render_template("player.html", playing=mpv_running())
|
||||
|
||||
|
||||
@app.route("/files/<path:path>", methods=["GET"])
|
||||
|
@ -156,33 +171,33 @@ def filemgr(path=""):
|
|||
|
||||
|
||||
@app.route("/api/start", methods=["POST"])
|
||||
def api_start():
|
||||
if is_playing():
|
||||
async def api_start():
|
||||
if mpv_running():
|
||||
return jsonify("Laas is already lofi'ing"), 400
|
||||
else:
|
||||
playback_start()
|
||||
await playback_start()
|
||||
return jsonify("ok"), 200
|
||||
|
||||
|
||||
@app.route("/api/stop", methods=["POST"])
|
||||
def api_stop():
|
||||
if not is_playing():
|
||||
if not mpv_running():
|
||||
return jsonify("You cant stop when theres no playback, womp womp!"), 400
|
||||
else:
|
||||
playback_stop()
|
||||
mpv_stop()
|
||||
return jsonify("ok"), 200
|
||||
|
||||
|
||||
@app.route("/api/status", methods=["GET"])
|
||||
def api_status():
|
||||
return jsonify(is_playing())
|
||||
return jsonify(mpv_running())
|
||||
|
||||
|
||||
@app.route("/api/nowplaying", methods=["GET"])
|
||||
def api_nowplaying():
|
||||
async def api_nowplaying():
|
||||
response: dict[str, Any] = {"status": "stopped"}
|
||||
|
||||
sock = mpv_socket_open()
|
||||
sock = await mpv_socket_open()
|
||||
if sock is not None:
|
||||
response["status"] = "playing"
|
||||
|
||||
|
@ -199,16 +214,21 @@ def api_nowplaying():
|
|||
else:
|
||||
key = prop
|
||||
|
||||
reply_json = mpv_socket_command(sock, {"command": ["get_property", prop]})
|
||||
reply_json = await mpv_socket_command(
|
||||
*sock, {"command": ["get_property", prop]}
|
||||
)
|
||||
if reply_json is None:
|
||||
break
|
||||
response[key] = reply_json["data"] if "data" in reply_json else "Unknown"
|
||||
|
||||
sock.close()
|
||||
sock[1].close()
|
||||
await sock[1].wait_closed()
|
||||
|
||||
return jsonify(response)
|
||||
|
||||
|
||||
@app.route("/api/play/<path:filename_or_url>", methods=["POST"])
|
||||
def api_play_file(
|
||||
async def api_play_file(
|
||||
filename_or_url: str, error_str: str = "Could not play file '{filename}'"
|
||||
):
|
||||
if re.match("^https?://.*", filename_or_url):
|
||||
|
@ -219,23 +239,19 @@ def api_play_file(
|
|||
return jsonify(error_str.format(filename=filename_or_url)), 404
|
||||
playback_uri = str(file_path)
|
||||
|
||||
if not is_playing():
|
||||
playback_start()
|
||||
if mpv_running():
|
||||
mpv_stop()
|
||||
|
||||
sock = mpv_socket_open()
|
||||
if sock is not None:
|
||||
mpv_socket_command(sock, {"command": ["loadfile", playback_uri]})
|
||||
sock.close()
|
||||
await mpv_start([playback_uri])
|
||||
|
||||
time.sleep(0.1)
|
||||
if is_playing():
|
||||
return jsonify("ok")
|
||||
if not mpv_running():
|
||||
return jsonify(error_str.format(filename=filename_or_url)), 500
|
||||
|
||||
return jsonify(error_str.format(filename=filename_or_url)), 500
|
||||
return jsonify("ok")
|
||||
|
||||
|
||||
@app.route("/api/play", methods=["POST"])
|
||||
def api_play_file2(error_str: str = "Could not play file '{filename}'"):
|
||||
async def api_play_file2(error_str: str = "Could not play file '{filename}'"):
|
||||
filename_or_url = request.get_data().decode()
|
||||
if re.match("^https?://.*", filename_or_url):
|
||||
playback_uri = filename_or_url
|
||||
|
@ -245,30 +261,26 @@ def api_play_file2(error_str: str = "Could not play file '{filename}'"):
|
|||
return jsonify(error_str.format(filename=filename_or_url)), 404
|
||||
playback_uri = str(file_path)
|
||||
|
||||
if not is_playing():
|
||||
playback_start()
|
||||
if mpv_running():
|
||||
mpv_stop()
|
||||
|
||||
sock = mpv_socket_open()
|
||||
if sock is not None:
|
||||
mpv_socket_command(sock, {"command": ["loadfile", playback_uri]})
|
||||
sock.close()
|
||||
await mpv_start([playback_uri])
|
||||
|
||||
time.sleep(0.1)
|
||||
if is_playing():
|
||||
return jsonify("ok")
|
||||
if not mpv_running():
|
||||
return jsonify(error_str.format(filename=filename_or_url)), 500
|
||||
|
||||
return jsonify(error_str.format(filename=filename_or_url)), 500
|
||||
return jsonify("ok")
|
||||
|
||||
|
||||
@app.route("/api/isengard", methods=["POST"])
|
||||
def api_isengard():
|
||||
return api_play_file(
|
||||
async def api_isengard():
|
||||
return await api_play_file(
|
||||
"isengard.mp3", error_str="Could not take the hobbits to Isengard"
|
||||
)
|
||||
|
||||
|
||||
@app.route("/api/volume", methods=["GET", "PUT"])
|
||||
def api_volume():
|
||||
async def api_volume():
|
||||
if request.method == "PUT":
|
||||
global volume
|
||||
try:
|
||||
|
@ -278,10 +290,11 @@ def api_volume():
|
|||
except Exception:
|
||||
return jsonify("bad volume"), 400
|
||||
|
||||
sock = mpv_socket_open()
|
||||
sock = await mpv_socket_open()
|
||||
if sock is not None:
|
||||
mpv_socket_command(sock, {"command": ["set", "volume", str(volume)]})
|
||||
sock.close()
|
||||
await mpv_socket_command(*sock, {"command": ["set", "volume", str(volume)]})
|
||||
sock[1].close()
|
||||
await sock[1].wait_closed()
|
||||
|
||||
return jsonify(volume)
|
||||
|
||||
|
@ -297,4 +310,4 @@ if __name__ == "__main__":
|
|||
try:
|
||||
app.run(host="::", port=1337)
|
||||
finally:
|
||||
playback_stop()
|
||||
mpv_stop()
|
||||
|
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
flask[async]
|
Loading…
Add table
Reference in a new issue