Springe zum Hauptinhalt

Fehlercode 0.60 bei Prime Video auf Google Chromecast mit Android-TV

Seit etwas mehr als einer Woche plagte mich der Fehlercode 0.60 bei der "Prime Video"-App auf dem Google Chromecast mit Android TV – ich finde es ja auch furchtbar, das so auszuschreiben, aber das Gerät heißt nun mal so. Da ich meine Lösung letztendlich über ein Apple-TV-Support-Forum fand, wird das aber vermutlich auf verschiedenen Geräten von Roku, Amazon und Herstellern von Smart-TVs ähnlich sein.

Auf die falsche Fährte führte mich, dass am 2024-01-24 ein Update der App stattgefunden hat, was dann vermutlich in den ein, zwei Tagen danach auch auf meinem Chromecast landete. Während meiner Recherche habe ich mich zu sehr auf diese zeitliche Koinzidenz eingeschossen. Tatsächlich lag die Ursache aber in der Aktivierung unserer Glasfaser am 2024-01-25 und vermutlich am Kurzurlaub meiner Familie am 2024-02-03 für ein paar Tage.

Die Glasfaser-Aktivierung war schuld, weil damit erstmalig IPv6 Einzug hielt bei uns. Vorher befand sich das Heimnetz in einem Zustand von "vielleicht funktioniert das ja so". Ich konnte ja nichts belastbar testen, ich konnte keine Erfahrungen sammeln. Hätte ich nicht zu viele Eigenheiten im Heimnetz, wäre das vielleicht auch nie aufgetreten, wer weiß?

Durch IPv6 über die Glasfaser hat mein Netz jetzt jedenfalls auch endlich ein IPv6-Präfix erhalten. Und ich war super erstaunt, dass das praktisch sofort alle Geräte erreichte, die sich dann auch selbst konfiguriert hatten. Für mich ein Rätsel war aber immer noch, wie die Geräte eigentlich herauskriegen, wo das Gateway liegt und wie sie Namen auflösen sollen. Das sollte mir hierbei noch auf die Füße fallen.

Im Nachhinein kann ich mir nicht erklären, warum das nicht sofort aufgefallen ist. Vielleicht haben wir bei Amazon einfach nichts geschaut für ein paar Tage. Oder ich habe das als Fehler auf Amazons Seite betrachtet, denn alle anderen Streamingdienste liefen ja ohne Probleme. Ja, die App "Prime Video" auf dem Google Chromecast mit Android TV macht irgendwas eigenes, und sie macht das nicht auf anderen Android-Geräten – auf meinem Tablet wie auch auf dem Handy konnte ich sie normal benutzen.

Der Kurzurlaub meiner Familie wiederum war dahingehend daran beteiligt, dass ich währenddessen am NAS gearbeitet hatte, wo ich einen dnsmasq in einem systemd-nspawn-Container betreibe, der für DNS und DHCP im Heimnetz zuständig ist. Nach viel hin und her beschloss ich am Ende, um zumindest einen Teil des Umzugs durchzuführen, den alten Container auf dem neuen NAS in Betrieb zu nehmen. Für niemanden überraschend außer mich, der schlicht nicht dran gedacht hat, hat der Container dort natürlich eine neue IPv6 für sich erzeugt, so dass der DNS-Server-Eintrag in den IPv6-Netzwerkeinstellungen der Fritzbox natürlich falsch war. War er vorher vermutlich auch schon, denn es hatte ja schon vorher nicht funktioniert.

Jetzt habe ich auch ein paar Tage Urlaub und habe mich heute früh mal dran gesetzt. Der Forumsbeitrag erwähnte IPv6, und da ich das noch nicht weiter verfolgt hatte, dachte ich mir, dass ich das ja mal machen könnte. Stück für Stück habe ich dann meine Konfiguration im Heimnetz mal abgeklopft.

Die resolv.conf meines Containers war noch auf die alte IP eingerichtet.

Meine Datei für Namensauflösungs-Overrides warf immer Fehler.

Feb 08 09:34:22 lan-basics1 systemd[1]: Starting dnsmasq - A lightweight DHCP and caching DNS server...
Feb 08 09:34:22 lan-basics1 dnsmasq[4698]: bad option at line 1 of /etc/dnsmasq.d/override.hosts
Feb 08 09:34:22 lan-basics1 dnsmasq[4698]: FAILED to start up
Feb 08 09:34:22 lan-basics1 systemd[1]: dnsmasq.service: Control process exited, code=exited, status=1/FAILURE
Feb 08 09:34:22 lan-basics1 systemd[1]: dnsmasq.service: Failed with result 'exit-code'.
Feb 08 09:34:22 lan-basics1 systemd[1]: Failed to start dnsmasq - A lightweight DHCP and caching DNS server.

Hintergrund: Auch wenn in der /etc/dnsmasq.conf steht:

conf-dir=/etc/dnsmasq.d,*.conf

so steht in der /etc/default/dnsmasq dummerweise:

CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new

In der /etc/init.d/dnsmasq wird die Default-Datei dann gesourcet und CONFIG_DIR auf der Kommandozeile übergeben, womit es die Option in dnsmasq.conf überschreibt, falls die Datei dann überhaupt noch ausgewertet wird. Das hat jedenfalls dazu geführt, dass alle Dateien in /etc/dnsmasq.d eingebunden wurden, die nicht auf .dpkg-dist, dpkg-old oder dpkg-new endeten. Ich habe den Eintrag in der Default-Datei entsprechend geändert, dass er dem in der Konfigurationsdatei entspricht.

