Spotify: read-only Verbindungstest-Skript (Toolset/Login/Live-API), analog zum Auth-Skript
Prueft direkt in Hermes' eigenem Code (get_auth_status, _get_platform_tools, SpotifyClient), ob Toolset aktiviert, Login vorhanden und ein echter GET /me/player/devices erfolgreich ist -- ohne Umweg ueber Claude/Proxy, da LLM-Textantworten wie 'nicht verbunden/aktiv' kein verlaesslicher Diagnosewert sind.
This commit is contained in:
@@ -294,6 +294,32 @@ nennen. Falls es weiter hakt: `docker logs hermes-proxy --tail 100 -f`
|
|||||||
waehrend der Reproduktion pruefen ob `--safe-mode` tatsaechlich im
|
waehrend der Reproduktion pruefen ob `--safe-mode` tatsaechlich im
|
||||||
gestarteten Prozess ankam (`docker exec -it hermes-proxy ps aux | grep claude`).
|
gestarteten Prozess ankam (`docker exec -it hermes-proxy ps aux | grep claude`).
|
||||||
|
|
||||||
|
### Verbindungstest ohne Chat/Claude (`spotify_test_connection.py`)
|
||||||
|
|
||||||
|
Wenn Claude im Dashboard-Chat was sagt wie "Spotify-Tools sind zwar
|
||||||
|
gelistet, aber nicht verbunden/aktiv" ist unklar OB das stimmt oder ob
|
||||||
|
Claude nur raet — eine LLM-Textantwort ist kein verlaesslicher
|
||||||
|
Diagnosewert. `scripts/spotify_test_connection.py` prueft stattdessen
|
||||||
|
direkt in Hermes' eigenem Code (denselben Funktionen, die der echte
|
||||||
|
Tool-Dispatch benutzt), read-only, ohne irgendwas zu veraendern:
|
||||||
|
|
||||||
|
1. Ist das Toolset `spotify` ueber `hermes tools` fuer irgendeine
|
||||||
|
Plattform aktiviert? (`~/.hermes/config.yaml` -> `platform_toolsets`)
|
||||||
|
2. Ist Spotify eingeloggt? (`~/.hermes/auth.json` -> `providers.spotify`)
|
||||||
|
3. Funktioniert ein ECHTER API-Call mit dem gespeicherten Token
|
||||||
|
(`GET /me/player/devices`, inkl. Auto-Refresh falls abgelaufen)?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker cp scripts/spotify_test_connection.py hermes-agent:/tmp/spotify_test_connection.py
|
||||||
|
docker exec -it hermes-agent python3 /tmp/spotify_test_connection.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Sind alle drei Punkte gruen und der Chat sagt trotzdem "kenn ich nicht" /
|
||||||
|
"nicht verbunden", liegt's am Proxy bzw. am System-Prompt (siehe Abschnitt
|
||||||
|
oben), nicht an Spotify selbst — dann `docker logs hermes-proxy` waehrend
|
||||||
|
der Reproduktion pruefen. Gleiches Nutzungsmuster wie
|
||||||
|
`scripts/spotify_manual_auth.py` (Login-Skript weiter oben).
|
||||||
|
|
||||||
## Mobiler Client (Android)?
|
## Mobiler Client (Android)?
|
||||||
|
|
||||||
Zwei GRUNDVERSCHIEDENE Richtungen, nicht verwechseln:
|
Zwei GRUNDVERSCHIEDENE Richtungen, nicht verwechseln:
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Spotify-Verbindungstest fuer Hermes -- prueft in drei Schritten, OHNE den
|
||||||
|
Umweg ueber Claude/den Proxy, ob Spotify aus dem Chat heraus wirklich
|
||||||
|
funktionieren sollte.
|
||||||
|
|
||||||
|
Hintergrund: Wenn Claude im Dashboard-Chat sowas sagt wie "Spotify-Tools
|
||||||
|
sind zwar in meiner Werkzeugliste beschrieben, aber in dieser Session
|
||||||
|
aktuell nicht verbunden/aktiv", ist unklar OB das stimmt oder ob Claude nur
|
||||||
|
raet -- Text-Antworten vom LLM sind kein verlaesslicher Diagnosewert. Dieses
|
||||||
|
Skript ruft dieselben Hermes-internen Funktionen direkt auf, die auch beim
|
||||||
|
echten Tool-Dispatch benutzt werden (siehe plugins/spotify/tools.py
|
||||||
|
_check_spotify_available und plugins/spotify/client.py SpotifyClient):
|
||||||
|
|
||||||
|
1. Toolset "spotify" ueber `hermes tools` aktiviert? (pro Plattform,
|
||||||
|
~/.hermes/config.yaml -> platform_toolsets)
|
||||||
|
2. Bei Spotify eingeloggt? (~/.hermes/auth.json -> providers.spotify)
|
||||||
|
3. Funktioniert ein ECHTER API-Call mit dem gespeicherten Token (inkl.
|
||||||
|
Auto-Refresh falls abgelaufen)? Ruft GET /me/player/devices auf --
|
||||||
|
harmlos, read-only, keine Wiedergabe wird veraendert.
|
||||||
|
|
||||||
|
Nutzung (im hermes-agent-Container, wo hermes_cli installiert ist):
|
||||||
|
docker cp scripts/spotify_test_connection.py hermes-agent:/tmp/spotify_test_connection.py
|
||||||
|
docker exec -it hermes-agent python3 /tmp/spotify_test_connection.py
|
||||||
|
|
||||||
|
Reiner Read-Only-Diagnose-Check, veraendert nichts. Fuer den Login selbst
|
||||||
|
siehe scripts/spotify_manual_auth.py (gleiches Nutzungsmuster).
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hermes_cli.auth import get_auth_status
|
||||||
|
except ImportError as exc: # pragma: no cover
|
||||||
|
sys.exit(
|
||||||
|
"Konnte hermes_cli.auth nicht importieren -- Skript muss INNERHALB "
|
||||||
|
f"des hermes-agent-Containers laufen (python3 dort). Fehler: {exc}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hermes_cli.config import load_config_readonly
|
||||||
|
from hermes_cli.tools_config import _get_platform_tools, PLATFORMS
|
||||||
|
except ImportError as exc: # pragma: no cover
|
||||||
|
sys.exit(f"Konnte hermes_cli.tools_config/config nicht importieren: {exc}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from plugins.spotify.client import (
|
||||||
|
SpotifyAPIError,
|
||||||
|
SpotifyAuthRequiredError,
|
||||||
|
SpotifyClient,
|
||||||
|
SpotifyError,
|
||||||
|
)
|
||||||
|
except ImportError as exc: # pragma: no cover
|
||||||
|
sys.exit(f"Konnte plugins.spotify.client nicht importieren: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
def _bar(title: str) -> None:
|
||||||
|
print()
|
||||||
|
print("=" * 78)
|
||||||
|
print(title)
|
||||||
|
print("=" * 78)
|
||||||
|
|
||||||
|
|
||||||
|
def check_auth() -> bool:
|
||||||
|
_bar("1) Login-Status (~/.hermes/auth.json -> providers.spotify)")
|
||||||
|
status = get_auth_status("spotify")
|
||||||
|
logged_in = bool(status.get("logged_in"))
|
||||||
|
print(f" logged_in: {logged_in}")
|
||||||
|
print(f" auth_type: {status.get('auth_type')}")
|
||||||
|
print(f" client_id: {status.get('client_id')}")
|
||||||
|
print(f" redirect_uri: {status.get('redirect_uri')}")
|
||||||
|
print(f" scope: {status.get('scope')}")
|
||||||
|
print(f" expires_at: {status.get('expires_at')}")
|
||||||
|
print(f" has_refresh_token: {status.get('has_refresh_token')}")
|
||||||
|
if not logged_in:
|
||||||
|
print()
|
||||||
|
print(" -> NICHT eingeloggt. `python3 spotify_manual_auth.py` ausfuehren")
|
||||||
|
print(" (oder `hermes auth spotify`, falls SSH-Port-Forward moeglich ist).")
|
||||||
|
return logged_in
|
||||||
|
|
||||||
|
|
||||||
|
def check_toolsets() -> bool:
|
||||||
|
_bar("2) Toolset 'spotify' aktiviert? (hermes tools, pro Plattform)")
|
||||||
|
config = load_config_readonly()
|
||||||
|
any_enabled = False
|
||||||
|
for platform_key, info in sorted(PLATFORMS.items()):
|
||||||
|
try:
|
||||||
|
enabled = _get_platform_tools(config, platform_key)
|
||||||
|
except Exception as exc:
|
||||||
|
print(f" {platform_key:14s} -> Fehler beim Aufloesen: {exc}")
|
||||||
|
continue
|
||||||
|
is_on = "spotify" in enabled
|
||||||
|
any_enabled = any_enabled or is_on
|
||||||
|
marker = "AN " if is_on else "aus"
|
||||||
|
label = info.get("label", platform_key) if isinstance(info, dict) else platform_key
|
||||||
|
print(f" [{marker}] {platform_key:14s} ({label})")
|
||||||
|
if not any_enabled:
|
||||||
|
print()
|
||||||
|
print(" -> Fuer KEINE Plattform aktiviert. Im Container:")
|
||||||
|
print(" `hermes tools` -> zu Spotify runterscrollen -> Leertaste -> mit 's' speichern.")
|
||||||
|
return any_enabled
|
||||||
|
|
||||||
|
|
||||||
|
def check_live_call() -> bool:
|
||||||
|
_bar("3) Echter Live-API-Call (GET /me/player/devices, read-only)")
|
||||||
|
try:
|
||||||
|
client = SpotifyClient()
|
||||||
|
devices = client.get_devices()
|
||||||
|
except SpotifyAuthRequiredError as exc:
|
||||||
|
print(f" FEHLER (Auth erforderlich): {exc}")
|
||||||
|
return False
|
||||||
|
except SpotifyAPIError as exc:
|
||||||
|
print(f" FEHLER (Spotify-API, status={exc.status_code}): {exc}")
|
||||||
|
return False
|
||||||
|
except SpotifyError as exc:
|
||||||
|
print(f" FEHLER: {exc}")
|
||||||
|
return False
|
||||||
|
except Exception as exc: # pragma: no cover
|
||||||
|
print(f" UNERWARTETER FEHLER ({type(exc).__name__}): {exc}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
items = (devices or {}).get("devices", []) if isinstance(devices, dict) else []
|
||||||
|
if not items:
|
||||||
|
print(" API-Call erfolgreich, aber KEINE Geraete gemeldet.")
|
||||||
|
print(" -> Spotify-App auf dem Zielgeraet (Handy/PC) kurz oeffnen, damit es")
|
||||||
|
print(" bei Spotify Connect als aktiv gemeldet wird, dann nochmal testen.")
|
||||||
|
else:
|
||||||
|
print(f" API-Call erfolgreich, {len(items)} Geraet(e) gefunden:")
|
||||||
|
for d in items:
|
||||||
|
active = "aktiv" if d.get("is_active") else "inaktiv"
|
||||||
|
print(f" - {d.get('name')} ({d.get('type')}, {active}, vol={d.get('volume_percent')}%)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ok_auth = check_auth()
|
||||||
|
ok_tools = check_toolsets()
|
||||||
|
ok_live = check_live_call() if ok_auth else False
|
||||||
|
|
||||||
|
_bar("Zusammenfassung")
|
||||||
|
print(f" 1) Eingeloggt: {'OK' if ok_auth else 'FEHLT'}")
|
||||||
|
print(f" 2) Toolset aktiviert: {'OK' if ok_tools else 'FEHLT'}")
|
||||||
|
print(f" 3) Live-API erreichbar: {'OK' if ok_live else 'FEHLT/UEBERSPRUNGEN'}")
|
||||||
|
print()
|
||||||
|
if ok_auth and ok_tools and ok_live:
|
||||||
|
print("Alles gruen -- Spotify sollte im Chat funktionieren. Kommt trotzdem")
|
||||||
|
print("'kenn ich nicht'/'nicht verbunden', liegt's am Proxy bzw. System-Prompt")
|
||||||
|
print("(z.B. Claude nutzt eigene Connectors statt der injizierten Tools),")
|
||||||
|
print("nicht an Spotify selbst -- dann bitte docker logs hermes-proxy pruefen.")
|
||||||
|
else:
|
||||||
|
print("Siehe die '->'-Hinweise oben fuer den jeweils naechsten Schritt.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user