#!/bin/bash
TG="$1"

([ "$TG" = "" ] && TG=7)

# cleanchannels.sh - Kanalliste des VDR aufräumen
# Author: MegaV0lt, Version: 20121108

# Funktionsweise:
# 1. Die channels.conf wird gesichert (channels.conf.bak).
# 2. Die channels.conf.bak wird zeilenweise nach Markern ("-OLD-") durchsucht.
#    a) Kanäle mit Marker werden in die channels.conf.removed geschrieben.
#    b) Kanäle ohne Marker werden (neu) markiert und in die channels.conf.new
#+      geschrieben.
# 3. Wenn der VDR nicht läuft, wird die channels.conf.new nach channels.conf
#+   kopiert.

# Die Marker werden beim Provider angelegt (nach dem ;) sind also in der
#+Kanalliste nicht sichtbar.

# Das Skript sollte etwa ein mal im Monat (Vorgabe: 25 Tage) ausgeführt werden.
# Bei Systemen mit nur einem Tuner sollte zur Sicherheit ein größerer Intervall
#+gewählt werden (100 Tage oder mehr). Am besten direkt vor dem VDR-Start mit
#+Parameter für die Tage, die der VDR Zeit bekommen soll, seine Kanalliste zu
#+aktualisieren. Im VDR sollte die Option "EPG aktualisieren" aktiv sein.
# Beispiel:
# /usr/local/sbin/cleanchannels.sh 25 # Alle 25 Tage starten (Vorgabe)

# Um das Skript unter Gen2VDR V3 vor dem VDR zu starten, kann die Datei
#+8000_cleanchannels wie folgt unter /etc/vdr.d angelegt werden:
# echo "/usr/local/sbin/cleanchannels.sh 25" > /etc/vdr.d/8000_cleanchannels


# Einstellungen
CHANNELSCONF=/var/lib/vdr/channels.conf
OLDMARKER="OBSOLETE_"                       # Markierung (Keine ~ ; : verwenden!)
DAYS=0                                 # Liste alle XX Tage prüfen
CHANNELSNEW=${CHANNELSCONF}.new         # Neue Kanalliste
CHANNELSBAK=${CHANNELSCONF}.bak         # Kopie der Kanalliste
CHANNELSREMOVED=${CHANNELSCONF}.removed # Gelöschte Kanäle
SETUPCONF=/var/lib/vdr/setup.conf           # VDR Einstellungen (Wird nur gelesen)
marker=0 ; removed=0 ; marked=0         # Für die Statistik

# Funktionen
function log() {     # Gibt die Meldung auf der Konsole und im Syslog aus
  logger -s -t $(basename ${0%.*}) "$1"
}

# Skript start!

if [ -n "$TG" ] ; then # Falls dem Skript die Tage übergeben wurden.
   [[ $TG == [0-9]?([0-9])?([0-9]) ]] && DAYS=$TG   # 0-999 erlaubt
fi

if [ -e ${CHANNELSNEW} -a $DAYS -ne 0 ] ; then # Erster Start?
   ACT_DATE=$(date +%s) ; FDATE=$(stat -c %Y "${CHANNELSNEW}")
   DIFF=$(($ACT_DATE - $FDATE))     # Sekunden
   if [ $DIFF -lt $(($DAYS*60*60*24)) ] ; then
      log "Letzte Ausführung vor ~ $(($DIFF/24/60/60)) Tag(en)! Stop."
      exit 0                        # Letzter Start vor weniger als XX Tage!
   fi
else                                # Erster Start? Erzwungener Start ($1=0)?
   log "Erster/Erzwungener Start des Skript's"
fi

while read -r LINE ; do # Hier werden verschiedene VDR-Optionen geprüft
      if [[ "$LINE" == "EPGScanTimeout = 0" ]] ; then
         log "WARNUNG: EPG-Scan ist deaktiviert! (${LINE})"
      fi
      if [[ "$LINE" == "UpdateChannels = 0" ]] ; then
         log "FATAL: Kanäle aktualisieren ist deaktiviert! (${LINE})"
         exit 0      # Ohne Kanalaktualisierung geht das hier nicht!
      fi
done < ${SETUPCONF}  # VDR-Einstellungen

if [ ! -e ${CHANNELSCONF} ] ; then  # Prüfen, ob die channels.conf existiert
   log "${CHANNELSCONF} nicht gefunden!"
   exit 0
fi

cp -f ${CHANNELSCONF} ${CHANNELSBAK}          # Kanalliste kopieren
[ -e ${CHANNELSNEW} ] && rm -f ${CHANNELSNEW} # Frühere Liste löschen
OLDIFS="${IFS}"                               # Interner Feldtrenner

# Die $CHANNELSREMOVED sammelt die gelöschten Kanäle. Markierung setzen, um
#+später leichter zu sehen, wann die Kanäle entfernt wurden.
echo ":==> Entfernt am $(date "+%d.%m.%Y %R")" >> ${CHANNELSREMOVED}

while read -r CHANNEL ; do
    if [ "${CHANNEL:0:1}" = ":" ] ; then     # Marker auslassen (: an 1. Stelle)
       echo ${CHANNEL} >> ${CHANNELSNEW}     # In die neue Liste
       (( marker++ ))
       continue
    fi
    if [[ "${CHANNEL}" =~ "${OLDMARKER}" ]] ; then # Markierung gefunden?
       echo ${CHANNEL} >> ${CHANNELSREMOVED}       # Kanal nach *.removed
       (( removed++ ))
    else                                           # Keine Markierung
        IFS=:                                      # Daten sind mit : getrennt
        CHANNELDATA=(${CHANNEL})                   # In Array einfügen
        if [[ "${CHANNELDATA[0]}" =~ ";" ]] ; then
           CHANNEL=${CHANNEL/;/;$OLDMARKER}        # Marker einfügen (Provider)
        else                                       # Kein Provider gefunden
           CHANNELDATA[0]="${CHANNELDATA[0]};$OLDMARKER"
           CHANNEL="${CHANNELDATA[*]}"             # Aus dem Array -> Variable
        fi
        echo "${CHANNEL}" >> ${CHANNELSNEW}        # In die neue Liste
        IFS="$OLDIFS"
        (( marked++ ))
    fi
done < ${CHANNELSBAK} # Backup verwenden um konflikt mit VDR zu vermeiden

# Als letzter Eintarg kommt noch ein Neu-Marker. Damit kann man schön
#+kontrollieren, was seit dem Aufräumen wieder neu dazugekommen ist
echo ":==> Neu seit $(date "+%d.%m.%Y %R")" >> ${CHANNELSNEW}

if [ ! "$(pidof vdr)" ] ; then           # VDR läuft?
   cp -f ${CHANNELSNEW} ${CHANNELSCONF}  # Neue Liste aktivieren
else
   log "VDR läuft! Neue Kanalliste: ${CHANNELSNEW}"
fi

# Statistik
log "${marker} Marker (:) gefunden"
log "${removed} Kanäle wurden nach ${CHANNELSREMOVED} verschoben"
log "${marked} Kanäle wurden neu markiert (${OLDMARKER})"

exit 0