Ich vermute, die Debian-Maintainer hatten das irgendwann in der Vergangenheit aus guten Gründen so gehandhabt, aber dann nicht mitbekommen, dass die Upstream-Konfigurationsdatei das bereits erledigt, was die Maintainer erzielen wollten. Ich werde das auch mal melden müssen. Die Korrektur hat jetzt jedenfalls dazu geführt, dass meine ausgelagerten Einstellungen für DNS-Server –google.dns und quad9.dns– nicht mehr beide gleichzeitig eingebunden werden. War zwar vorher kein bemerkbares Problem, aber ich erinnere mich, dass ich zurück auf Google musste, weil Quad9 irgendeinen Blödsinn gemacht hat (oder auch nix gemacht hat).

Ich finde solche Probleme bei Konfigurationsdateien ja doch sehr ärgerlich. Ich möchte gerne wissen, welche Dateien die Laufzeit-Konfiguration enthalten. Ich möchte Kontrolle darüber haben. Ich will nicht so überrascht werden.

Auf der anderen Seite, beim Chromecast, konnte ich zumindest feststellen, dass die App funktionierte, wenn ich die Netzwerkkonfiguration von "DHCP" auf "statisch" änderte.

Trivia: Ändert man das, werden die einzelnen Optionen nicht mit den letzten DHCP-Werten befüllt, sondern mit generischen Werten aus dem 192.168.1.1/24-Netz. Und die Eingabe über die Fernbedienung ist nicht sonderlich komfortabel.. Immerhin müssen nur Adresse, Subnetzlänge und Gateway eingegeben werden. Bei den DNS-Servern habe ich schlicht die Vorgaben (Google-DNS) verwendet.

Damit ging es also, was mir die Vermutung nahelegte, dass irgendwas bei der DHCP-Konfiguration schief lief. Aber mehr als die IP-Adressen kann ich der Oberfläche des Chromecast nicht entlocken. Und irgendwie funktionierte ja die Konfiguration. Ich habe wieder einmal in die DHCP-Einstellungen von dnsmasq geschaut, und wieder hatte ich vergessen, dass IPv6 anders konfiguriert wird. Mein Router meldet den IPv6-Clients, welchen DNS-Server sie verwenden sollen. Und da fiel mir dann auf, dass da ein falscher Wert steht. Schwupps ausgetauscht gegen die aktuelle IPv6-Adresse des lan-basics-Containers, und schon läuft es.

Hilfreich zum Überprüfen (Quelle: How can I view IPv6 router advertisements that are being received by my computer for diagnostic purposes?) :

tcpdump -n -i wlp2s0 icmp6
tcpdump -n -i wlp2s0 icmp6 and ip6[40] == 134
radvdump

Interessanter Nebeneffekt: Ich hatte seit Monaten das Gefühl, dass mein Tablet beim Aufruf einer noch nicht cachierten Website eine unangenehm lange Denkpause einlegt. Ich hatte DNS im Verdacht, aber ich fand nichts. Ich denke, das geht jetzt auch flotter. Vermutlich hat auch das Tablet erst einmal DNS per IPv6 aufzulösen versucht, und wenn keine Antwort kam, hat es IPv4 probiert. Das scheint die "Prime Video"-App nicht zu machen.

Mir bleibt nur noch die Frage offen, wie stabil die Selbstkonfiguration bei IPv6 ist. Ich habe für den lan-basics-Container folgendes gesetzt:

IPv6LinkLocalAddressGenerationMode=eui64

Nach dem Wälzen der man-Page (ist schon ein paar Monate her) scheint mir das die einzige Einstellung zu sein, die keine Konflikte erzeugen kann und reproduzierbar die gleiche IPv6-Adresse erzeugt. Aber ist das so?

Strange Behaviour in Container Namespace

Anmerkung: Dieser Beitrag ist zusammengestellt aus mehreren Posts im Fediverse, wo ich gerade bei technischen Beiträgen zu englisch neige in der Hoffnung, dass jemand drauf reagiert. Für die bessere Auffindbarkeit veröffentliche ich das nachträglich auch hier. Das Datum des Beitrags setze ich auf das vom ersten Beitrag des Threads.


I am, by no means, a good C programmer or a good programmer at all. But looking at the #dnsmasq source code causes some severe headaches. Indentation is wildly mixed between tabstops, 8 spaces and 2 spaces. Functions have no meaningful documentation … has anybody some resources to make sense of this code? I'm especially interested in iface_check (network.c:112) as dnsmasq complains about my interface not having an address (dhcp.c:295).

For the moment, I'm tempted to just switch over to Kea + Bind. Or try to get systemd-networkd + systemd-resolved to do what I want.

Background: I'm migrating my NAS to a new NAS (NAS1 → NAS2). On my NAS1 I have a systemd-nspawn lan-basics which provides some LAN basics like DNS and DHCP. My NAS1 only has 1 physical interface so I created a bridge and added it to the nspawn. That worked reasonably well. My NAS2 has 4 physical ports and I wanted to dedicate 1 port for the nspawn. I did not try yet to replicate the complete NAS1 interface config on NAS2 to rule out some other sources for my problems.

