This is a work in progress. ```python #!/usr/bin/env python3 # Python 3 server example from http.server import BaseHTTPRequestHandler, HTTPServer from subprocess import run, PIPE import time import sys import re import json import os from datetime import datetime from threading import Thread import urllib.parse hostName = "" serverPort = 4097 def play_pause(): Thread(target = lambda: run(["mp","p"])).start() def mpc_vol(v): Thread(target = lambda: run(["mpc","vol",str(v)])).start() class Mpd: def __init__(self,bp,rp): self.bp = bp self.rp = rp self.port = bp+rp self.status = None self.running = False self.should_terminate = False def start(self): self.thread = Thread(target=self.task) self.thread.start() def join(self): return self.thread.join() def terminate(self): self.should_terminate = True def task(self): while not self.should_terminate: self.update_status() time.sleep(1) def parse_opts(self,a): # volume: 60% repeat: on random: on single: on consume: off b = re.split(r"\W{3,}",a) # the for x in b: k,v = x.split(": ") self.status[k] = v def update_status(self): m = run(["mpc","-p",str(self.port),"status"],stdout=PIPE,stderr=PIPE) if m.returncode == 0: self.running = True self.status = {} s = m.stdout.decode() l = s.splitlines() self.error = None if len(l) == 3: # paused/playing # Odysseus - Blackout - Synthwave but it gets dark # [playing] #1/3 45:21/46:52 (96%) # volume: 70% repeat: on random: off single: on consume: off self.track_name = l[0] if m := re.match(r"\[(\w+)\]\s+#(\d+)/(\d+)\s+(\d+):(\d+)/(\d+):(\d+)\s+\((\d+)%\)",l[1]): s,tn,tt,mc,sc,mt,st,pc = m.groups() mc, sc, mt, st, pc = map(int,(mc, sc, mt, st, pc)) if self.status is None: self.status = {} self.status["play_state"] = s self.status["track_index"] = tn self.status["track_total"] = tt self.status["current_position"] = (mc,sc) self.status["track_duration"] = (mt,st) self.status["percentage"] = pc else: self.error = "Fail to parse line 2" self.parse_opts(l[2]) elif len(l) == 1: # stopped # volume: n/a repeat: on random: on single: on consume: off self.parse_opts(l[0]) else: self.error = "mpc status parse error" else: self.error = m.stderr.decode() if not "Connection refused" in self.error: print(f"Error: {self.error}") self.running = False self.status = None def do_cmd(self,cmd): env = os.environ.copy() env["MPD_PORT"] = str(self.port) m = run(["mp"]+cmd,stdout=PIPE,env=env) return (m.returncode,m.stdout.decode()) class MpdMgr: def __init__(self,np=20,bp=6600): self.mpds = { i : Mpd(bp,i) for i in range(np) } for mpd in self.mpds.values(): mpd.start() def get_running(self): return { i : mpd.running for i, mpd in self.mpds.items() } def get_statuses(self): return { i : mpd.status for i, mpd in self.mpds.items() if mpd.running } def get_status(self,i): if i in self.mpds: return self.mpd[i].status return None def has(self,k): return k in self.mpds def __getitem__(self,k): if k in self.mpds: return self.mpds[k] else: return None class MyServer(BaseHTTPRequestHandler): def homepage(self): d = { "running": mpdmgr.get_running(), "status": mpdmgr.get_statuses(), "when": datetime.now().strftime("%c:") } self.send_as_json(d) def send_as_json(self,d,response_code=200): j = json.dumps(d) self.send_json(j,response_code) def send_json(self,j,response_code=200): self.send_response(response_code) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(bytes(j, "utf-8")) def do_GET(self): if self.path == "/favicon.ico": self.send_response(404) self.end_headers() self.wfile.write(b"No favicon") if self.path.strip("/") == "quit": if self.path.strip("/") == "": return self.homepage() print(datetime.now().strftime("%c:")) print(f"Request path: {self.path}") p = [urllib.parse.unquote(x) for x in self.path.strip("/").split("/")] # /10 -- get status of mpd 10 # /10/play -- send command "play" to mpd 10 # /10/volume/50 -- mp volume 50 if p[0].isnumeric(): i = int(p[0]) print(f"Index {i=}") print(f"{p=}") if not mpdmgr.has(i): print(f"Not in mpdmgr") self.send_response(404) self.end_headers() self.wfile.write(b"404") return mpd = mpdmgr[i] if len(p) == 1: print(f"Get status {i=}") sys.stdout.flush() d = { "running": mpd.running, "status": mpd.status, "when": datetime.now().strftime("%c:") } self.send_as_json(d) else: print(f"Command {p=}") sys.stdout.flush() cmd = p[1:] rc,o = mpd.do_cmd(p[1:]) d = { "returncode": rc, "output": rc, "when": datetime.now().strftime("%c:") } self.send_as_json(d) else: self.send_respose(400) self.end_headers() self.wfile.write(b"400") return if __name__ == "__main__": mpdmgr = MpdMgr(np=20) webServer = HTTPServer((hostName, serverPort), MyServer) print("Server started http://%s:%s" % (hostName, serverPort)) try: webServer.serve_forever() except KeyboardInterrupt: pass webServer.server_close() print("Server stopped.") ```