Gemeinsame Funktionen
Wird von allen anderen Skripten eingebunden: Ziel über TV_HOST, Verbindungsprüfung mit klarer Fehlermeldung (unauthorized, offline), Paketprüfung über pm list packages, sicheres Quotieren.
TV_HOST=tv.example.org:5555 ./tv-info.shanderes Ziel für einen einzelnen Aufruf
#!/usr/bin/env bash
# tv-lib.sh – gemeinsame Funktionen für die Android-TV-Skripte (VisualAndroidTV)
#
# Wird von den anderen tv-*.sh-Skripten eingebunden, nicht direkt gestartet:
# . "$(dirname "$0")/tv-lib.sh"
#
# Voraussetzungen:
# - Android SDK Platform-Tools (adb) auf dem Rechner
# - Entwickleroptionen + USB-/Netzwerk-Debugging auf dem EIGENEN Fernseher eingeschaltet
# - Freigabedialog „USB-Debugging zulassen?“ am Fernseher einmal bestätigt
#
# Ziel wählen (Beispieladresse aus dem Dokumentationsnetz 192.0.2.0/24):
# TV_HOST=192.0.2.50:5555 ./tv-info.sh
# TV_HOST=tv.example.org:5555 ./tv-info.sh
TV_HOST="${TV_HOST:-192.0.2.50:5555}" # Adresse:Port des Fernsehers (adbd lauscht auf TCP 5555)
ADB="${ADB:-adb}" # Pfad zum adb-Programm
TV_USER="${TV_USER:-0}" # Android-Benutzer; 0 = Hauptbenutzer
tv_die() { printf 'Fehler: %s\n' "$*" >&2; exit 1; }
tv_info() { printf '%s\n' "$*" >&2; }
# Prüft, ob adb installiert ist.
tv_need_adb() {
command -v "$ADB" >/dev/null 2>&1 \
|| tv_die "adb nicht gefunden – Android SDK Platform-Tools installieren."
}
# Zustand des Ziels laut „adb devices“: device | offline | unauthorized | (leer)
tv_state() {
"$ADB" devices | tr -d '\r' | awk -v h="$TV_HOST" '$1 == h { print $2 }'
}
# Stellt die Verbindung her (falls nötig) und bricht mit klarer Meldung ab, wenn sie nicht steht.
tv_connect() {
tv_need_adb
local state
state="$(tv_state)"
if [ "$state" != "device" ]; then
"$ADB" connect "$TV_HOST" >/dev/null 2>&1 || true
state="$(tv_state)"
fi
case "$state" in
device) return 0 ;;
unauthorized)
tv_die "$TV_HOST ist nicht freigegeben – Dialog „USB-Debugging zulassen?“ am Fernseher bestätigen." ;;
offline)
tv_die "$TV_HOST ist offline – Fernseher einschalten oder „adb disconnect“ und erneut versuchen." ;;
*)
tv_die "Keine Verbindung zu $TV_HOST – Adresse, Netzwerk und Debugging-Einstellung prüfen." ;;
esac
}
# adb gezielt für diesen Fernseher aufrufen.
tv_adb() { "$ADB" -s "$TV_HOST" "$@"; }
# Shell-Befehl auf dem Fernseher; -n verhindert, dass adb die Standardeingabe des Skripts verbraucht.
tv_shell() { tv_adb shell -n "$@"; }
# Wie tv_shell, aber ohne Wagenrücklauf am Zeilenende (ältere Geräte liefern \r\n).
tv_out() { tv_shell "$@" | tr -d '\r'; }
# Text für die Shell AUF DEM FERNSEHER in einfache Anführungszeichen setzen.
tv_quote() {
local s=$1
s=${s//\'/\'\\\'\'}
printf "'%s'" "$s"
}
# API-Level des Fernsehers (z. B. 33 für Android 13).
tv_sdk() { tv_out getprop ro.build.version.sdk; }
# Paketlisten einmal laden (spart viele einzelne adb-Aufrufe).
TV_PKG_INSTALLED=""
TV_PKG_DISABLED=""
TV_PKG_KNOWN=""
tv_load_packages() {
TV_PKG_INSTALLED="$(tv_out pm list packages --user "$TV_USER")"
TV_PKG_DISABLED="$(tv_out pm list packages -d --user "$TV_USER")"
TV_PKG_KNOWN="$(tv_out pm list packages -u --user "$TV_USER")"
}
# Zustand eines Pakets: aktiv | deaktiviert | entfernt | fehlt
# entfernt = für den Benutzer deinstalliert, liegt aber noch im System (wiederherstellbar)
# fehlt = auf diesem Gerät unbekannt
tv_pkg_state() {
local line="package:$1"
[ -n "$TV_PKG_KNOWN" ] || tv_load_packages
if grep -qxF -- "$line" <<<"$TV_PKG_DISABLED"; then
echo "deaktiviert"
elif grep -qxF -- "$line" <<<"$TV_PKG_INSTALLED"; then
echo "aktiv"
elif grep -qxF -- "$line" <<<"$TV_PKG_KNOWN"; then
echo "entfernt"
else
echo "fehlt"
fi
}
# Paketnamen aus einer Liste lesen: eine Zeile je Paket, # leitet Kommentare ein.
tv_read_list() {
[ -r "$1" ] || tv_die "Liste nicht lesbar: $1"
sed -e 's/#.*$//' -e 's/^package://' -e 's/[[:space:]]//g' "$1" | grep -v '^$' || true
}
# Nur Zeichen zulassen, die in Paketnamen vorkommen.
tv_valid_package() {
case "$1" in
""|*[!A-Za-z0-9._]*) return 1 ;;
*.*) return 0 ;;
android) return 0 ;;
*) return 1 ;;
esac
}