On NAS1 I added all nspawns to the bridge interface. On NAS2 my plan was to only expose the nspawns that are required to be exposed. Everything else should be reverse proxied using nginx on the lan-basics nspawn. So, lan-basics requires at least two interfaces: the physical interface and a veth connected to the veth zone on NAS2. The other nspawns only get veth interfaces bound to that zone.

The NAS2 does DHCP using systemd-networkd on the zone interface, vz-zone. lan-basics should provide DNS and DHCP on the physical interface but itself use LLMNR on the veth interface to find the neighbouring nspawns.

At the moment, I think I'll just drop this requirement and use a dedicated nspawn for nginx. But then along came the message "DHCP packet received on enp6s0 which has no address" which is caused by dnsmasq and I can't find out what's wrong.

I could imagine it has something to do with the interface being moved into a different namespace, though. Maybe there's a difference in a veth bound to bridge and a physical interface in a different namespace, even if veth and physical interface both were in the same namespace.


Okay, I did replicate the config but it's still "DHCP packet received on host0 which has no address".

The last difference is the version of dnsmasq: 2.85 vs 2.89. I'll move the nspawn to NAS1 and try it there.

I must emphasize that I really appreciate the networkctl command. Prior to that I always issued systemctl restart systemd-networkd.service and still wasn't sure if it really applies my changes. networkctl reload OTOH seems to always does.

And then there's netplan. The people from Openmediavault, as much as I appreciate their work, decided to use netplan for network management. I just managed to terminate my ssh connections by netplan apply.

Of course, that's just a coincidence as my DHCP server wasn't running and the interfaces were set to DHCP. 😄

Well, I cannot tell for sure why, but the lan-basics nspawn from NAS2 doesn't work on NAS1, too. Because I already wasted^Wlearned so much I'll just copy the old lan-basics to NAS2 and see if it works there as I intended. Actually, I feel bad not using btrfs send|receive for that but it's just too big a hassle to ro-snapshot the subvolumes, send/receive them and the set them rw again. I should suggest automating these steps.

Result 1: The lan-basics1 nspawn bound to a bridge interface works.

Result 2: When providing exclusive access to enp6s0 the nspawn's dnsmasq starts showing "DHCP packet received on enp6s0 which has no address".

I don't know what's happening here but I'd say it's a bug somewhere, either in systemd-nspawn or in dnsmasq.

After a long chat with the nice people of #systemd IRC channel (nice to have it hashtagged if I mention the channel) I conclude that the bug is with dnsmasq. There's no reason it shouldn't work.


I then went on to file a bug report:

I finally found some time for further investigations. Here are my observations.

NAS1

old NAS with systemd-nspawn lan-basics

NAS2

new NAS with systemd-nspawn lan-basics

lan-basics1

NAS1's lan-basics on NAS2

lan-basics2

NAS2's lan-basics on NAS1

OS NAS1

Debian 11

OS NAS2

Debian 12

OS lan-basics at NAS1

Debian 11

OS lan-basics at NAS2

Debian 12

lan-basics at NAS1 is configured to use bridge br0 which enslaved the physical interface enp1s0.

lan-basics at NAS2 started with 1 of 4 interfaces moved into the systemd-nspawn, enp6s0. I removed any additional interfaces of my prior setup as I wanted to reduce the moving parts.

Leaving aside dnsmasq's configuration that worked on lan-basics at NAS1, I made the following attempts:

  1. I copied lan-basics at NAS2 to lan-basics2 at NAS1. As NAS1 only has one interface I added lan-basics2 to the same br0 as lan-basics at NAS1. The result was the same as on NAS2: "DHCP packet received on host0 which has no address" (the veth interface in this configuration is named host0 in the container).

  2. I replicated the network configuration from NAS1: I created a bridge interface br0, enslaved enp6s0 and configured lan-basics at NAS2 to use this bridge interface. Still the same symptoms.

  3. I copied lan-basics at NAS1 to lan-basics1 at NAS2. There I first tried using the same initial config as lan-basics at NAS2 with enp6s0, but lan-basics1 now oddly showed the same symptoms.

  4. I reconfigured the network to enslave enp6s0 under br0 and lan-basics1 to use this bridge interface. It works.

For the moment I stick to setup 4 but there's apparently something wrong with how dnsmasq treats namespaced interfaces. I can switch around setups 3 and 4, always with the same result of dnsmasq complaining about receiving DHCP packets on the interface where it doesn't know its address. Yes, I made sure that dnsmasq is started after the interface got its configuration (stopping dnsmasq, checking the address of the interface, starting dnsmasq).

I haven't tried yet the other network options of systemd-nspawn, e.g. IPVLAN, MACVLAN, VETH with port forwarding etc. Giving a systemd-nspawn container a network interface with exclusive access should be the gold standard of all possible network configurations.

FWIW, the versions of the involved dnsmasq binaries are 2.85 for Debian 11 and 2.89 for Debian 12.

I believe this to be a bug in dnsmasq. I'd gladly help to debug it but I can't do it myself. AFAICT the problem seems to be in iface_check in network.c but I don't know where it goes wrong.

Erste Erfahrungen mit dem E-Rezept

Anmerkung: Dieser Beitrag ist zusammengestellt aus mehreren Posts im Fediverse. Für die bessere Auffindbarkeit veröffentliche ich das nachträglich auch hier. Das Datum des Beitrags setze ich auf das vom ersten Beitrag des Threads.

