Files
avatar/plugins/musica.py
T
lucianoandClaude Fable 5.1 ff79832c30 AvatarPy: assistente personale con volto 3D, voce, memoria e plugin
Riscrittura in Python dell'assistente Avatar con interfaccia HUD (derivata da Mark LIV, CC BY-NC 4.0, vedi NOTICE.md).
Tre motori (Claude API, server locale OpenAI-compatibile, Claude Code), voce Kokoro/macOS, Whisper MLX,
avatar 3D con sincronizzazione labiale, memoria per categorie, allegati con OCR, monitor con avvisi,
plugin per Calendario, Mail, Promemoria, Note, Musica, app, Mac, timer, meteo, contatti, Messaggi,
file, Comandi Rapidi, browser, Telegram, WhatsApp (archivio e tempo reale).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 16:21:39 +02:00

95 lines
4.3 KiB
Python

"""Musica: controlla Apple Music (o Spotify, se aperto): riproduci, pausa, brano, playlist, volume."""
from __future__ import annotations
import subprocess
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from avatar.macos import osa # noqa: E402
def _running(name: str) -> bool:
return subprocess.run(["pgrep", "-x", name], capture_output=True).returncode == 0
def _app(launch: bool = False) -> str | None:
"""App musicale in uso: Spotify se è l'unica aperta, altrimenti Musica (avviata se launch=True)."""
if _running("Spotify") and not _running("Music"):
return "Spotify"
if _running("Music"):
return "Music"
if launch:
subprocess.run(["open", "-a", "Music"], check=False, timeout=15)
for _ in range(20):
if _running("Music"):
time.sleep(2)
return "Music"
time.sleep(0.5)
return None
def controllo(params: dict, ctx: dict) -> str:
azione = str(params.get("azione", "")).lower()
app = _app(launch=azione in ("play", "riproduci"))
if app is None:
return "Nessuna app musicale aperta: di' «riproduci» per avviare Musica, oppure apri Spotify."
cmds = {"play": "play", "riproduci": "play", "pausa": "pause", "stop": "stop", "prossimo": "next track", "avanti": "next track",
"precedente": "previous track", "indietro": "previous track"}
if azione in cmds:
osa(f'tell application "{app}" to {cmds[azione]}', timeout=20)
return f"Fatto ({azione})."
if azione in ("brano", "cosa suona", "info"):
try:
out = osa(f'tell application "{app}" to return (name of current track) & " — " & (artist of current track) & " (" & (album of current track) & ")"')
stato = osa(f'tell application "{app}" to return player state as string')
return f"{'In riproduzione' if stato == 'playing' else 'In pausa'}: {out}"
except Exception:
return "Nessun brano in riproduzione."
if azione == "volume":
v = max(0, min(100, int(params.get("valore") or 50)))
osa(f'tell application "{app}" to set sound volume to {v}')
return f"Volume musica al {v}%."
return "Azione sconosciuta. Usa: riproduci, pausa, prossimo, precedente, brano, volume."
def riproduci(params: dict, ctx: dict) -> str:
q = str(params.get("nome", "")).strip()
tipo = str(params.get("tipo", "auto")).lower()
if not q:
return "Errore: serve il nome."
app = _app(launch=True)
if app == "Spotify":
return "Con Spotify posso solo controllare la riproduzione, non cercare: avvia tu il brano e poi dimmi pausa, avanti, ecc."
if tipo in ("playlist", "auto"):
try:
out = osa('on run argv\ntell application "Music"\nset p to first playlist whose name contains (item 1 of argv)\nplay p\nreturn name of p\nend tell\nend run', q)
return f"Riproduco la playlist «{out}»."
except Exception:
if tipo == "playlist":
return f"Nessuna playlist chiamata '{q}'."
for prop in ("artist", "album", "name"):
try:
out = osa(f'''on run argv
tell application "Music"
set trk to (first track of library playlist 1 whose {prop} contains (item 1 of argv))
play trk
return (name of trk) & " — " & (artist of trk)
end tell
end run''', q, timeout=60)
return f"Riproduco: {out}."
except Exception:
continue
return f"Non ho trovato '{q}' nella libreria di Musica."
TOOLS = [
{"name": "musica_controllo", "description": "Controlla la musica: riproduci, pausa, prossimo, precedente, brano (cosa sta suonando), volume (0-100).",
"parameters": {"type": "object", "properties": {"azione": {"type": "string", "enum": ["riproduci", "pausa", "prossimo", "precedente", "brano", "volume"]},
"valore": {"type": "integer", "description": "Per volume: 0-100."}}, "required": ["azione"]}, "run": controllo},
{"name": "musica_riproduci", "description": "Cerca e riproduce una playlist, un artista, un album o un brano nella libreria di Apple Music.",
"parameters": {"type": "object", "properties": {"nome": {"type": "string"}, "tipo": {"type": "string", "enum": ["auto", "playlist", "artista", "album", "brano"]}}, "required": ["nome"]},
"run": riproduci},
]