Benutzer-Werkzeuge

Webseiten-Werkzeuge


hackspace:ausstattung:tv:tvheadend:tvheadend

TV-Headend

Dokumentation

TvHeadend kann tvkarten verarbeiten und streamen.

Es nutzt tunebare v4l devices.

Docker Run (einfach testen)

docker run -d \
  --name tvheadend2 \
  --restart unless-stopped \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Europe/Berlin \
  -e RUN_OPTS="" \
  -p 9981:9981 \
  -p 9982:9982 \
  -v /yacht/AppData/tvheadend2/data:/config \
  -v /yacht/AppData/tvheadend2/recordings:/recordings \
  --device /dev/dri:/dev/dri \
  --device /dev/dvb:/dev/dvb \
  lscr.io/linuxserver/tvheadend:latest

Dauereinsatz (Grundlage)

#!/usr/bin/env bash
#
# tvheadend2-manage.sh
#
# Management-Script für den TVHeadend-Docker-Container "tvheadend2":
#   - install   : Erstinstallation / Neuinstallation
#   - update    : Image aktualisieren + Container neu erstellen
#   - clean     : Container stoppen + löschen (Daten bleiben erhalten)
#   - remove    : Alias für "clean"
#   - purge     : Container + Image + (optional) Daten löschen
#   - logs      : Logs anzeigen (follow)
#   - status    : Status anzeigen
#   - shell     : Shell im Container öffnen
#
# Unterstützt variable Basis-Verzeichnisse:
#   - /yacht/AppData/tvheadend2
#   - /srv/docker/tvheadend2
#

set -euo pipefail

########################################
# Konfiguration
########################################

# Name des Containers
CONTAINER_NAME="tvheadend2"

# Docker-Image
IMAGE_NAME="lscr.io/linuxserver/tvheadend:latest"

# Standard-Ports (Host:Container)
HTTP_PORT="9981"
HTSP_PORT="9982"

# Mögliche Basisverzeichnisse (Host)
BASE_DIR_CANDIDATES=(
  "/yacht/AppData/tvheadend2"
  "/srv/docker/tvheadend2"
)

# Effektives Basisverzeichnis bestimmen
BASE_DIR=""
for c in "${BASE_DIR_CANDIDATES[@]}"; do
    if [ -d "$c" ]; then
        BASE_DIR="$c"
        break
    fi
done

# Falls noch keins existiert: erstes als Default nehmen und anlegen
if [ -z "$BASE_DIR" ]; then
    BASE_DIR="${BASE_DIR_CANDIDATES[0]}"
    mkdir -p "$BASE_DIR"
fi

CONFIG_DIR="$BASE_DIR/data"
RECORDINGS_DIR="$BASE_DIR/recordings"

# Default-UID/GID (bei Bedarf anpassen)
PUID="${PUID:-1000}"
PGID="${PGID:-1000}"

########################################
# Hilfsfunktionen
########################################

log() {
    echo "[tvh2-manage] $*"
}

ensure_dirs() {
    log "Erzeuge Verzeichnisse (falls nicht vorhanden):"
    log "  CONFIG_DIR    = $CONFIG_DIR"
    log "  RECORDINGS_DIR= $RECORDINGS_DIR"

    mkdir -p "$CONFIG_DIR" "$RECORDINGS_DIR"

    # Rechte setzen (damit der Container schreiben kann)
    log "Setze Eigentümer auf PUID=$PUID, PGID=$PGID"
    chown -R "$PUID:$PGID" "$BASE_DIR"
}

container_exists() {
    docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"
}

container_running() {
    docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"
}

########################################
# Aktionen
########################################

do_install() {
    log "Starte INSTALL für $CONTAINER_NAME mit Image $IMAGE_NAME"
    ensure_dirs()

    if container_exists; then
        log "Container $CONTAINER_NAME existiert bereits – entferne alte Instanz..."
        docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
        docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
    fi

    log "Pull neues Image..."
    docker pull "$IMAGE_NAME"

    log "Starte neuen Container mit --restart unless-stopped"
    docker run -d \
        --name "$CONTAINER_NAME" \
        --restart unless-stopped \
        -e PUID="$PUID" \
        -e PGID="$PGID" \
        -e TZ="Europe/Berlin" \
        -e RUN_OPTS="" \
        -p "${HTTP_PORT}:9981" \
        -p "${HTSP_PORT}:9982" \
        -v "${CONFIG_DIR}:/config" \
        -v "${RECORDINGS_DIR}:/recordings" \
        --device /dev/dri:/dev/dri \
        --device /dev/dvb:/dev/dvb \
        "$IMAGE_NAME"

    log "Install/Neu-Deploy abgeschlossen. Web-GUI sollte unter http://<host>:${HTTP_PORT}/ erreichbar sein."
}