Über das E-Rezept wurde ja schon viel gemeckert, aber ein Aspekt kam mir noch nicht unter.

Ich muss jedes Quartal meine Versichertenkarte in die Praxis bringen. Meine Medikamente reichen knapp weniger als ein Quartal. Meine regulären Kontrolltermine werden aber auch nicht so gelegt, dass sie mit der Reichweite meiner Medikamente übereinstimmen.

Effektiv habe ich nur ca.jedes 4. Rezept etwas vom e-Rezept, wenn mal ausnahmsweise das neue Rezept ans Ende eines Quartals fällt.

Wichtige Zusatzinfo: Eigentlich könnte ich einfach eine Mail schreiben mit meinem Rezeptwunsch und einen halben Tag später zur Apotheke gehen, um mit meiner Versichertenkarte mein E-Rezept einzulösen.

Wie ich heute aber erfuhr, wird kein E-Rezept ausgestellt, wenn ich im aktuellen Quartal noch nicht meine Karte habe einlesen lassen.

Obendrauf kam, dass meine Praxis mir diese Info erst mitteilte, als ich persönlich vor Ort nach dem Verbleib des E-Rezeptes nachfragte. Aber das ist ja kein Fehler des e-Rezeptes, sondern des Prozesses in meiner Praxis. Ich hoffe, sie kriegen das noch besser hin.

Und ja, ich habe mitbekommen, dass gerade im Gespräch sei, diesen Quartalsturnus zu einem Jahresturnus zu verändern. Meine Unterstützung hat das.


Update: Am Samstag danach, also 2024-02-03, war ich gerade auf dem Rückweg nach Hause, als ich überlegte, noch eine Apotheke aufzusuchen, um endlich mein Rezept einzulösen. Aber nach der obigen Erfahrung würde ich ungerne in der Apotheke stehen ohne Rezept im System. Also dachte ich mir, dass es doch eine Möglichkeit geben müsste zu überprüfen, ob ich jetzt ein E-Rezept habe oder nicht.

Gibt es.

Die App erfordert aber eine Anmeldung bei der Krankenversicherung. Gut, dass ich erst vor zwei Monaten die App eingerichtet habe. Schlecht, dass es offensichtlich eine weitere Authentifizierung braucht, weil Rezepte als Daten mit erhöhten Sicherheitsbedarf gelten. Ich kann mich also per Personalausweis plus PIN oder per Gesundheitskarte plus PIN authentifizieren.

Es gehört natürlich nicht viel Fantasie dazu sich vorzustellen, dass ich weder die eine noch die andere PIN auf dem Rückweg nach Hause dabei habe. Bei der Gesundheitskarte ist mir nicht einmal klar, ob ich jemals eine PIN dafür zugesandt bekommen habe. Ich kann mich nur an einen Einmal-Code erinnern, mit dem ich mich initial bei der App anmelden konnte.

War also nix. Hatte eh keine Apotheke gefunden, die nach 14 Uhr noch auf hat und gut gelegen war.

Mir fiel dabei nur auf, dass beide Apps zwingend eine App-PIN festlegen wollten. Mir geht so was ja auf die Nerven, schließlich ist mein Handy bereits gesichert, vermutlich sicherer als die Apps es könnten.

Mastodon als Kommentarsystem für Nikola

Ich bin sicher nicht der erste, der Mastodon als Kommentarsystem einsetzen wollte. Immerhin waren es Blogbeiträge zum Thema, weswegen ich das überhaupt aufgreifen wollte. Aber anscheinend gab es vor mir niemanden, der das für Nikola umgesetzt hat.

Nun hatte ich mir Nikola ja deswegen ausgesucht, weil es in Python geschrieben ist und ich Python als sehr lesbare und einsteigerfreundliche Sprache ansehe. Zu recht, wie ich nach dieser Arbeit erneut feststellen muss.

tl;dr: https://github.com/MasinAD/nikola-mastodoncomments/ ist das Ergebnis.

Für ausgiebige Erklärungen, was da passiert, verweise ich lieber auf meine Inspirationsquellen:

Grob formuliert, funktioniert das so:

  1. Ich schreibe einen Blog-Eintrag.

  2. Ich verlinke in einem Mastodon-Beitrag auf meinen Blog-Eintrag.

  3. Ich notiere die ID meines Mastodon-Beitrags.

  4. Ich füge dem Blog-Beitrag diese ID als zusätzliches Meta-Datum hinzu.

Das Plugin kann dann auf der Basis dieser ID die Antworten auf den Beitrag laden, sofern der Beitrag nicht in der Sichtbarkeit beschränkt ist. Die hohe Kunst ist dann sicher, aus der Antwort der Mastodon-Instanz hübsch aufbereitete Kommentar-Beiträge unterhalb des Blog-Eintrags zu machen. Um den Teil habe ich mich bislang nicht weiter gekümmert, aber nach dem, was ich gesehen habe, werde ich mit der bisherigen Arbeit sicher nicht glücklich sein.

Das Plugin lädt mittels API den Context des Beitrags. Dieser enthält das Attribut descendants mit Referenzen auf alle Antworten auf die ID. Das ist aber erstmal nur flach und erfordert die Auswertung der jeweiligen Attribute id und in_reply_to_id. Derzeit werden nur Antworten auf Kommentare ein Mal eingerückt, aber das geht bestimmt auch noch besser.

