Musiksteuerung über Siri mit Shortcuts

SqueezeCommander / iPeng / SqueezePad etc - der Streichelzoo
karlek
Moderator
Beiträge: 1750
Registriert: 2. November 2011 12:35
SqueezeBox: Touch
SqueezeBox: Radio
SqueezeBox: Boom
SqueezeBox: Classic
SqueezeBox: Transporter
SqueezeBox Server läuft auf: Raspberry Pi 3 (Jessie) mit LMS 7.9
(O2 Joggler mit LMS 7.9)
(QNAP-212 (Turbo) mit LMS 7.9)

Musiksteuerung über Siri mit Shortcuts

Beitrag von karlek »

Projekt Musiksteuerung über Siri mit Shortcuts

Vielleicht kann ja jemand etwas mit dem folgenden Shortcuts-Progrämmchen anfangen:
Link:
Musiksteuerung 1

Edit: Für den Import müssen in den Einstellungen „nicht vertrauenswürdige Quellen“ erlaubt werden. Das geht aber erst, wenn man bereits einen Kurzbefehl selbst erstellt hat.

Ich habe die Sprache in der Kurzbefehle-App auf Englisch gestellt, weil ich mit vielen Befehlen auf Deutsch gar nichts anfangen konnte.
Deshalb werde ich meistens auf die englischen Befehle Bezug nehmen, man sehe es mir nach. :oops:

Einleitung
Ich war nach einer Frage im slimdevices-Forum neugierig, was man mit der Shortcuts-App (Kurzbefehle) alles in Sachen Squeezebox-Steuerung bewerkstelligen kann. Also begann ich mit (für mich) interessanten Anweisungen zur Steuerung. Die wuchsen dann bis zum jetzigen Stand und werden wohl auch in diesem Umfang bleiben.
Sprich: meine Motivation, da noch großartig etwas zu erweitern oder zu „verbessern“ ist nicht sehr groß. Dafür ist das Projekt schon ein bisschen zu groß und in Shortcuts ist es echt schwer, die Übersicht zu behalten.
Falls aber jemand Interesse an dieser Steuerung hat und Fragen zu Funktion oder zur Anpassung, helfe ich gerne.
Die Spracherkennung von Siri ist übrigens überraschend gut – auch für englische Künstlernamen, aber „Squeezebox“ wollte Siri nie wirklich verstehen, weswegen ich dieses Programm „Musiksteuerung“ genannt habe.
Leider läppern sich die Wartezeiten
(„Hey Siri“ – „Was kann ich für Dich tun?“ – „Musiksteuerung“ – „Welcher Text“? – „Spiele Sarah Connor Wohnzimmer“ – „OK“)
schon ein wenig zusammen, sodass das ganze eher ein Gimmick für mich ist, als eine echte Erleichterung.

Funktionen
Der Aufruf erfolgt über Siri („Musiksteuerung“) oder aus der Shortcuts-App.
Bei letzterer ist mir aufgefallen, dass sie meine Sprache – zumindest auf dem Handy – als Englisch interpretiert, was eventuell daran liegt, dass ich die Sprache in der App auf Englisch gestellt habe (allerdings auf dem iPad…?).
Die folgenden Befehle können interpretiert werden, die Reihenfolge ist dabei unerheblich, aber es muss immer der Name der SB mit angegeben werden:
  • Start/Starten
  • Stopp
  • Pause (kein toggle)
  • Schlafen (Nach Titelende)
  • An/Aus
  • Zufall [Ende] (Titel)
  • Wiederholen [Ende] (alle Titel)
  • Weiter/Zurück
  • Lauter/Leiser
  • Lautstärke n (n>12: erst ab 13 schreibt Siri keine Zahlwörter mehr.)
  • Spiele <Artist> Spielt alles von einem Interpreten
  • Playlist <Name> Lädt die Playlist aus dem Standardverzeichnis
Beispiele
  • "Spiele Foreigner Küche" ("Foreigner" wurde von mir natürlich englisch ausgesprochen, ebenso Juhtu -> U2.)
  • "Wohnzimmer Playlist Bibi und Tina" (Leerzeichen bei Künstlern und Playlisten gehen also auch.)
  • "Keller Zufall" (Shuffle Titel)
  • "Wiederhole Badezimmer Ende" (Repeat aus)
Vorbereitungen nach dem Import
Bevor man diesen Kurzbefehl nutzen kann müssen die folgenden Dinge auf die eigenen Gegebenheiten angepasst werden:
  • Kurzbefehl in "Musiksteuerung" umbenennen
  • IP-Adresse und Port
  • Namen und MAC-Adressen der SBen
  • Die Sprachanweisungen könnt Ihr natürlich auch anpassen.
    Meine wurden von meiner Siri gut erkannt. :-)
  • Die relative Lautstärkeänderung passt bei mir mit 10 gut.