do_update() {
    log "Starte UPDATE für $CONTAINER_NAME"

    ensure_dirs

    if ! container_exists; then
        log "Container existiert nicht. Führe stattdessen INSTALL aus."
        do_install
        return
    fi

    log "Pull neues Image..."
    docker pull "$IMAGE_NAME"

    log "Stoppe alten Container..."
    docker stop "$CONTAINER_NAME" || true

    log "Entferne alten Container..."
    docker rm "$CONTAINER_NAME" || true

    log "Starte Container mit neuem Image..."
    docker run -d \
        --name "$CONTAINER_NAME" \
        --restart unless-stopped \
        -e PUID="$PUID" \
        -e PGID="$PGID" \
        -e TZ="Europe/Berlin" \
        -e RUN_OPTS="" \
        -p "${HTTP_PORT}:9981" \
        -p "${HTSP_PORT}:9982" \
        -v "${CONFIG_DIR}:/config" \
        -v "${RECORDINGS_DIR}:/recordings" \
        --device /dev/dri:/dev/dri \
        --device /dev/dvb:/dev/dvb \
        "$IMAGE_NAME"

    log "Update abgeschlossen."
}

do_clean() {
    log "CLEAN: Container stoppen und löschen (Daten bleiben erhalten)."

    if container_running; then
        log "Stoppe laufenden Container..."
        docker stop "$CONTAINER_NAME" || true
    fi

    if container_exists; then
        log "Entferne Container..."
        docker rm "$CONTAINER_NAME" || true
    else
        log "Container existiert nicht – nichts zu tun."
    fi
}

do_purge() {
    log "PURGE: Container, Image und optional Daten löschen."

    # 1) Container stoppen/entfernen
    do_clean

    # 2) Image löschen
    if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${IMAGE_NAME}$"; then
        log "Entferne Image $IMAGE_NAME..."
        docker rmi "$IMAGE_NAME" || true
    else
        log "Image $IMAGE_NAME nicht gefunden – überspringe."
    fi

    # 3) Daten löschen (nur nach expliziter Bestätigung)
    echo
    echo "WARNUNG: Sollen auch die Datenverzeichnisse gelöscht werden?"
    echo "  CONFIG_DIR    = $CONFIG_DIR"
    echo "  RECORDINGS_DIR= $RECORDINGS_DIR"
    read -r -p "WIRKLICH ALLES LÖSCHEN? (yes/NO): " ans

    if [ "$ans" = "yes" ]; then
        log "Lösche Datenverzeichnisse..."
        rm -rf "$CONFIG_DIR" "$RECORDINGS_DIR"
        log "Daten entfernt."
    else
        log "Daten bleiben erhalten."
    fi
}

do_logs() {
    log "Zeige Logs von $CONTAINER_NAME (Ctrl+C zum Beenden)..."
    docker logs -f "$CONTAINER_NAME"
}

do_status() {
    log "Status von $CONTAINER_NAME:"

    if container_running; then
        echo "  - Container läuft."
    elif container_exists; then
        echo "  - Container existiert, läuft aber nicht."
        echo "  - Letzter Exit-Code siehe: docker inspect $CONTAINER_NAME"
    else
        echo "  - Container existiert nicht."
    fi

    echo
    echo "Gemappte Verzeichnisse:"
    echo "  BASE_DIR      = $BASE_DIR"
    echo "  CONFIG_DIR    = $CONFIG_DIR (-> /config)"
    echo "  RECORDINGS_DIR= $RECORDINGS_DIR (-> /recordings)"

    echo
    echo "Image:"
    docker images | grep -E 'REPOSITORY|tvheadend|linuxserver/tvheadend|lscr.io/linuxserver/tvheadend' || true

    echo
    echo "Container:"
    docker ps -a | grep -E 'CONTAINER ID|tvheadend2' || true
}

do_shell() {
    if ! container_running; then
        log "Container läuft nicht – starte ihn kurz an..."
        docker start "$CONTAINER_NAME" >/dev/null 2>&1 || true
    fi

    log "Öffne Shell im Container..."
    docker exec -it "$CONTAINER_NAME" bash 2>/dev/null || docker exec -it "$CONTAINER_NAME" sh
}

########################################
# Main
########################################

ACTION="${1:-}"

case "$ACTION" in
    install)
        do_install
        ;;
    update)
        do_update
        ;;
    clean|remove)
        do_clean
        ;;
    purge)
        do_purge
        ;;
    logs)
        do_logs
        ;;
    status)
        do_status
        ;;
    shell)
        do_shell
        ;;
    *)
        echo "Usage: $0 {install|update|clean|remove|purge|logs|status|shell}"
        echo
        echo "  install : Container (neu) erstellen mit restart=unless-stopped"
        echo "  update  : Image pullen + Container neu erstellen"
        echo "  clean   : Container stoppen + löschen (Daten bleiben)"
        echo "  remove  : Alias für clean"
        echo "  purge   : Container+Image und optional Daten löschen"
        echo "  logs    : docker logs -f"
        echo "  status  : Übersicht über Container/Image/Verzeichnisse"
        echo "  shell   : Shell in laufendem Container öffnen"
        exit 1
        ;;
esac
/app/www/public/data/pages/hackspace/ausstattung/tv/tvheadend/tvheadend.txt · Zuletzt geändert: von spock0010