Zeitzonen-Spaß mit Nextcloud

Ich habe meine heutige Neuerstellung meines Kontos bei meiner Nextcloud mal genutzt, die Einrichtung der Kalender auf meinen Androiden zu vervollständigen. Mittels "Google Integration" habe ich mein Google Drive sowie Kalender, Kontakte usw. zu Nextcloud synchronisiert.

Android beherrscht von Haus aus kein CalDAV, einen Kalenderstandard, aber es gibt DAVx, was (nicht nur) CalDAV synchronisiert und als Kalender-Anbieter auf dem Androiden auftritt. Zur Anzeige von CalDAV-Kalendern habe ich mir Etar installiert.

Jetzt fiel mir auf, dass zwei morgige Termine kollidierten. Aber auch nur bei Nextcloud. Nach kurzem Grübeln fiel auf, dass ein Termin ein wiederholender Termin ist, der eine Stunde früher als eigentlich eingestellt begann. Das sah schon so aus, als hätte es was mit dem Wechsel von Sommer- zu Winterzeit zu tun. Es stellte sich heraus: Entweder speichert Google generell alle Termine mit UTC als Zeitzone und interpretiert erst bei Anzeige den endgültigen Wert, oder die Google-Integration hat beim Abgleich Mist gebaut und die Zeitzone irgendwie auf UTC gesetzt, den Zeitstempel aber gelassen.

Ich habe zu wenig Ahnung von den beteiligten Komponenten, um tief ins Debugging einzusteigen. Aber ich konnte den Termin immerhin damit "reparieren", dass ich im Nextcloud-Kalender den ersten Termin suchte und dort bei den Uhrzeiten eine Zeitzone (Europe/Berlin) einstellte. Das hat erstmal nur bis Ende Oktober geholfen, bis zum Wechsel von Sommer- auf Winterzeit. Beim ersten, wieder abweichenden Termin habe ich das Prozedere wiederholt. Das hat anscheinend das Problem auch über den nächsten Sommerzeit-Wechsel hinweg gelöst.

Aus irgendeinem Grund waren die Termine auf einem der beiden Androiden dann aber um 7 Stunden verschoben. Ich würde meinen, Nextcloud war dieses Mal unschuldig. Es hat aber ein Weilchen gedauert, bis ich in den allgemeinen Einstellungen von Etar die "Heimatzeitzone" entdeckte, die merkwürdigerweise auf "Chinesische Normalzeit GMT+8" oder so eingestellt war. Nachdem ich das auf "Europäische Normalzeit GMT+1" zurückgestellt hatte, war auch im Kalender wieder alles okay.

Update 2023-12-19 23:58:00

Links gesetzt. Die beteiligten Android-Apps stammen alle aus dem F-Droid-Repository. Der Plan ist es, sukzessive die Abhängigkeit von Google zu reduzieren.

Umzug auf Nikola

Als die Familie im Urlaub war und mich verantwortungsloserweise allein zuhause gelassen hat, habe ich die sturmfreie Bude genutzt und angefangen, den Familienblog, der de facto eher mein Blog ist, von Serendipity auf einen Static-Site-Generator umzustellen. Ich habe mich für Nikola entschieden. Die Geschwindigkeit vorher war auch nicht schlecht, aber schneller als jetzt geht es halt auch nicht.

Der Workflow ist anders, wobei ich sagen muss, dass es sicher daran liegt, dass ich die Einträge bislang nur konvertiert habe:

  • Ich erstelle eine Textdatei, …

  • … schreibe in die ersten paar Zeilen ein paar Metadaten …

  • … und in den Rest dann den Artikelinhalt.

Um einen Eindruck von der Formatierung zu bekommen, verwende ich lokal ReText, was sowohl RestructuredText wie auch Markdown versteht. Bin ich am Ende zufrieden, wird die Datei gespeichert und mittels nikola build die Änderungen seit dem letzten Build neu erzeugt. Die erstellten statischen Seiten muss ich dann auf den Webserver schieben. Perspektivisch überlege ich, ob nicht einfach ein Git-Repository nutze und da dann eine CI/CD-Pipeline ranbastele. Weiß aber gerade nicht, ob das aufwändiger wird.

Erste Schritte mit Flatpak

Flatpak logo

Ich habe die letzten Tage Spaß mit Flatpak-Paketierung gehabt. Meine Mädels wollten Dungeondraft haben, was für Linux wahlweise als .deb oder als .tar.gz angeboten wird. Aber ich habe ihre Rechner ja mit Silverblue aufgesetzt, und dort sind Flatpaks First-Class-Citizens. Klar, die tar-Balls hätten auch irgendwie funktioniert, aber warum nicht das Nützliche mit dem Lehrreichen verbinden? 😀