Anmerkungen
Nutzung
  • Die Anweisung ("An", "Lautstärke", "Mischen", ...) und der Name der SB dürfen nur aus einem Wort bestehen. Alles andere wird als Daten interpretiert.
  • Es werden nur alle Titel eines Künstlers abgespielt oder eine Playlist. Kein Genre, keine Alben, keine einzelnen Titel.
  • Es werden keine Füllwörter gefiltert, sodass man sich auf die einzelnen Befehle und Daten beschränken muss.
    „Lade Playlist Bibi und Tina im Wohnzimmer“ ergäbe fälschlicherweise:
    <Wohnzimmer-MAC> playlist play „Bibi und Tina im.m3u“
    Kurz gesagt: Alles, was kein SB-Name oder ein Befehl ist, wird als Daten behandelt.
  • Was nicht geht, sind doppeldeutige Bezeichnungen: wenn die SB „Wohnzimmer“ heißt, dann wird niemals eine Playlist namens „Wohnzimmer“ aufgerufen. Da gibt es keinen Plausibilitätscheck oder Alternativen, oder so.
  • Auch müssen alle Daten am Wortanfang groß sein: „Bibi Und Tina“, aber nicht „Bibi und Tina“. Die App wandelt das automatisch um, Ihr müsstet das bei Euren Interpreten und Wiedergabelisten eventuell anpassen oder den entsprechenden Befehl nach dem Diktat rauswerfen. (Und dann den Input des folgenden Befehls anpassen.)
  • Es werden nur Wiedergabelisten im Wiedergabelisten-Verzeichnis, wie es im LMS gespeichert, ist aufgerufen. Eine Pfadangabe via JSON wurde mir von Shortcuts immer mit escapeden Slashes geposted:

    Code: Alles auswählen

    /media/playlists -> \/media\/playlists
    Keine Ahnung, wie ich das verhindern kann.



---------------------------------------------------------
Ab hier nur für an der Umsetzung Interessierte
---------------------------------------------------------

Programmierstil
Bisweilen ist mir meine Implementierung ein wenig peinlich, deshalb hier der Versuch, alles auf das Framework der Shortcuts-App zu schieben…
Und natürlich möchte ich den Code auch ein wenig nachvollziehbarer machen.

Modularisierung
Da man in einem Kurzbefehl auch andere Kurzbefehle aufrufen und mit deren Ergebnissen weiter arbeiten kann, habe ich kurz mit dem Gedanken gespielt, die einzelnen Bestandteile der Implementierung in einzelne Kurzbefehle aufzuteilen. Da das Programm dann aber doch noch einigermaßen überschaubar blieb und jeder Kurzbefehl natürlich in meiner Liste auftaucht, habe ich darauf verzichtet.

Variablen
  • Die Belegung von Variablen mit Text ist hier etwas ungewöhnlich: Man muss zuerst einen Text in ein Textfeld schreiben und dann eine Variable mit diesem Text erstellen.
  • Verschiedene Variablen können denselben Namen haben. Wenn man eine Variable ein zweites Mal belegt, behandelt Shortcuts sie als zweite Variable. Man muss also später aufpassen, auf welche Variable man sich bezieht! Dabei hilft aber „Reveal Action“, das einem zeigt, auf welchen Baustein gerade Bezug genommen wurde. Nichtsdestotrotz sollte man sich aber, wenn mal etwas unerwarteterweise falsch läuft, daran erinnern, dass es mehrere Variablen gleichen Namens geben kann. Beim Zusammensetzen der Daten musste ich beispielsweise rückwirkend auf ein Variable Bezug nehmen, die es zum Zeitpunkt der Erstellung des Verkettungsbefehls noch gar nicht gab. Glaube ich...
Listen
  • Man kann komplette Listen leicht erstellen, aber nicht so leicht auf einzelne Elemente zugreifen. Das gilt insbesondere, wenn man die Dimension der Liste nicht kennt. Greift man dann auf ein Element zu, das es nicht gibt. Bricht Shortcuts mit einer Fehlermeldung ab.
  • Man kann einzelne Listenelemente im Nachhinein nicht ändern.
  • Man kann eine Liste nicht ausgehend von einer existierenden Liste erstellen, was für die Parameterliste echt geschickt gewesen wäre. Ich musste also die Parameter p0 bis p4 einzeln festlegen, was weniger elegant ist.
