"""ABC notation utilities: MusicXML conversion and HTML visualization.""" import html as html_module import json import os import subprocess import tempfile from config import ABC2XML_PATH, APP_DIR def abc_to_musicxml_file(abc: str): """Convert ABC to MusicXML using abc2xml.py; return file path for download or None.""" if not (abc or "").strip(): return None try: result = subprocess.run( [os.environ.get("PYTHON", "python"), ABC2XML_PATH, "-"], input=(abc or "").strip().encode("utf-8"), capture_output=True, cwd=APP_DIR, timeout=30, ) if result.returncode != 0 or not result.stdout: return None xml_bytes = result.stdout if isinstance(xml_bytes, bytes): xml_str = xml_bytes.decode("utf-8", errors="replace") else: xml_str = xml_bytes tmpdir = tempfile.mkdtemp(prefix="musicxml_") score_path = os.path.join(tmpdir, "score.musicxml") try: with open(score_path, "w", encoding="utf-8") as f: f.write(xml_str) return score_path except Exception: try: os.unlink(score_path) except Exception: pass try: os.rmdir(tmpdir) except Exception: pass return None except Exception: return None def abc_viz_html(abc: str) -> str: """Generate HTML with ABCJS for rendering ABC notation in Gradio.""" viz_abc = abc or "" data_attr = html_module.escape(json.dumps(viz_abc), quote=True) # Gradio strips