Das Paketieren hat super funktioniert. Ich hatte vor einiger Zeit mal mit Vicuna begonnen und den Flow jetzt ausgenutzt, Vicuna, Pattypan, Commonist, OpenRefine und Freemind flatpaketieren zu wollen, die bei WMDE Teil der Installation sind. Meine Recherche zu Freemind zeigte, dass die Software seit einigen Jahren schon nicht mehr weiterentwickelt wird. Ich fand dann Freeplane als Ergebnis meiner Recherche zu Mindmapping-Werkzeugen unter Linux, die noch weiterentwickelt werden. Und das gibt es auch schon als Flatpak, also musste ich da nichts mehr machen. OpenRefine ist ein Sonderfall, weil es lokal einen Server startet und die Bedienung dann im Browser stattfindet. Da weiß ich noch nicht, wie ich damit umgehen will. Vergleichbares kenne ich nur von Syncthing, aber das gibt es auch nicht "pur" als Flatpak, sondern nur mit dem einen oder andern Tray-Indicator. Aber Vicuna, Pattypan und Commonist habe ich erfolgreich paketiert gekriegt, im Falle von Vicuna sogar besser als lokal installiert, weil ich dem Flatpak ohne Probleme die passende JVM konfigurieren kann (alles über OpenJDK8 macht irgendwie Probleme mit der Konfigurationsdatei).

Der nächste Schritt wird sein, ein Repository aufzusetzen. Momentan habe ich ein lokales Repository.

Auflistung der Flatpaks im lokalen Repository

Das ist nur begrenzt nützlich. Die Flatpaks für meine Kinder will ich lokal bei mir verteilen, die Flatpaks für WMDE sollten für die damit bespielten Rechner erreichbar sein. Ich muss mir da noch was mit GPG-Signaturen und so anlesen und wie ich das dann tatsächlich verteilen soll. Ein pacman-Repository war ja recht simpel, aber ich habe noch keine Ahnung, wie das mit Flatpaks läuft.

Natürlich könnte ich die WMDE-Flatpaks auch bei Flathub einreichen, aber einer der Vorteile von Flatpaks gegenüber Snap ist ja eben, dass man das dezentral aufsetzen kann und keine zentrale Autorität braucht.

Und Dungeondraft und Wonderdraft sind kommerzielle Software, die ich nicht einfach irgendwo herunterladen lassen kann. Für die Verwendung in der Familie finde ich das noch fair, was ich mache, auch wenn ich mich rechtlich sicher in einer Grauzone bewegen sollte. Wenn Megasploot drauf bestehen sollten, kaufe ich eben zwei weitere Lizenzen dafür. Für eine Verwendung in der Familie sehe ich da aber nicht akut Handlungsbedarf.

Spotifys Familientarif

Es kam jetzt schon mehrmals vor, dass ich auf dem Heimweg Musik über Spotify hörte und plötzlich die Musik ausging. Ich konnte sie zwar wieder starten, aber kurz danach war sie wieder weg.

Zuhause hat $Familie nämlich Spotify über Google Home gestartet.

Jetzt dachte ich mir, so viel mehr kostet Spotify Premium Family auch nicht, da gönn ich mir das mal, und jede*r kriegt eigene Playlists und Verläufe …

Aber, ich habe die Rechnung ohne Spotify gemacht. Spotify bietet eine App an, Spotify Kids. Die Rezensionen ließen nichts Gutes ahnen, also dachte ich mir, ich erstelle einen normalen Account für $Kind1. Tja, Spotify verlangt ein Geburtsdatum. Gebe ich das korrekte Datum an, verweigert Spotify den Account mit Verweis darauf, dass man zu jung sei für Spotify.

Okay, also probiere ich doch erstmal die Kids-App. Melde mich dort mit meinem Konto an und erstelle ein Kids-Konto. Dann die Ernüchterung: Ich kann der App nur sagen, sie soll sich per Bluetooth mit irgendwas verbinden. Keine Auswahl der Abspielgeräte. Aber es soll ja eben die Musik über Google Home abgespielt werden!

Najut, denke ich mir, Spotify bietet Kids-Konten für 0-6 Jahre und für 5-12 Jahre an. Dann mache ich sie eben 3 Jahre älter und erstelle ein normales Konto … aber Pustekuchen! Auch dann gilt sie noch als zu jung.

Also suche ich nach dem Mindestalter für Spotify und finde: »Um die Spotify-Dienste nach diesen Allgemeinen Nutzungsbedingungen nutzen und auf Inhalte zugreifen zu können, (1) müssen Sie 18 Jahre alt oder älter sein, oder 16 Jahre alt oder älter sein und das Einverständnis Ihrer Eltern oder Ihres Vormunds zu der Vereinbarung besitzen,[…]«

Es gibt also für Kinder von 13 bis 16 Jahren keine Möglichkeit, Spotify zu nutzen, da sie zu jung für ein Konto und zu alt für ein Kids-Konto sind. Das sie selbstverständlich nutzen könnten, aber erklärt mal einem Teenager, dass sie ein Kinderkonto nutzen sollen. Zumal es gegenüber dem regulären Spotify kuratiert, limitiert und technisch beschnitten ist. Jedenfalls motivieren mich diese Einschränkungen nicht, mehr Geld für den Familientarif zu zahlen.

Grundsätzlich frage ich mich, welchen Sinn der Familientarif überhaupt hat, wenn die Hauptnutzerïnnen im Alter von 12 bis 16 Jahren den Dienst nicht nutzen können, wie sie wollen. Und Familienmitglieder über 18 Jahre am selben Wohnort sind eine verschwindend kleine Gruppe. Viele Kinder können es gar nicht erwarten auszuziehen, selbst wenn ich meinen Kindern anbiete, dass sie bis zum Ende ihres Studiums bei uns wohnen können, was wohl so mit 24 Jahren sein dürfte.

Soziale Videokonferenzen

