Stream Recorder: Unterschied zwischen den Versionen

Aus TV-Browser Wiki
Wechseln zu: Navigation⧼comma-separator⧽Suche
TuxNix⧼word-separator⧽⧼parentheses⧽
⧼parentheses⧽
TuxNix⧼word-separator⧽⧼parentheses⧽
⧼parentheses⧽
Zeile 50: Zeile 50:
 
#!/bin/bash
 
#!/bin/bash
  
##### streamrecorder Version 1.4 - Jan. 2021
+
# Script from tuxnix - Version 1.6 - 2023-06-17
  
##### From tuxnix
 
# with no garanty at all
 
  
 
# FreeAsFreeBeerLicense:
 
# FreeAsFreeBeerLicense:
Zeile 59: Zeile 57:
 
# Do not sell a free beer
 
# Do not sell a free beer
 
# Have fun!
 
# Have fun!
 
 
##### Parameter für Tv-Browser: Aufnahme
 
#record {start_hour} {start_minute} {start_year} {start_month} {start_day} {end_hour} {end_minute} {end_year} {end_month} {end_day} "{channel_name}" "{title}" {production_year} {episode_number} "{episode}"
 
 
##### Parameter für Tv-Browser: Löschen
 
#delete {start_hour} {start_minute} {start_year} {start_month} {start_day} {end_hour} {end_minute} {end_year} {end_month} {end_day} "{channel_name}" "{title}" {production_year} {episode_number} "{episode}"
 
 
##### Benötigt die Pakete: at ffmpeg
 
 
##### Der at service muss aktiviert werden.
 
#Befehl: 'sytemctl enable --now atd.service'
 
  
  
 
##### Benutzer Konfiguration
 
##### Benutzer Konfiguration
 
+
recPath=~/Videos/
recPath=/Videos
+
storePath=~/Videos/Filme
  
 
##### Das Script
 
##### Das Script
  
 
declare -a Pakete=("at" "ffmpeg")
 
declare -a Pakete=("at" "ffmpeg")
 
 
for i in "${Pakete[@]}"; do
 
for i in "${Pakete[@]}"; do
 
   if ! [[ -f "/bin/$i" || -f "/sbin/$i" || -f "/usr/bin/$i" || -f "/usr/sbin/$i" ]] ; then
 
   if ! [[ -f "/bin/$i" || -f "/sbin/$i" || -f "/usr/bin/$i" || -f "/usr/sbin/$i" ]] ; then
Zeile 87: Zeile 72:
 
   fi
 
   fi
 
done
 
done
 +
  
 
args=("$@")
 
args=("$@")
 
operation=${args[0]}
 