Dictionary (Wörterbuch)
Ich kannte Dictionaries bereits aus Perl und Python und ich liebe sie!
  • Dictionaries sind wie Listen, haben allerdings keine Ganzzahl als Index sondern ein Schlüsselwort:

    Code: Alles auswählen

    {key: value}, z.B. {"method" : "slim.request", "params" : [...]}
    JSON arbeitet auch mit Wörterbüchern und der Aufruf über die JSONRPC-API erfolgt entsprechend mit den Daten in einem Wörterbuch.
  • Dictionaries waren für mich bisweilen die einzige Möglichkeit, Inhalte von Variablen abzufragen, da mir die Shortcuts-App bei Bedingungen häufig keinen Vergleichsoperator zur Verfügung stellte.
Aufbau des Programms
Überblick
  1. Initialisierung URL, p0 bis p4, data
  2. Eingabe aus diktiertem Text
  3. diktierte Anweisungen in Liste speichern
  4. Anweisungen parsen:
    • MAC-Adresse
    • Befehlsparameter
    • Daten
  5. Ggf. Daten an richtiger Stelle in Parameterliste einfügen.
  6. POST abschicken
Programmablauf (schematisch mit Kommentaren)
Initialisierung
• URL=http://IP:Port/jsonrpc.js wird zusammengebaut
• Parameter p0 bis p4, sowie data für variable Inhalte werden initialisiert

Eingabe
  1. Diktat des Befehls
  2. In Große Anfangsbuchstaben
  3. In Liste zerlegen
  4. Parsen der einzelnen Bestandteile:
    • Directory: SB-Name –> MAC-Adresse mac
    • Directory: Befehl –> Parameterliste parameters
    • Sonstiges (Lautstärke, Künstler, Playlist, ...)–> data
Verarbeitung
Hier muss nun interpretiert werden, an welche Position der Befehlskette ein eventueller Wert in data gehört. Anweisungen, die variable Daten benötigen sind:
  • „Spiele“ <Artist> ["playlist", "loadalbum", "*", data, "*"] (vierte Position)
  • „Playlist“ <Name> ["playlist", "play", data] (dritte Position)
  • „Zufall Ende“ ["playlist", "shuffle", 0] (wenn data == “Ende")
  • „Wiederholen Ende“ ["playlist", "repeat", 0] (wenn data == “Ende")
  • „Lautstärke“ <n> ["mixer", "volume", data] (dritte Position)
    aber: „Lauter“ ["mixer", "volume", "+10"](ohne data)
Meine Strategie war nun, zuerst die einparametrigen Anweisungen („Start“, „Stopp“, „Pause“) zu verarbeiten. Dann kann man beim Rest ohne Fehler auf den zweiten Parameter zugreifen.
Ich beginne bie diesem Rest mit „Spiele...“, bei dem data an vierter Position (p3) kommt.

Code: Alles auswählen

wenn p2 == "loadalbum"
	dann p3 = data	
	sonst wenn data == ""
		dann p2 = letztes Element von parameters
			// es gibt nur noch Befehle mit zwei oder drei Parametern
			// überzählige Parameter werden von jsonrpc ignoriert
		sonst wenn data == "Ende" // „Mischen Ende“ oder „Wiederholen Ende“
			dann p2 = 0
			sonst p2 = data // für „Lautstärke“ <n> oder „Playlist“ <Name>
Ausgabe
Hier wird nur noch eine POST-Anweisung an URL generiert und abgesetzt:

Code: Alles auswählen

curl -X POST -d '{ "method": "slim.request", "params":[mac, [p0, p1, p2, p3, p4]]}' URL

karlek
Moderator
Beiträge: 1750
Registriert: 2. November 2011 12:35
SqueezeBox: Touch
SqueezeBox: Radio
SqueezeBox: Boom
SqueezeBox: Classic
SqueezeBox: Transporter
SqueezeBox Server läuft auf: Raspberry Pi 3 (Jessie) mit LMS 7.9
(O2 Joggler mit LMS 7.9)
(QNAP-212 (Turbo) mit LMS 7.9)

Re: Musiksteuerung über Siri mit Shortcuts

Beitrag von karlek »

Heute ist mir ein wichtiger use case eingefallen, den ich noch ganz dringend implementieren musste: die Presets

Deshalb gibt es nun eine neuen Link
Musiksteuerung Import
und einen neuen Befehl:

"Station" mit Parametern "Eins" bis "Zehn".

Wer es noch nicht wusste: man kann die Presets mittlerweile recht einfach übers Webinterface unter den Player-Einstellungen befüllen. Dort gehen dann auch die "Tasten" 7 bis 10.