Gestern kam endlich die Mail vom Chef: Die Weihnachtsfeier wurde abgesagt!

Sehr beruhigend. Ich habe ja darauf gehofft und damit gerechnet, so dass ich mir schon Gedanken gemacht habe, wie wir die Feier dann virtuell abhalten können. Klar, per Video, aber Teams ist denkbar ungeeignet zum Socialisen. Was gibt es denn so an Alternativen, die nicht alle strunzlangweilig aussehen?

Als erstes fiel mir https://wonder.me ein, das ich auch schon benutzt habe. Ich mag die dynamische Erstellung von kleinen Plauschzirkeln, das kommt einer Party-Dynamik näher als das umständliche Erstellen von Breakout-Räumen. Negativ fällt mir auf, dass die Areas von wonder.me leider nicht weiter anpassbar sind und auch ansonsten eher keine Funktion erfüllen.

Vor einem halben Jahr oder so stieß ich aber noch auf einen anderen Dienst, dessen Name mir aber nicht mehr einfallen wollte. Tipp: Wenn etwas so halbwegs interessant ist, anmelden und Newsletter abonnieren. Dann vergisst man das nicht mehr. Jedenfalls habe ich mich auf die Suche nach Alternativen zu wonder.me gemacht und fand dann auch https://gather.town wieder. Da kann man aus Vorlagen auswählen oder mit einem Tile-Editor eigene Räume im 8-Bit-Stil entwerfen. Einfache Interaktionen mit der Karte sind auch möglich.

Unter https://www.hyhyve.com/ gibt es einen weiteren Dienst, der ähnlich wie wonder.me funktioniert, aber rudimentäre Karten bietet. Ich habe jetzt nicht gesehen, dass man da eigene hochladen kann, aber ab 499 USD kann man sich welche von denen designen lassen.

https://spatial.chat/ wirkt wie Gather Town auf Steroiden. Bislang habe ich da noch keinen Test durchführen können – mir wurde noch kein Raum bereitgestellt. Die Optik auf deren Website sieht jedenfalls schnieke aus. Inwiefern das anpassbar ist, kann ich derzeit aber noch nicht sagen.

Die Website, die mich mit all diesen Links versorgt hat, https://www.micestens-digital.de/tools-fuer.../, erwähnt aber auch einen Dienst namens "Unhangout". Hangout, wissen wir, hat Gruppen-Videochats ja erst so halbwegs populär gemacht, weswegen der Name meine Neugierde geweckt hat. Es handelt sich um eine Open-Source-Lösung, die am MIT entwickelt oder zumindest dokumentiert wird: https://unhangout.media.mit.edu/. Mit den anderen hier genannten Lösungen hat es jetzt nicht so viel gemein, aber als Alternative zu Big Blue Button kann man es sich mal anschauen.

Erwähnenswert ist auch noch https://www.butter.us/, das ich, glaube ich, mal im Rahmen einer Veranstaltung eines Freundes kennenlernen durfte. Es sticht durch zahlreiche Integrationen von Anwendungen heraus.

https://www.welo.space/ habe ich dann schon nicht mehr weiter angeschaut, könnte aber auch interessant sein.

Update 2021-12-01 21:45: Eine ehemalige Kollegin machte mich auf https://workadventu.re aufmerksam. Nice. Die Video-Einbindung ist nicht so transparent wie bei den anderen, aber für komplett open-source ist das schon beeindruckend. Für die Video-Komponente wird auf Jitsi Meet zurückgegriffen. Ich bin gespannt, ob das von deren Ansible-Playbook mitinstalliert wird oder ob ich das selbst bereitstellen muss.

Inkscape: Grafische Editoren, Beschreibungssprachen und ihre Tücken

Anfang bis Mitte der 90er habe ich ja sehr ausgiebig den freien Raytracer POV-Ray genutzt. Auch wenn ich mich immer wieder mal an Moray gewagt habe – mit 3D-Modellierern wurde ich nicht wirklich warm. Die Szenenbeschreibungssprache (SDL, scene description language) von POV-Ray wiederum lag mir sehr. Und es hat mir auch wunderbar dabei geholfen, boolesche Operationen auf Mengen (Vereinigung, Differenz, Schnittmenge usw.) sowie Vektorrechnung zu verstehen. Grundsätzlich war die SDL hervorragend geeignet zur Beschreibung dreidimensionaler Szenen.

Eine Kugel wurde da bspw. als Menge aller Punkte definiert, die einen Abstand r von einem Punkt z haben. Damit war eine Kugel wirklich eine Kugel und keine Menge an Dreiecken, die nur in Annäherung eine Kugel ergeben.

Wenn ich eine Differenz zwischen der Kugel und einer Ebene durch den Mittelpunkt der Kugel bildete, bekam ich eine Halbkugel. Ebenso bei der Schnittmenge in diesem Fall, dann jedoch die andere Halbkugel.

Es hat sich in vielerlei Hinsicht als sinnvoll erwiesen, die Objekte im Ursprung zu entwerfen und erst am Ende zu skalieren und zu translatieren (bewegen). Eine Kugel, die bei <0,0,0> definiert ist, verhält sich nämlich anders als eine Kugel, die bei <1,0,0> definiert ist. Skaliere ich beide Kugeln um 2, bleibt erstere mit ihrem Mittelpunkt an Ort und Stelle, letztere bewegt sich um den Skalierungsfaktor entlang der x-Achse, da all ihre Punkte um den Faktor skaliert werden. Und Translationen finden dann ganz zum Schluss statt, wenn das Objekt die passende Größe hat, denn eine Skalierung am Ende würde auch die Translation skalieren.