operation=${args[0]}
sStunde=${args[1]}; if (( ${#sStunde} < 2 )); then sStunde="0"${args[1]}; fi
+
sStunde=${args[1]}; if [ ${#sStunde} -lt 2 ]; then sStunde="0"${args[1]}; fi
sMinute=${args[2]}; if (( ${#sMinute} < 2 )); then sMinute="0"$sMinute; fi
+
sMinute=${args[2]}; if [ ${#sMinute} -lt 2 ]; then sMinute="0"$sMinute; fi
 
sJahr=${args[3]}
 
sJahr=${args[3]}
sMonat=${args[4]}; if (( ${#sMonat} < 2 )); then sMonat="0"$sMonat; fi
+
sMonat=${args[4]}; if [ ${#sMonat} -lt 2 ]; then sMonat="0"$sMonat; fi
sTag=${args[5]}; if (( ${#sTag} < 2 )); then sTag="0"$sTag; fi
+
sTag=${args[5]}; if [ ${#sTag} -lt 2 ]; then sTag="0"$sTag; fi
eStunde=${args[6]}; if (( ${#eStunde} < 2 )); then eStunde="0"$eStunde; fi
+
eStunde=${args[6]}; if [ ${#eStunde} -lt 2 ]; then eStunde="0"$eStunde; fi
eMinute=${args[7]}; if (( ${#eMinute} < 2 )); then eMinute="0"$eMinute; fi
+
eMinute=${args[7]}; if [ ${#eMinute} -lt 2 ]; then eMinute="0"$eMinute; fi
 
eJahr=${args[8]}
 
eJahr=${args[8]}
eMonat=${args[9]}; if (( ${#args[9]} < 2 )); then eMonat="0"${args[9]}; fi
+
eMonat=${args[9]}; if [ ${#args[9]} -lt 2 ]; then eMonat="0"${args[9]}; fi
eTag=${args[10]}; if (( ${#args[10]} < 2 )); then eTag="0"${args[10]}; fi
+
eTag=${args[10]}; if [ ${#args[10]} -lt 2 ]; then eTag="0"${args[10]}; fi
Kanal=`echo ${args[11]} | sed -e 's/ /_/g' -e 's!"!!g'`
+
Kanal=${args[11]}
 
Titel=${args[12]}
 
Titel=${args[12]}
if (( ${#args[13]} > 3 )); then ProdJahr="-"${args[13]}; fi
+
if [ ${#args[13]} -ge 3 ]; then ProdJahr="-"${args[13]}; fi
if (( ${#args[14]} > 3 )); then EpisodenNr="-"${args[14]}; fi
+
if [ ${#args[14]} -ge 3 ]; then EpisodenNr="-"${args[14]}; fi
if (( ${#args[15]} > 3 )); then Episode="-"${args[15]}; fi
+
if [ ${#args[15]} -ge 3 ]; then Episode="-"${args[15]}; fi
  
Name="$Titel$ProdJahr$EpisodenNr$Episode"
+
Name="$Titel$ProdJahr$EpisodenNr${Episode}"
Name=`echo $Name | sed -e 's![ ]!_!g' -e 's![/}]!-!g' -e 's![.,:()"\x27]!!g' -e 's!&!und!g' #-e 's!ß!ss!g'  -e 's!ö!oe!g'`
+
Name=`echo $Name | sed -e 's![ ]!_!g' -e 's![/}]!-!g' -e 's![.,:()"\x27]!!g' -e 's!&!und!g'` #-e 's!ß!ss!g'  -e 's!ö!oe!g'
  
  
 
   if [ $Kanal == 'Das_Erste_(ARD)' ] ; then stream_url="https://mcdn.daserste.de/daserste/de/master.m3u8"
 
   if [ $Kanal == 'Das_Erste_(ARD)' ] ; then stream_url="https://mcdn.daserste.de/daserste/de/master.m3u8"
elif [ $Kanal == 'ARD-alpha' ] ; then stream_url="https://brlive-lh.akamaihd.net/i/bralpha_germany@119899/master.m3u8"
+
elif [ $Kanal == 'ARD-alpha' ] ; then stream_url="http://livestreams.br.de/i/bralpha_germany@119899/master.m3u8"
elif [ $Kanal == 'One' ] ; then stream_url="https://onelivestream-lh.akamaihd.net/i/one_livestream@568814/master.m3u8"
+
elif [ $Kanal == 'One' ] ; then stream_url="https://mcdn.one.ard.de/ardone/hls/master.m3u8"
elif [ $Kanal == 'tagesschau24' ] ; then stream_url="https://tagesschau-lh.akamaihd.net/i/tagesschau_1@119231/master.m3u8"
+
elif [ $Kanal == 'tagesschau24' ] ; then stream_url="https://tagesschau.akamaized.net/hls/live/2020115/tagesschau/tagesschau_1/master.m3u8"
elif [ $Kanal == 'arte' ] ; then stream_url="https://artelive-lh.akamaihd.net/i/artelive_de@393591/master.m3u8"
+
elif [ $Kanal == 'arte' ] ; then stream_url="https://artesimulcast.akamaized.net/hls/live/2030993/artelive_de/index.m3u8"
elif [ $Kanal == 'ARTE_(francais)' ] ; then stream_url="https://artelive-lh.akamaihd.net/i/artelive_fr@344805/master.m3u8"
+
elif [ $Kanal == 'BR_Sued' ] ; then stream_url="https://brcdn.vo.llnwd.net/br/fs/bfs_sued/hls/de/master.m3u8"
elif [ $Kanal == 'BR' ] ; then stream_url="http://livestreams.br.de/i/bfsnord_germany@119898/master.m3u8"
+
elif [ $Kanal == 'BR_Nord' ] ; then stream_url="https://mcdn.br.de/br/fs/bfs_nord/hls/de/master.m3u8"
elif [ $Kanal == 'BR_Sued' ] ; then stream_url="https://brlive-lh.akamaihd.net/i/bfssued_germany@119890/master.m3u8"
+
elif [ $Kanal == 'KiKA' ] ; then stream_url="https://kikageohls.akamaized.net/hls/live/2022693/livetvkika_de/master.m3u8"
elif [ $Kanal == 'BR_Nord' ] ; then stream_url="https://brlive-lh.akamaihd.net/i/bfsnord_germany@119898/master.m3u8"
+
elif [ $Kanal == 'HR' ] ; then stream_url="https://hrhls.akamaized.net/hls/live/2024525/hrhls/master.m3u8"
elif [ $Kanal == 'KiKA' ] ; then stream_url="https://kikageohls-i.akamaihd.net/hls/live/1006268/livetvkika_de/master.m3u8"
+
elif [ $Kanal == 'MDR_Thueringen' ] ; then stream_url="https://mdrtvthhls.akamaized.net/hls/live/2016880/mdrtvth/master.m3u8"
elif [ $Kanal == 'HR' ] ; then stream_url="https://live1_hr-lh.akamaihd.net/i/hr_fernsehen@75910/master.m3u8"
+
elif [ $Kanal == 'MDR_Sachsen' ] ; then stream_url="https://mdrtvsnhls.akamaized.net/hls/live/2016928/mdrtvsn/master.m3u8"
elif [ $Kanal == 'MDR_Thueringen' ] ; then stream_url="https://mdrthuhls-lh.akamaihd.net/i/livetvmdrthueringen_de@514027/master.m3u8"
+
elif [ $Kanal == 'MDR_Sachsen-Anhalt' ] ; then stream_url="https://mdrtvsahls.akamaized.net/hls/live/2016879/mdrtvsa/master.m3u8"
elif [ $Kanal == 'MDR_Sachsen' ] ; then stream_url="https://mdrsnhls-lh.akamaihd.net/i/livetvmdrsachsen_de@513998/master.m3u8"
+
elif [ $Kanal == 'NDR_Niedersachsen' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_nds/master.m3u8"
elif [ $Kanal == 'MDR_Sachsen_Anhalt' ] ; then stream_url="https://mdrsahls-lh.akamaihd.net/i/livetvmdrsachsenanhalt_de@513999/master.m3u8"
+
elif [ $Kanal == 'NDR_Schleswig-Holstein' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_sh/master.m3u8"
elif [ $Kanal == 'NDR_Niedersachsen' ] ; then stream_url="https://ndrfs-lh.akamaihd.net/i/ndrfs_nds@430233/master.m3u8"
+
elif [ $Kanal == 'NDR_Hamburg' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_hh/master.m3u8"
elif [ $Kanal == 'NDR_Schleswig-Holstein' ] ; then stream_url="https://ndrfs-lh.akamaihd.net/i/ndrfs_sh@430234/master.m3u8"
+
elif [ $Kanal == 'NDR_Mecklenburg-Vorpommern' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_mv/master.m3u8"
elif [ $Kanal == 'PHOENIX' ] ; then stream_url="https://zdf-hls-19.akamaized.net/hls/live/2016502/de/high/master.m3u8"
+
elif [ $Kanal == 'PHOENIX' ] ; then stream_url="https://zdf-hls-19.akamaized.net/hls/live/2016502/de/veryhigh/master.m3u8"
elif [ $Kanal == 'RBB_Berlin' ] ; then stream_url="https://rbblive-lh.akamaihd.net/i/rbb_berlin@144674/master.m3u8"
+
elif [ $Kanal == 'RBB_Berlin' ] ; then stream_url="https://rbb-hls-berlin.akamaized.net/hls/live/2017824/rbb_berlin/master.m3u8"
elif [ $Kanal == 'RBB_Brandenburg' ] ; then stream_url="https://rbblive-lh.akamaihd.net/i/rbb_brandenburg@349369/master.m3u8"
+
elif [ $Kanal == 'RBB_Brandenburg' ] ; then stream_url="https://rbb-hls-brandenburg.akamaized.net/hls/live/2017825/rbb_brandenburg/master.m3u8"
elif [ $Kanal == '3sat' ] ; then stream_url="https://zdf-hls-18.akamaized.net/hls/live/2016501/dach/high/master.m3u8"
+
elif [ $Kanal == '3sat' ] ; then stream_url="https://zdf-hls-18.akamaized.net/hls/live/2016501/dach/veryhigh/master.m3u8"
elif [ $Kanal == 'SWR_BW' ] ; then stream_url="https://swrbwhls-i.akamaihd.net/hls/live/667638/swrbwd/master.m3u8"  
+
elif [ $Kanal == 'SWR_BW' ] ; then stream_url="https://swrbwd-hls.akamaized.net/hls/live/2018672/swrbwd/master.m3u8"
elif [ $Kanal == 'SWR_SR' ] ; then stream_url="https://live2_sr-lh.akamaihd.net/i/sr_universal02@107595/master.m3u8" 
+
elif [ $Kanal == 'SWR_RP' ] ; then stream_url="https://swrrpd-hls.akamaized.net/hls/live/2018676/swrrpd/master.m3u8"
elif [ $Kanal == 'SWR_RP' ] ; then stream_url="https://swrrphls-i.akamaihd.net/hls/live/667639/swrrpd/master.m3u8"
+
elif [ $Kanal == 'WDR' ] ; then stream_url="https://mcdn.wdr.de/wdr/wdrfs/de/master.m3u8"
elif [ $Kanal == 'WDR' ] ; then stream_url="https://wdrfsgeo-lh.akamaihd.net/i/wdrfs_geogeblockt@530016/master.m3u8"      
+
elif [ $Kanal == 'ZDF' ] ; then stream_url="http://zdf-hls-15.akamaized.net/hls/live/2016498/de/veryhigh/master.m3u8"
elif [ $Kanal == 'ZDF' ] ; then stream_url="https://zdf-hls-15.akamaized.net/hls/live/2016498/de/high/master.m3u8"
+
elif [ $Kanal == 'ZDFinfo' ] ; then stream_url="https://zdf-hls-17.akamaized.net/hls/live/2016500/de/veryhigh/master.m3u8"
elif [ $Kanal == 'ZDFinfo' ] ; then stream_url="https://zdf-hls-17.akamaized.net/hls/live/2016500/de/high/master.m3u8"
+
elif [ $Kanal == 'ZDFneo' ] ; then stream_url="https://zdf-hls-16.akamaized.net/hls/live/2016499/de/veryhigh/master.m3u8"
elif [ $Kanal == 'ZDFneo' ] ; then stream_url="https://zdf-hls-16.akamaized.net/hls/live/2016499/de/high/master.m3u8"
 
  
 
#Geoblocking (In der BRD nur mittels VPN zu streamen)
 
#Geoblocking (In der BRD nur mittels VPN zu streamen)
Zeile 161: Zeile 146:
 
endZeit=$eStunde:$eMinute' '$eJahr-$eMonat-$eTag
 
endZeit=$eStunde:$eMinute' '$eJahr-$eMonat-$eTag
  
if [ $operation == 'record' ] && (( $sysTime >= $endTime )) ; then
+
if [ $operation == 'record' ] && [ $sysTime -ge $endTime ] ; then
     echo ""
+
    echo "Keine Aufnahme!"
     echo "Die Sendung ist abgelaufen und kann nicht mehr aufgenommen werden."
+
    echo "Die Sendung liegt in der Vergangenheit."
 +
    exit 1
 +
elif [ $operation == 'record' ] && [[ -f $storePath$Name.mp4 ]]; then
 +
     echo "Keine Aufnahme!"
 +
     echo "Die Sendung wurde bereits in der Vergangenheit aufgezeichnet:"
 +
    echo $storePath$Name".mp4"
 
     exit 1
 
     exit 1
 
+
elif [ $operation == 'record' ] && [ $sysTime -ge $startTime ] ; then
elif [ $operation == 'record' ] && (( $sysTime > $startTime )) ; then
+
    let secsPart=$endTime-$sysTime
 
+
    hPart=$((secsPart/3600)); if [ ${#hPart} -lt 2 ]; then hPart="0"$hPart; fi
     echo "Von `date --date='now' +%R` (jetzt) bis $eStunde:$eMinute Uhr $Name"
+
    mPart=$((secsPart%3600/60)); if [ ${#mPart} -lt 2 ]; then mPart="0"$mPart; fi
    echo ""
+
    durationPart="$hPart:$mPart:00"
     echo "Die Aufnahme wurde gestartet und wird nach"
+
     echo "`date --date='now' +%R` (jetzt) bis $eStunde:$eMinute Uhr, Dauer: $durationPart"
     echo $recPath$Name"-part.mp4 gespeichert."
+
     echo "Aufnahme speichern:"
     echo "ffmpeg -i $stream_url -vcodec copy -acodec copy $recPath$Name-part.mp4" | at $startNow > /dev/null 2>&1
+
     echo $recPath$Name"-part.mp4"
    echo "fuser -k -TERM $recPath$Name-part.mp4" | at $endZeit > /dev/null 2>&1
+
     echo "ffmpeg -i $stream_url -c copy -t $durationPart $recPath$Name-part.mp4" | at $startNow > /dev/null 2>&1
 
+
elif [ $operation == 'record' ] && [ $sysTime -le $startTime ] ; then
elif [ $operation == 'record' ] && (( $sysTime <= $startTime )) ; then
+
    atJob=(`atq | awk '{print $1}'`)
 
+
    let secs=$endTime-$startTime
     echo "$eTag.$eMonat.$eJahr: Von $sStunde:$sMinute bis $eStunde:$eMinute Uhr $Name"
+
    H=$((secs/3600)); if [ ${#H} -lt 2 ]; then H="0"$H; fi
     echo ""
+
    M=$((secs%3600/60)); if [ ${#M} -lt 2 ]; then M="0"$M; fi
    echo "Die Aufnahme wird veranlasst und nach"
+
    duration="$H:$M:00"
     echo $recPath$Name".mp4 gespeichert."
+
     echo "Tag: $eTag.$eMonat.$eJahr - $sStunde:$sMinute bis $eStunde:$eMinute Uhr, Dauer: $duration"
     echo "ffmpeg -i $stream_url -vcodec copy -acodec copy $recPath$Name.mp4" | at $startZeit > /dev/null 2>&1
+
     echo "Aufnahme speichern:"
     echo "fuser -k -TERM $recPath$Name.mp4" | at $endZeit > /dev/null 2>&1
+
     echo $recPath$Name".mp4"
+
     echo "ffmpeg -i $stream_url -c copy -t $duration $recPath$Name.mp4" | at $startZeit > /dev/null 2>&1
elif [ $operation == 'delete' ] ; then
+
elif [ $operation == 'delete' ] && [ $sysTime -ge $startTime ] ; then
 
+
    echo "fuser -k -TERM $recPath$Name.mp4" | at $stopNow > /dev/null 2>&1
 +
     echo "fuser -k -TERM $recPath$Name-part.mp4" | at $stopNow > /dev/null 2>&1
 +
    echo "Die laufende Aufnahme von '$Name' wird beendet!"
 +
elif [ $operation == 'delete' ] && [ $sysTime -lt $startTime ] ; then
 
     Monat=([1]=Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
 
     Monat=([1]=Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
+
     sTag=${args[5]}
    if (( $sysTime >= $startTime )) ; then
+
    if [ ${#sTag} -lt 2 ] ; then sTag=" "$sTag ; fi
 
+
    while [[ `atq | grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"` ]]; do
        echo "fuser -k -TERM $recPath$Name.mp4" | at $stopNow > /dev/null 2>&1
+
        Job=( `atq | grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"`)
        echo "fuser -k -TERM $recPath$Name-part.mp4" | at $stopNow > /dev/null 2>&1
+
        if [[ `at -c $Job | grep -e $Name` ]]; then atrm $Job; echo "Der Job $Job wurde gelöscht!"; fi
        echo "Die laufende Aufnahme von '$Name' wird beendet!"
+
     done
 
 
     else
 
 
        sTag=${args[5]}
 
        if (( ${#sTag} < 2 )) ; then sTag=" "$sTag ; fi
 
 
 
        while [[ `atq | grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"` ]]; do
 
            Job=( `atq | grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"`)
 
            if [[ `at -c $Job | grep -e $Name` ]] ; then
 
                atrm $Job
 
                echo "Der at Start-Job $Job wurde gelöscht!"
 
            fi
 
        done
 
    fi
 
      
 
 
        eTag=${args[10]}
 
        if (( ${#eTag} < 2 )) ; then eTag=" "$eTag ; fi
 
       
 
        while [[ `atq | grep -e "${Monat[${args[9]}]} $eTag $eStunde:$eMinute:00 $eJahr"` ]]; do
 
            Job=( `atq | grep -e "${Monat[${args[9]}]} $eTag $eStunde:$eMinute:00 $eJahr"`)
 
            if [[ `at -c $Job | grep -e $Name` ]] ; then
 
                atrm $Job
 
                echo "Der at Stop-Job $Job wurde gelöscht!"
 
            fi
 
        done
 
       
 
 
else
 
else
 
 
     echo "Abbruch: Der Operator $operation ist nicht korrekt. Bitte überprüfe die Parameter im TV-Browser Aufnahme Plugin"
 
     echo "Abbruch: Der Operator $operation ist nicht korrekt. Bitte überprüfe die Parameter im TV-Browser Aufnahme Plugin"
    exit 2
 
 
fi
 
fi
 
</nowiki>
 
 
Anregungen und Verbesserungen zum Skript können auf Gitlab eingereicht werden: [https://gitlab.com/tuxnix/streamrecorder streamrecorder]
 

Version vom 19. Juni 2023, 04:48 Uhr

Stream Recorder ist ein Shell-Skript zur zeitgesteuerten Aufnahme von TV Livestreams aus dem TV-Browser heraus.

Voraussetzungen

  • Internetanschluss
  • Linux Pc
  • at (Paket)
  • ffmpeg (Paket)
  • TV-Browser - Aufnahmesteuerung Plugin

Installation

Das Skript

Benötigt wird die Installation der Pakete 'at' und 'ffmpeg'.

Der at Dienst wird von systemd gesteuert. Zur Aktivierung gibt man auf der Konsole (sudo systemctl enable --now atd.service) ein.

Das Skript wird kopiert und mit dem Namen streamrecoder in den Ordner /usr/local/bin/ abgespeichert. Danach wird es mit chmod a+rx /usr/local/bin/streamrecorder ausführbar gemacht.

Konfiguration des TV-Browsers

Das Plugin Aufnahmesteuerung muss geladen werden.

Im TV-Browser Menu Extras -> Aufnahmesteuerung -> Geräte -> Gerät-hinzufügen und den Standardtreiber auswählen. Beim Eintrag "Gerät" kann ein beliebiger Name eingetragen werden.

Als "Applikation" wird das Skript (streamrecoder) mit seinem Pfad angegeben.

Parameter für die Aufnahme:
record {start_hour} {start_minute} {start_year} {start_month} {start_day} {end_hour} {end_minute} {end_year} {end_month} {end_day} "{channel_name}" "{title}" {production_year} {episode_number} "{episode}"

Parameter für das Löschen:
delete {start_hour} {start_minute} {start_year} {start_month} {start_day} {end_hour} {end_minute} {end_year} {end_month} {end_day} "{channel_name}" "{title}" {production_year} {episode_number} "{episode}"

Bei den Einstellungen können mehere Aufnahme gleichzeitig erlaubt werden.
Auch wird die Aufnahme schon laufender Sendungen unterstützt.

Die Sender URLs der öffentlich rechtlichen Sender sind im Skript gelistet (Stand Januar 2021). Man kann beliebig viele Sender hinzufügen. Die Namen der Sender sollten im TV-Browser und im Skript miteinander übereinstimmen. Leerstellen im Sendernamen sollten im Skript mit Unterstrich eingetragen werden. Der Speicherort der Aufnahme ist auf ~/Video vor eingestellt und kann im Skript in der Benutzerkonfiguration angepasst werden. Als Quelle für weitere Seder-URLs eignet sich die Projektseite Free-IPTV

Benutzung

Die Benutzung ist im Grunde selbsterklärend. Mit der rechten Maustaste wählt man eine Sendung aus. Mit der linken Maustaste wird auf Aufnahme gedrückt. Zum Rückgängigmachen der Aufnahmejobs geht man entsprechend vor. Ein Dialogfenster von TV-Browser öffnet sich und gibt jeweils Auskunft über den Programmablauf.

Hintergrund

Zur Zeitsteuerung habe ich at ausgewählt. Cronie und systemd.timers sind besser für wiederkehrende Ereignisse geeignet. Wer wissen möchte wie die at-Jobs gespeichert werden, kann auf der Konsole die Befehle atq, at -c <job> und atrm <job> ausprobieren. Für das eigentliche streaming ist ffmpeg verantwortlich.

Viel Spaß damit tuxnix

Das Skript

<nowiki>
  1. !/bin/bash
  1. Script from tuxnix - Version 1.6 - 2023-06-17


  1. FreeAsFreeBeerLicense:
  2. Do not buy a free beer
  3. Do not sell a free beer
  4. Have fun!


          1. Benutzer Konfiguration

recPath=~/Videos/ storePath=~/Videos/Filme

          1. Das Script

declare -a Pakete=("at" "ffmpeg") for i in "${Pakete[@]}"; do

 if ! | -f "/sbin/$i" || -f "/usr/bin/$i" || -f "/usr/sbin/$i"  ; then
   echo "Das Paket $i muss noch installiert werden"
   exit 1
 fi

done


args=("$@") operation=${args[0]} sStunde=${args[1]}; if [ ${#sStunde} -lt 2 ]; then sStunde="0"${args[1]}; fi sMinute=${args[2]}; if [ ${#sMinute} -lt 2 ]; then sMinute="0"$sMinute; fi sJahr=${args[3]} sMonat=${args[4]}; if [ ${#sMonat} -lt 2 ]; then sMonat="0"$sMonat; fi sTag=${args[5]}; if [ ${#sTag} -lt 2 ]; then sTag="0"$sTag; fi eStunde=${args[6]}; if [ ${#eStunde} -lt 2 ]; then eStunde="0"$eStunde; fi eMinute=${args[7]}; if [ ${#eMinute} -lt 2 ]; then eMinute="0"$eMinute; fi eJahr=${args[8]} eMonat=${args[9]}; if [ ${#args[9]} -lt 2 ]; then eMonat="0"${args[9]}; fi eTag=${args[10]}; if [ ${#args[10]} -lt 2 ]; then eTag="0"${args[10]}; fi Kanal=${args[11]} Titel=${args[12]} if [ ${#args[13]} -ge 3 ]; then ProdJahr="-"${args[13]}; fi if [ ${#args[14]} -ge 3 ]; then EpisodenNr="-"${args[14]}; fi if [ ${#args[15]} -ge 3 ]; then Episode="-"${args[15]}; fi

Name="$Titel$ProdJahr$EpisodenNr${Episode}" Name=`echo $Name | sed -e 's![ ]!_!g' -e 's![/}]!-!g' -e 's![.,:()"\x27]!!g' -e 's!&!und!g'` #-e 's!ß!ss!g' -e 's!ö!oe!g'


 if [ $Kanal == 'Das_Erste_(ARD)' ] ; then stream_url="https://mcdn.daserste.de/daserste/de/master.m3u8"

elif [ $Kanal == 'ARD-alpha' ] ; then stream_url="http://livestreams.br.de/i/bralpha_germany@119899/master.m3u8" elif [ $Kanal == 'One' ] ; then stream_url="https://mcdn.one.ard.de/ardone/hls/master.m3u8" elif [ $Kanal == 'tagesschau24' ] ; then stream_url="https://tagesschau.akamaized.net/hls/live/2020115/tagesschau/tagesschau_1/master.m3u8" elif [ $Kanal == 'arte' ] ; then stream_url="https://artesimulcast.akamaized.net/hls/live/2030993/artelive_de/index.m3u8" elif [ $Kanal == 'BR_Sued' ] ; then stream_url="https://brcdn.vo.llnwd.net/br/fs/bfs_sued/hls/de/master.m3u8" elif [ $Kanal == 'BR_Nord' ] ; then stream_url="https://mcdn.br.de/br/fs/bfs_nord/hls/de/master.m3u8" elif [ $Kanal == 'KiKA' ] ; then stream_url="https://kikageohls.akamaized.net/hls/live/2022693/livetvkika_de/master.m3u8" elif [ $Kanal == 'HR' ] ; then stream_url="https://hrhls.akamaized.net/hls/live/2024525/hrhls/master.m3u8" elif [ $Kanal == 'MDR_Thueringen' ] ; then stream_url="https://mdrtvthhls.akamaized.net/hls/live/2016880/mdrtvth/master.m3u8" elif [ $Kanal == 'MDR_Sachsen' ] ; then stream_url="https://mdrtvsnhls.akamaized.net/hls/live/2016928/mdrtvsn/master.m3u8" elif [ $Kanal == 'MDR_Sachsen-Anhalt' ] ; then stream_url="https://mdrtvsahls.akamaized.net/hls/live/2016879/mdrtvsa/master.m3u8" elif [ $Kanal == 'NDR_Niedersachsen' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_nds/master.m3u8" elif [ $Kanal == 'NDR_Schleswig-Holstein' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_sh/master.m3u8" elif [ $Kanal == 'NDR_Hamburg' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_hh/master.m3u8" elif [ $Kanal == 'NDR_Mecklenburg-Vorpommern' ] ; then stream_url="https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_mv/master.m3u8" elif [ $Kanal == 'PHOENIX' ] ; then stream_url="https://zdf-hls-19.akamaized.net/hls/live/2016502/de/veryhigh/master.m3u8" elif [ $Kanal == 'RBB_Berlin' ] ; then stream_url="https://rbb-hls-berlin.akamaized.net/hls/live/2017824/rbb_berlin/master.m3u8" elif [ $Kanal == 'RBB_Brandenburg' ] ; then stream_url="https://rbb-hls-brandenburg.akamaized.net/hls/live/2017825/rbb_brandenburg/master.m3u8" elif [ $Kanal == '3sat' ] ; then stream_url="https://zdf-hls-18.akamaized.net/hls/live/2016501/dach/veryhigh/master.m3u8" elif [ $Kanal == 'SWR_BW' ] ; then stream_url="https://swrbwd-hls.akamaized.net/hls/live/2018672/swrbwd/master.m3u8" elif [ $Kanal == 'SWR_RP' ] ; then stream_url="https://swrrpd-hls.akamaized.net/hls/live/2018676/swrrpd/master.m3u8" elif [ $Kanal == 'WDR' ] ; then stream_url="https://mcdn.wdr.de/wdr/wdrfs/de/master.m3u8" elif [ $Kanal == 'ZDF' ] ; then stream_url="http://zdf-hls-15.akamaized.net/hls/live/2016498/de/veryhigh/master.m3u8" elif [ $Kanal == 'ZDFinfo' ] ; then stream_url="https://zdf-hls-17.akamaized.net/hls/live/2016500/de/veryhigh/master.m3u8" elif [ $Kanal == 'ZDFneo' ] ; then stream_url="https://zdf-hls-16.akamaized.net/hls/live/2016499/de/veryhigh/master.m3u8"

  1. Geoblocking (In der BRD nur mittels VPN zu streamen)

elif [ $Kanal == 'ORF_eins' ] ; then stream_url="https://orf1.mdn.ors.at/out/u/orf1/qxb/manifest.m3u8" elif [ $Kanal == 'ORF_2' ] ; then stream_url="https://orf2e.mdn.ors.at/out/u/orf2e/qxb/manifest.m3u8" elif [ $Kanal == 'ORF_III' ] ; then stream_url="https://orf3.mdn.ors.at/out/u/orf3/qxb/manifest.m3u8" elif [ $Kanal == 'ORF_SPORT_PLUS' ] ; then stream_url="https://orfs.mdn.ors.at/out/u/orfs/qxb/manifest.m3u8"

else

   echo "Abbruch: Der Sender '$Kanal' ist in streamrecorder nicht gelistet."
   echo ""
   echo "Die Namen der Sender im TV-Browser müssen mit denen im Skript übereinstimmen."
   echo "Bitte Groß und Kleinschreibung beachten und Leerzeichen im Sendernamen im TV-Browser vermeiden oder im Skript durch einen Unterstrich ersetzen."
   echo "Umlaute werden nicht unterstützt."
   exit 1

fi

sysTime=`date --date='now' +%s` startTime=`date --date="$sJahr-$sMonat-$sTag $sStunde:$sMinute" +%s` endTime=`date --date="$eJahr-$eMonat-$eTag $eStunde:$eMinute" +%s` startNow=`date --date='now' +%R' '%F` stopNow=`date --date="1 minute" +%R' '%F` startZeit=$sStunde:$sMinute' '$sJahr-$sMonat-$sTag endZeit=$eStunde:$eMinute' '$eJahr-$eMonat-$eTag

if [ $operation == 'record' ] && [ $sysTime -ge $endTime ] ; then

   echo "Keine Aufnahme!"
   echo "Die Sendung liegt in der Vergangenheit."
   exit 1

elif [ $operation == 'record' ] && -f $storePath$Name.mp4 ; then

   echo "Keine Aufnahme!"
   echo "Die Sendung wurde bereits in der Vergangenheit aufgezeichnet:"
   echo $storePath$Name".mp4"
   exit 1

elif [ $operation == 'record' ] && [ $sysTime -ge $startTime ] ; then

   let secsPart=$endTime-$sysTime
   hPart=$((secsPart/3600)); if [ ${#hPart} -lt 2 ]; then hPart="0"$hPart; fi
   mPart=$((secsPart%3600/60)); if [ ${#mPart} -lt 2 ]; then mPart="0"$mPart; fi
   durationPart="$hPart:$mPart:00"
   echo "`date --date='now' +%R` (jetzt) bis $eStunde:$eMinute Uhr, Dauer: $durationPart"
   echo "Aufnahme speichern:"
   echo $recPath$Name"-part.mp4"
   echo "ffmpeg -i $stream_url -c copy -t $durationPart $recPath$Name-part.mp4" | at $startNow > /dev/null 2>&1

elif [ $operation == 'record' ] && [ $sysTime -le $startTime ] ; then

   atJob=(`atq | awk '{print $1}'`)
   let secs=$endTime-$startTime
   H=$((secs/3600)); if [ ${#H} -lt 2 ]; then H="0"$H; fi
   M=$((secs%3600/60)); if [ ${#M} -lt 2 ]; then M="0"$M; fi
   duration="$H:$M:00"
   echo "Tag: $eTag.$eMonat.$eJahr - $sStunde:$sMinute bis $eStunde:$eMinute Uhr, Dauer: $duration"
   echo "Aufnahme speichern:"
   echo $recPath$Name".mp4"
   echo "ffmpeg -i $stream_url -c copy -t $duration $recPath$Name.mp4" | at $startZeit > /dev/null 2>&1

elif [ $operation == 'delete' ] && [ $sysTime -ge $startTime ] ; then

   echo "fuser -k -TERM $recPath$Name.mp4" | at $stopNow > /dev/null 2>&1
   echo "fuser -k -TERM $recPath$Name-part.mp4" | at $stopNow > /dev/null 2>&1
   echo "Die laufende Aufnahme von '$Name' wird beendet!"

elif [ $operation == 'delete' ] && [ $sysTime -lt $startTime ] ; then

   Monat=([1]=Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
   sTag=${args[5]}
   if [ ${#sTag} -lt 2 ] ; then sTag=" "$sTag ; fi
   while  grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"` ; do
       Job=( `atq | grep -e "${Monat[${args[4]}]} $sTag $sStunde:$sMinute:00 $sJahr"`)
       if  grep -e $Name` ; then atrm $Job; echo "Der Job $Job wurde gelöscht!"; fi
   done

else

   echo "Abbruch: Der Operator $operation ist nicht korrekt. Bitte überprüfe die Parameter im TV-Browser Aufnahme Plugin"

fi