SVG wiederum ist XML. XML ist eine Auszeichnungssprache. Das heißt grob, dass mit XML irgendwelche menschenlesbaren Texte oder Werte ausgezeichnet werden, damit sie maschinenlesbar und -interpretierbar sind. Schon MathML zur Auszeichnung mathematischer Ausdrücke hat mich in seiner Unleserlichkeit schockiert, SVG ist nur graduell besser. Beide Sprachen kranken meiner Meinung nach daran, dass sie den Gegenstand des Interesses (mathematische Ausdrücke einerseits, 2D-Vektorgrafik andererseits) krampfhaft in XML verpacken wollten. Aber jut, so isses halt. Vermutlich ging es darum, mittels CSS und JavaScript auf die jeweiligen Dokumente zugreifen zu können, und das DOM existierte ja schon für (X)HTML. Ich habe aber auch nur sehr wenige MathML- und SVG-Inhalte im Web gesehen und noch weniger dynamisch mit JavaScript manipulierte. Wobei das ziemlich cool wäre. Aber ich vermute HTML5's canvas-Element hat SVG hier überflüssig gemacht

Vergleich zwischen LaTeX und MathML anhand der quadratischen Gleichung

Was mich aber fuchst, ist die primitive Form der booleschen Operationen: Wenn ich einen Kreis mit einem Rechteck vereinige, dann werden beide Formen zu einem Pfad. Ihre ursprüngliche Natur geht dabei verloren und sie lassen sich auch nicht mehr ohne weiteres trennen oder auch nur in ihren Parametern verändern, es sei denn ich bearbeite die Knoten des Pfades manuell.

Eine andere Sache ist das Koordinatensystem. Zumindest bei Pfaden gibt es sowohl absolute als auch relative Angaben. Und Inkscape nutzt dynamisch, was gerade opportun ist: Ist der Pfad am Ursprung <0,0> definiert, sind es absolute, ansonsten zumeist relative Werte. Aber eben auch nicht immer. Manchmal wechselt Inkscape da auch einfach innerhalb eines Pfades. Tatsächlich kann ich keinerlei Grund für die Existenz absoluter Werte erkennen außer für den Startpunkt.

Ein Workaround wäre es vielleicht, alle Objekte in eine (eigene) Gruppe zu stecken. Denn gruppierte Objekte werden nicht mehr weiter angefasst bei Transformationen. Stattdessen erhält das Gruppenobjekt alle Transformationen wie Skalierungen und Translationen. Denn natürlich gibt es mehr als einen Weg, Objekten ihren endgültigen Ort zuzuweisen.

Eine zusätzliche Herausforderung sind die Farb-Definitionen (hier mal als Sammelbegriff für alles, was mit Konturfarben und Füllfarben zu tun hat). Ich weiß nicht, ob SVG das so erfordert, aber Inkscape macht es so: Alle komplexeren Farbinformationen wie Farbverläufe oder Filter werden nur im style-Attribut referenziert. Ihre tatsächliche Definition liegt in einem speziellen defs-Element. Und natürlich haben Verläufe absolute statt objekt-relativer Koordinaten. Wenn ich also programmatisch ein Element irgendwo hinsetze, dann muss ich auch seine referenzierten Definitionen entsprechend transformieren.

Die Probleme, die ich mit SVG habe (und ich bin eigentlich ein SVG-Fan, seit ich erstmals von SVG gehört habe), beruhen teilweise auf dem Format, teilweise auf Inkscape, was ich zur Erstellung nutze. Um SVG sinnvoll in einem programmatischen Kontext nutzen zu können, müssen allen Elementen id-Attribute zugewiesen werden, aber Inkscape erzeugt die für viele Elemente automatisch und erlaubt nur bei einer Teilmenge die manuelle Änderung der id. Aus einer Usability-Perspektive kann ich das nachvollziehen, zwingt mich jetzt aber dazu, entweder das erzeugte SVG komplett zu überarbeiten oder aber mir SVG-Fragmente aus meinem SVG zu nehmen und sie programmatisch erneut zu erzeugen, aber mit selbst definierten id-Attributen.

Und letzteres mache ich gerade für das D&D-Overlay. Vorbereitend erstelle ich das Gerüst nochmal sauber mit am Ursprung verankerten Koordinaten, ebenso alle Teilstücke. Dann entnehme ich die Teilstücke der SVG-Datei und füge sie in ein Pythonskript und vergebe id's vom Format "rangNzauberplatzM" als Präfix vor den drei Kreisen, aus denen die "Kugeln" bestehen. Am Ende ist das hoffentlich nur noch ein großes Puzzle, das ich wieder zusammensetzen muss. Wenn die Elemente und ihre referenzierten Definitionen alle am Ursprung entworfen sind, kann ich mittels einer abschließenden Transformation alles dorthin setzen, wo ich es brauche. Inkscape unterstützt solch einen Workflow leider nur mäßig. Andererseits kann ich mich ja auch dazu zwingen, alles einzeln in Inkscape zu entwerfen und erst am Ende zusammenzusetzen, wie ich es ja auch gerade tue.