Dvb wiki script/Script: Unterschied zwischen den Versionen
Escho (Diskussion | Beiträge) (kdialog: Abbrechen klappt nun) |
Escho (Diskussion | Beiträge) (export VIDEO_FORMAT=PAL) |
||
(11 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
+ | {{Dvbscript navigationsbox}} | ||
+ | '''Bitte die [[Dvb wiki script/Installation|Installationsanleitung]] beachten!'''<br> | ||
<pre> | <pre> | ||
#!/bin/bash | #!/bin/bash | ||
− | + | #Name: dvb_wiki_script | |
− | + | #Version: 0.9.0 | |
− | #Name: | + | #Erstellungsdatum: 9.1.2011 |
− | #Version: 0. | ||
− | #Erstellungsdatum: | ||
#Autor: escho (www.linux-club.de) | #Autor: escho (www.linux-club.de) | ||
#Benutzung auf eigene Gefahr | #Benutzung auf eigene Gefahr | ||
− | |||
#Dieses Shell Script automatisiert weitgehend die Vorgänge, die nötig sind, um aus einer DVB-Aufnahme | #Dieses Shell Script automatisiert weitgehend die Vorgänge, die nötig sind, um aus einer DVB-Aufnahme | ||
− | #eine abspielbare Video-DVD zu erzeugen | + | #eine abspielbare Video-DVD zu erzeugen. Es ist nur zusammen mit dem Installationsscript und dem GUI-Script lauffähig. |
− | # | + | #Neu in dieser Version: siehe Diskussion |
− | #------------- | + | # ---------------------------------Vorbereitungen------------------------------------- |
− | + | # Voreinstellungen | |
− | + | hauptverzeichnis=$HOME/dvb_wiki_script | |
+ | ini_verz=$HOME/.dvb_wiki_script | ||
− | + | aufnahme=$HOME/DVB/Aufnahme | |
+ | druckschablonen=$HOME/DVB/Druckschablonen | ||
+ | videoclips=$HOME/DVB/Videoclips | ||
− | + | speed=8 | |
+ | dvdgroesse=4600000000 | ||
− | + | export VIDEO_FORMAT=PAL | |
− | # | + | # Verzeichnisstruktur erstellen |
− | + | mkdir $hauptverzeichnis 2>/dev/null | |
+ | mkdir $ini_verz 2>/dev/null | ||
− | + | mkdir $hauptverzeichnis/dvdstruktur 2>/dev/null | |
+ | mkdir $hauptverzeichnis/sicherung 2>/dev/null | ||
+ | mkdir $hauptverzeichnis/tmp1 2>/dev/null | ||
+ | mkdir $hauptverzeichnis/tmp2 2>/dev/null | ||
− | + | # Hilfsprogramme festlegen | |
− | + | hilfsprogramm=( mplex dvdauthor ProjectX.jar normalize ffmpeg growisofs xine requant_lxdvdrip ) | |
− | + | for var in ${hilfsprogramm[*]} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
do | do | ||
− | + | touch $ini_verz/$var | |
− | if [ ! -e $ | + | hilfsvar=`cat $ini_verz/$var` |
+ | if [ ! -e "$hilfsvar/$var" ] | ||
then | then | ||
− | echo "$ | + | echo "Programmsuche: $var" |
− | gefundene_pfade=`find $ | + | gefundene_pfade=`find /bin $HOME /opt /usr ! -path "$HOME/.*" -type f -name $var ! -printf "%h " 2>/dev/null` |
− | + | pfadzahl=`echo "$gefundene_pfade" | wc -w` | |
+ | case "$pfadzahl" in | ||
− | + | 0) kdialog --error "Das Programm wurde nicht gefunden. Bitte zuerst installieren." | |
− | 0) kdialog -- | ||
exit ;; | exit ;; | ||
− | 1) echo "$ | + | |
− | echo $gefundene_pfade > $ | + | 1) echo "$var gefunden" |
− | *) kdialog --combobox " | + | echo $gefundene_pfade > $ini_verz/$var ;; |
− | echo "$ | + | |
+ | *) auswahl=`kdialog --caption "$var" --combobox "Bitte Pfad auswählen" $gefundene_pfade` | ||
+ | if [ $? = 0 ] | ||
+ | then | ||
+ | echo "$var gefunden" | ||
+ | echo $auswahl > $ini_verz/$var | ||
+ | else | ||
+ | kdialog --error "Abbruch durch den Benutzer! Installation wird abgebrochen!" | ||
+ | exit | ||
+ | fi ;; | ||
esac | esac | ||
fi | fi | ||
done | done | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | # | + | # Hilfsprogramme laden |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | mplex=`cat $ini_verz/mplex`/mplex | |
+ | dvdauthor=`cat $ini_verz/dvdauthor`/dvdauthor | ||
+ | pjx=`cat $ini_verz/ProjectX.jar`/ProjectX.jar | ||
+ | normalize=`cat $ini_verz/normalize`/normalize | ||
+ | ffmpeg=`cat $ini_verz/ffmpeg`/ffmpeg | ||
+ | growisofs=`cat $ini_verz/growisofs`/growisofs | ||
+ | xine=`cat $ini_verz/xine`/xine | ||
+ | requant=`cat $ini_verz/requant_lxdvdrip`/requant_lxdvdrip | ||
− | # | + | # X.ini erzeugen |
+ | echo "X.ini für ProjectX erzeugen" | ||
echo \ | echo \ | ||
"# Application | "# Application | ||
Application.Agreement=1 | Application.Agreement=1 | ||
Application.Language=de | Application.Language=de | ||
+ | Application.ActiveDirectory=$aufnahme | ||
+ | |||
+ | # CollectionPanel | ||
+ | CollectionPanel.Preview.SliderWidth=0 | ||
# WindowPosition | # WindowPosition | ||
− | + | WindowPosition.Main.Width=9999 | |
− | WindowPosition.Main.Width= | ||
− | |||
WindowPosition.Main.Y=0 | WindowPosition.Main.Y=0 | ||
# OptionPanel | # OptionPanel | ||
OptionPanel.NormalLog=0 | OptionPanel.NormalLog=0 | ||
− | OptionPanel.closeOnEnd=1" > $ | + | OptionPanel.closeOnEnd=1" \ |
+ | > $hauptverzeichnis/X.ini | ||
+ | |||
+ | # Playlist für mplayer | ||
− | + | find $videoclips/* > $hauptverzeichnis/playlist | |
− | + | # Löschen | |
− | |||
− | |||
− | |||
− | + | echo "Löschen tmp, kann etwas dauern ..." | |
− | + | rm -r -- $hauptverzeichnis/tmp1/* 2>/dev/null | |
− | + | rm -r -- $hauptverzeichnis/tmp2/* 2>/dev/null | |
− | + | rm -r -- $hauptverzeichnis/dvdstruktur/* 2>/dev/null | |
− | |||
− | # | + | # ----------------------------------Funktionen------------------------------------- |
− | |||
− | |||
− | # | + | # °°°° Abbruch °°°° |
− | |||
− | + | benutzerabbruch () | |
+ | { | ||
+ | echo "Abbruch durch den Benutzer" | ||
+ | programmende | ||
+ | } | ||
− | + | funktionsabbruch () | |
+ | { | ||
+ | echo "$1" | ||
+ | programmende | ||
+ | } | ||
− | + | programmende () | |
− | |||
{ | { | ||
− | echo " | + | echo "Ende" |
− | + | kdialog --msgbox "Programmende" | |
− | + | exit | |
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | # | + | # °°° Aufgabenmenues °°° |
− | + | ||
+ | hauptmenue () | ||
{ | { | ||
− | if [ ! | + | auswahl_hauptmenue=`kdialog --caption "Hauptmenue" --geometry 200x250+500+400 --radiolist "Bitte einen Aufgabenbereich wählen" \ |
+ | 1 "VIDEO-DVD" on \ | ||
+ | 2 "TS-Stream" off \ | ||
+ | 3 "Videoclips" off \ | ||
+ | 7 "Abspielen" off \ | ||
+ | 8 "DVD bedrucken" off` | ||
+ | if [ $? != 0 ] | ||
then | then | ||
− | + | benutzerabbruch | |
− | |||
− | |||
fi | fi | ||
} | } | ||
− | + | untermenue_video_dvd () | |
+ | { | ||
+ | brenn_pfad=${dvdstruktur_pfad} | ||
+ | |||
+ | was_tun=`kdialog --caption "Video_DVD" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ | ||
+ | 11 "VIDEO-DVD........Fernsehaufnahme schneiden --> als Video-DVD brennen" on \ | ||
+ | 12 "VIDEO-DVD........Fernsehaufnahme schneiden --> DVD-Struktur in Datei sichern" off \ | ||
+ | 13 "VIDEO-DVD........Sicherung brennen" off` | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | } | ||
− | + | untermenue_ts () | |
− | |||
{ | { | ||
− | was_tun=`kdialog --caption " | + | was_tun=`kdialog --caption "Daten-DVD" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ |
− | + | 21 "TS-Stream..........Fernsehaufnahme schneiden --> TS als Daten-DVD brennen" on \ | |
− | + | 22 "TS-Stream..........Fernsehaufnahme schneiden --> TS sichern" off \ | |
− | + | 23 "TS-Stream..........Sicherung als Daten-DVD brennen" off` | |
− | + | if [ $? != 0 ] | |
− | |||
− | |||
− | |||
− | |||
− | if [ $? = 0 ] | ||
then | then | ||
− | + | benutzerabbruch | |
− | |||
− | |||
− | |||
fi | fi | ||
} | } | ||
− | + | untermenue_videoclip () | |
− | + | { | |
+ | was_tun=`kdialog --caption "Videoclips" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ | ||
+ | 31 "Videoclip.............Schneiden und speichern (Ton: MP2 normalisiert + AC3)" on \ | ||
+ | 32 "Videoclip............ Schneiden und speichern (Ton: AC3)" off \ | ||
+ | 33 "Videoclip............ Schneiden und speichern (Ton: MP2 normalisiert)" off \ | ||
+ | 34 "Mpeg1-Clip............Schneiden und speichern (Ton: MP2 normalisiert)" off` | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | } | ||
+ | untermenue_abspielen () | ||
{ | { | ||
− | + | was_tun=`kdialog --caption "Abspielen" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ | |
− | if [ $? = 0 ] | + | 71 "Videoclip.............Playlist abspielen im Zufallsmodus" on` |
+ | if [ $? != 0 ] | ||
then | then | ||
− | + | benutzerabbruch | |
− | |||
− | |||
− | |||
fi | fi | ||
} | } | ||
− | + | ||
− | + | untermenue_direktdruck () | |
{ | { | ||
− | + | was_tun=`kdialog --caption "Direktdruck" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ | |
− | if [ $? = 0 ] | + | 81 "DVD bedrucken......Text und Bild (Video-DVD)" on \ |
+ | 82 "DVD bedrucken......nur Text (Daten-DVD)" off` | ||
+ | if [ $? != 0 ] | ||
then | then | ||
− | + | benutzerabbruch | |
− | |||
− | |||
− | |||
fi | fi | ||
} | } | ||
− | # | + | # °°°°Auswahl Quelldateien°°°° |
+ | |||
+ | filmauswahl () | ||
+ | { | ||
+ | echo "Quelldatei auswählen" | ||
− | + | case $was_tun in | |
− | + | 11) brenn_pfad=$hauptverzeichnis/dvdstruktur ;; | |
+ | 12) brenn_pfad=$hauptverzeichnis/dvdstruktur ;; | ||
+ | 21) brenn_pfad=$hauptverzeichnis/tmp1 ;; | ||
+ | 22) brenn_pfad=$hauptverzeichnis/tmp1 ;; | ||
+ | esac | ||
+ | |||
+ | quelldatei=`kdialog --caption "Filmauswahl" --geometry 600x500-0+0 --getopenfilename "$aufnahme"` | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | verzeichnisauswahl () | ||
{ | { | ||
− | echo "** | + | echo "Quelldatei auswählen" |
− | + | ||
− | echo "* | + | case $was_tun in |
+ | 13) verzeichnistyp="*_dvd" ;; | ||
+ | 23) verzeichnistyp="*_ts" ;; | ||
+ | esac | ||
+ | |||
+ | anzahl_der_sicherungen=`find $hauptverzeichnis/sicherung/$verzeichnistyp -maxdepth 0 -type d | wc -l` | ||
+ | hilfsverzeichnis=`find $hauptverzeichnis/sicherung/$verzeichnistyp -maxdepth 0 -type d` | ||
+ | |||
+ | case $anzahl_der_sicherungen in | ||
+ | 0) funktionsabbruch "Es gibt nichts passendes zum Brennen. Das Script wird nun beendet." ;; | ||
+ | 1) echo "$hilfsverzeichnis" | ||
+ | verzeichnis=$hilfsverzeichnis ;; | ||
+ | *) verzeichnis=`kdialog --combobox "Welche Datei soll gebrannt werden?" $hilfsverzeichnis` | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi ;; | ||
+ | esac | ||
+ | |||
+ | brenn_pfad=$verzeichnis | ||
} | } | ||
− | # | + | # °°°°Eingangsverarbeitung°°°° |
− | + | ||
+ | # Schneiden und Demultiplexen | ||
+ | pjx_demux_gui () | ||
{ | { | ||
− | echo " | + | echo "ProjectX: Schneiden und demultiplexen" |
− | java -jar $ | + | java -jar $pjx -demux -gui -ini $hauptverzeichnis/X.ini -out $hauptverzeichnis/tmp1 -name film "$quelldatei" |
− | |||
} | } | ||
− | # | + | # Schneiden und Wandeln nach TS |
− | + | pjx_ts_gui () | |
{ | { | ||
− | echo " | + | echo "ProjectX: Schneiden und demultiplexen" |
− | java -jar $ | + | java -jar $pjx -tots -gui -split 4300 -ini $hauptverzeichnis/X.ini -out $hauptverzeichnis/tmp1 -name film "$quelldatei" |
− | |||
} | } | ||
− | |||
mpeg1_input () | mpeg1_input () | ||
{ | { | ||
− | echo " | + | echo "ffmpeg: Decodierung Audio" |
− | $ | + | $ffmpeg -i "$quelldatei" $hauptverzeichnis/tmp1/film.mp2 -vcodec copy $hauptverzeichnis/tmp1/film.m1v |
− | |||
− | |||
} | } | ||
+ | # °°°°°Bearbeitung°°°° | ||
− | |||
− | |||
− | |||
requantisieren () | requantisieren () | ||
{ | { | ||
− | + | audio_video_summe=`du -bc $hauptverzeichnis/tmp1/*.ac3 $hauptverzeichnis/tmp1/*.mp2 $hauptverzeichnis/tmp1/*.m2v | cut -f1 | tail -n 1` | |
− | + | if [ $audio_video_summe -ge $dvdgroesse ] | |
− | |||
− | |||
− | |||
− | if [ $audio_video_summe -ge $ | ||
then | then | ||
− | echo " | + | kdialog --yesno "Der Film ist zu groß für eine DVD. Requantisieren?" |
− | + | if [ $? = 0 ] | |
− | + | then | |
− | + | echo "Requantisieren..." | |
− | + | videogroesse=`du -bc $hauptverzeichnis/tmp1/*.m2v | cut -f1 | tail -n 1` | |
+ | echo "Teil 1" | ||
+ | audio_summe=`du -bc $hauptverzeichnis/tmp1/*.ac3 $hauptverzeichnis/tmp1/*.mp2 | cut -f1 | tail -n 1` | ||
+ | echo "Teil 2" | ||
+ | requantisierungsfaktor=`echo "scale=8 ; ${videogroesse}/$((dvdgroesse-audio_summe))*1.04" | bc` | ||
+ | echo "Teil 3" | ||
+ | cat $hauptverzeichnis/tmp1/film.m2v | requant_lxdvdrip $requantisierungsfaktor $videogroesse > $hauptverzeichnis/tmp1/film.requant | ||
+ | echo "Rückkopieren..." | ||
+ | mv $hauptverzeichnis/tmp1/film.requant $hauptverzeichnis/tmp1/film.m2v | ||
+ | else | ||
+ | programmende | ||
+ | fi | ||
fi | fi | ||
} | } | ||
− | #- | + | # mp2-Ton auf einheitliche Lautstärke bringen (-12dBfs) |
− | |||
− | |||
normalisieren () | normalisieren () | ||
{ | { | ||
− | echo " | + | mv $hauptverzeichnis/tmp1/film.mp2 $hauptverzeichnis/tmp2 |
− | $ | + | rm -- $hauptverzeichnis/tmp1/*.mp2 |
− | echo "* | + | |
+ | echo "ffmpeg: Ton decodieren" | ||
+ | $ffmpeg -i $hauptverzeichnis/tmp2/film.mp2 $hauptverzeichnis/tmp2/film.mp2.wav | ||
+ | |||
+ | echo "normalize: Ton normalisieren" | ||
+ | $normalize $hauptverzeichnis/tmp2/film.mp2.wav | ||
+ | |||
+ | echo "ffmpeg: Ton encodieren" | ||
+ | $ffmpeg -i $hauptverzeichnis/tmp2/film.mp2.wav -acodec mp2 -ab 192k $hauptverzeichnis/tmp1/film.mp2 | ||
+ | |||
+ | rm -- $hauptverzeichnis/tmp2/* | ||
} | } | ||
− | + | ac3_behalten () | |
− | |||
{ | { | ||
− | + | if [ ! -e $hauptverzeichnis/tmp1/*.ac3 ] | |
− | + | then | |
− | + | funktionsabbruch "Der Clip enthält keinen AC3-Ton. Das Script wird nun beendet." | |
− | rm $ | + | fi |
− | + | ||
+ | rm -- $hauptverzeichnis/tmp1/*.mp2 | ||
} | } | ||
− | + | mp2_behalten () | |
+ | { | ||
+ | if [ ! -e $hauptverzeichnis/tmp1/*.mp2 ] | ||
+ | then | ||
+ | funktionsabbruch "Der Clip enthält keinen mp2-Ton. Das Script wird nun beendet." | ||
+ | fi | ||
+ | |||
+ | rm -- $hauptverzeichnis/tmp1/*.ac3 | ||
+ | } | ||
+ | |||
+ | # °°°°Multiplexen, Codieren°°°° | ||
+ | |||
multiplexen () | multiplexen () | ||
{ | { | ||
− | echo " | + | echo "mplex: Multiplexen, kann etwas dauern ..." |
− | |||
mpeg1_video= | mpeg1_video= | ||
mpeg2_video= | mpeg2_video= | ||
Zeile 310: | Zeile 360: | ||
ac3_audio= | ac3_audio= | ||
− | mpeg1_video=`find $ | + | mpeg1_video=`find $hauptverzeichnis/tmp1 | grep "m1v"` |
− | mpeg2_video=`find $ | + | mpeg2_video=`find $hauptverzeichnis/tmp1 | grep "m2v"` |
− | mp2_audio=`find $ | + | mp2_audio=`find $hauptverzeichnis/tmp1 | grep "mp2"` |
− | ac3_audio=`find $ | + | ac3_audio=`find $hauptverzeichnis/tmp1 | grep "ac3"` |
− | $ | + | $mplex -v1 -f8 -o $hauptverzeichnis/tmp1/film.mpg $mpeg1_video $mpeg2_video $ac3_audio $mp2_audio |
− | + | if [ ! -e $hauptverzeichnis/tmp1/film.mpg ] | |
− | + | then | |
− | + | funktionsabbruch "Es konnte keine Datei multiplext werden!" | |
− | + | fi | |
− | |||
} | } | ||
+ | # °°°°Authorn°°°° | ||
− | |||
− | |||
− | |||
− | |||
authoring_ohne_menue () | authoring_ohne_menue () | ||
{ | { | ||
− | echo " | + | echo "dvdauthor: Erzeugen der DVD-Struktur" |
− | $ | + | $dvdauthor -o $hauptverzeichnis/dvdstruktur -t $hauptverzeichnis/tmp1/film.mpg #VOBs und "Kapitel"-IFOs |
− | $ | + | $dvdauthor -o $hauptverzeichnis/dvdstruktur -T #VIDEO_TS.BUP und VIDEO_TS.IFO |
− | |||
} | } | ||
+ | # °°°°Brennen°°°° | ||
− | # | + | # Video-DVD |
− | |||
− | |||
brennen_video_dvd () | brennen_video_dvd () | ||
{ | { | ||
− | echo " | + | echo "growisofs: Video-DVD brennen" |
− | kdialog -- | + | $growisofs -dry-run -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad |
− | $ | + | while [ $? != 0 ] |
− | + | do | |
− | + | kdialog --warningcontinuecancel "DVD nicht bereit" | |
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | $growisofs -dry-run -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad | ||
+ | done | ||
+ | echo "Brennen beginnt" | ||
+ | $growisofs -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad | ||
+ | funktionsabbruch "Brennen fertig. Programm beendet" | ||
} | } | ||
− | # | + | # Daten-DVD |
brennen_ts () | brennen_ts () | ||
{ | { | ||
− | echo " | + | echo "growisofs: Daten-DVD brennen" |
− | dvdzahl=`find $ | + | dvdzahl=`find $brenn_pfad -type f | wc -l` |
− | + | echo "Anzahl der notwendigen DVDs: $dvdzahl" | |
− | for((i=1; i<=$ | + | for((i=1; i<=$dvdzahl; i++)) |
do | do | ||
− | kdialog -- | + | $growisofs -dry-run -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" |
− | + | while [ $? != 0 ] | |
− | + | do | |
+ | kdialog --warningcontinuecancel "Bitte DVD Nr.: $i einlegen" | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | $growisofs -dry-run -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" | ||
+ | done | ||
+ | echo "Brennvorgang gestartet" | ||
+ | $growisofs -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" | ||
done | done | ||
− | + | funktionsabbruch "Brennen fertig. Programm beendet" | |
− | |||
− | |||
} | } | ||
− | # | + | #°°°°Sichern°°°° |
− | + | sichern_dvd_struktur () | |
− | |||
{ | { | ||
− | echo " | + | echo "Sichern der DVD-Stuktur" |
− | sicherungsordner=$(date +%Y%m%d%H%M%S) | + | sicherungsordner="$(date +%Y%m%d%H%M%S)_dvd" |
− | mkdir $ | + | mkdir $hauptverzeichnis/sicherung/$sicherungsordner |
− | mv $ | + | mv $hauptverzeichnis/dvdstruktur/* $hauptverzeichnis/sicherung/$sicherungsordner |
− | + | funktionsabbruch "Datei gesichert nach $hauptverzeichnis/sicherung/$sicherungsordner. Programm beendet" | |
− | |||
} | } | ||
− | |||
sichern_ts () | sichern_ts () | ||
{ | { | ||
− | echo " | + | echo "Sichern des TS-File" |
− | sicherungsordner=$(date +%Y%m%d%H%M%S) | + | sicherungsordner="$(date +%Y%m%d%H%M%S)_ts" |
− | mkdir $ | + | mkdir $hauptverzeichnis/sicherung/$sicherungsordner |
− | mv $ | + | mv $hauptverzeichnis/tmp1/*.ts $hauptverzeichnis/sicherung/$sicherungsordner |
− | + | funktionsabbruch "Datei gesichert nach $hauptverzeichnis/sicherung/$sicherungsordner. Programm beendet" | |
− | |||
} | } | ||
− | + | sichern_clip () | |
− | |||
{ | { | ||
− | clipspeicher=`kdialog --title "$quelldatei" --getsavefilename $ | + | echo "Speichern des Videoclips" |
− | + | clipspeicher=`kdialog --title "$quelldatei" --getsavefilename $videoclips` | |
− | mv $ | + | if [ $? != 0 ] |
+ | then | ||
+ | benutzerabbruch | ||
+ | fi | ||
+ | |||
+ | if [ -e "$clipspeicher" ] | ||
+ | then | ||
+ | kdialog --yesno "Dieser Clip ist schon gespeichert. Überschreiben?" | ||
+ | if [ $? != 0 ] | ||
+ | then | ||
+ | sichern_clip | ||
+ | fi | ||
+ | fi | ||
+ | |||
+ | mv $hauptverzeichnis/tmp1/film.mpg "$clipspeicher" | ||
+ | funktionsabbruch "Videoclip gespeichert: $clipspeicher" | ||
} | } | ||
− | # | + | #°°°°Abspielen°°°° |
− | + | playlist_abspielen_shuffle () | |
− | |||
{ | { | ||
− | + | nohup $xine -P $hauptverzeichnis/playlist -a 1 -l=shuffle & | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | + | # --------------------------------Hauptprogramm------------------------------------ | |
− | |||
− | + | #-----Menueauswahl----- | |
− | + | ||
+ | hauptmenue | ||
+ | case $auswahl_hauptmenue in | ||
+ | 1) untermenue_video_dvd ;; | ||
+ | 2) untermenue_ts ;; | ||
+ | 3) untermenue_videoclip ;; | ||
+ | 7) untermenue_abspielen ;; | ||
+ | 8) untermenue_direktdruck ;; | ||
+ | esac | ||
− | # | + | # Video-DVD |
− | |||
− | |||
case $was_tun in | case $was_tun in | ||
− | + | 11) filmauswahl | |
− | |||
pjx_demux_gui | pjx_demux_gui | ||
requantisieren | requantisieren | ||
multiplexen | multiplexen | ||
− | |||
authoring_ohne_menue | authoring_ohne_menue | ||
− | + | brennen_video_dvd | |
− | + | programmende ;; | |
− | + | 12) filmauswahl | |
− | |||
pjx_demux_gui | pjx_demux_gui | ||
requantisieren | requantisieren | ||
multiplexen | multiplexen | ||
− | |||
authoring_ohne_menue | authoring_ohne_menue | ||
− | + | sichern_dvd_struktur | |
+ | programmende ;; | ||
− | + | 13) verzeichnisauswahl | |
− | + | brennen_video_dvd | |
− | + | programmende ;; | |
− | + | esac | |
− | + | # Daten-DVD | |
− | + | ||
+ | case $was_tun in | ||
+ | |||
+ | 21) filmauswahl | ||
pjx_ts_gui | pjx_ts_gui | ||
− | brennen_ts ;; | + | brennen_ts |
+ | programmende ;; | ||
− | + | 22) filmauswahl | |
pjx_ts_gui | pjx_ts_gui | ||
− | sichern_ts ;; | + | sichern_ts |
+ | programmende ;; | ||
+ | |||
+ | 23) verzeichnisauswahl | ||
+ | brennen_ts | ||
+ | programmende ;; | ||
+ | esac | ||
− | + | # Videoclips | |
− | |||
− | |||
− | + | case $was_tun in | |
− | + | ||
+ | 31) filmauswahl | ||
+ | pjx_demux_gui | ||
+ | multiplexen | ||
+ | sichern_clip | ||
+ | programmende ;; | ||
+ | |||
+ | 32) filmauswahl | ||
+ | pjx_demux_gui | ||
+ | ac3_behalten | ||
+ | multiplexen | ||
+ | sichern_clip | ||
+ | programmende ;; | ||
+ | |||
+ | 33) filmauswahl | ||
+ | pjx_demux_gui | ||
+ | mp2_behalten | ||
+ | multiplexen | ||
+ | sichern_clip | ||
+ | programmende ;; | ||
+ | |||
+ | 34) filmauswahl | ||
+ | mpeg1_input | ||
+ | multiplexen | ||
+ | sichern_clip | ||
+ | programmende ;; | ||
+ | |||
+ | 37) filmauswahl | ||
+ | pjx_demux_gui | ||
+ | mp2_behalten | ||
normalisieren | normalisieren | ||
− | |||
multiplexen | multiplexen | ||
− | + | sichern_clip | |
− | + | programmende ;; | |
− | + | 38) filmauswahl | |
mpeg1_input | mpeg1_input | ||
normalisieren | normalisieren | ||
− | |||
multiplexen | multiplexen | ||
− | + | sichern_clip | |
− | + | programmende ;; | |
+ | esac | ||
+ | |||
+ | # Abspielen | ||
+ | |||
+ | case $was_tun in | ||
+ | |||
+ | 71) playlist_abspielen_shuffle ;; | ||
esac | esac | ||
− | + | # DVD bedrucken | |
+ | |||
+ | case $was_tun in | ||
+ | |||
+ | 81) oodraw -o $druckschablonen/videodvd.odg ;; | ||
+ | 82) oodraw -o $druckschablonen/datendvd.odg ;; | ||
+ | esac | ||
+ | </pre> | ||
− | + | {{Dvbscript navigationsbox}} | |
− | + | [[Category:DVB-Weiterverarbeitung]] |
Aktuelle Version vom 9. Januar 2011, 14:24 Uhr
Vom DVB zur DVD, ein Wikibuch: Übersicht - Der Weg - Die Helferprogramme - Das Script - Installation - Bedienungsanleitung - Programmieranleitung |
Bitte die Installationsanleitung beachten!
#!/bin/bash #Name: dvb_wiki_script #Version: 0.9.0 #Erstellungsdatum: 9.1.2011 #Autor: escho (www.linux-club.de) #Benutzung auf eigene Gefahr #Dieses Shell Script automatisiert weitgehend die Vorgänge, die nötig sind, um aus einer DVB-Aufnahme #eine abspielbare Video-DVD zu erzeugen. Es ist nur zusammen mit dem Installationsscript und dem GUI-Script lauffähig. #Neu in dieser Version: siehe Diskussion # ---------------------------------Vorbereitungen------------------------------------- # Voreinstellungen hauptverzeichnis=$HOME/dvb_wiki_script ini_verz=$HOME/.dvb_wiki_script aufnahme=$HOME/DVB/Aufnahme druckschablonen=$HOME/DVB/Druckschablonen videoclips=$HOME/DVB/Videoclips speed=8 dvdgroesse=4600000000 export VIDEO_FORMAT=PAL # Verzeichnisstruktur erstellen mkdir $hauptverzeichnis 2>/dev/null mkdir $ini_verz 2>/dev/null mkdir $hauptverzeichnis/dvdstruktur 2>/dev/null mkdir $hauptverzeichnis/sicherung 2>/dev/null mkdir $hauptverzeichnis/tmp1 2>/dev/null mkdir $hauptverzeichnis/tmp2 2>/dev/null # Hilfsprogramme festlegen hilfsprogramm=( mplex dvdauthor ProjectX.jar normalize ffmpeg growisofs xine requant_lxdvdrip ) for var in ${hilfsprogramm[*]} do touch $ini_verz/$var hilfsvar=`cat $ini_verz/$var` if [ ! -e "$hilfsvar/$var" ] then echo "Programmsuche: $var" gefundene_pfade=`find /bin $HOME /opt /usr ! -path "$HOME/.*" -type f -name $var ! -printf "%h " 2>/dev/null` pfadzahl=`echo "$gefundene_pfade" | wc -w` case "$pfadzahl" in 0) kdialog --error "Das Programm wurde nicht gefunden. Bitte zuerst installieren." exit ;; 1) echo "$var gefunden" echo $gefundene_pfade > $ini_verz/$var ;; *) auswahl=`kdialog --caption "$var" --combobox "Bitte Pfad auswählen" $gefundene_pfade` if [ $? = 0 ] then echo "$var gefunden" echo $auswahl > $ini_verz/$var else kdialog --error "Abbruch durch den Benutzer! Installation wird abgebrochen!" exit fi ;; esac fi done # Hilfsprogramme laden mplex=`cat $ini_verz/mplex`/mplex dvdauthor=`cat $ini_verz/dvdauthor`/dvdauthor pjx=`cat $ini_verz/ProjectX.jar`/ProjectX.jar normalize=`cat $ini_verz/normalize`/normalize ffmpeg=`cat $ini_verz/ffmpeg`/ffmpeg growisofs=`cat $ini_verz/growisofs`/growisofs xine=`cat $ini_verz/xine`/xine requant=`cat $ini_verz/requant_lxdvdrip`/requant_lxdvdrip # X.ini erzeugen echo "X.ini für ProjectX erzeugen" echo \ "# Application Application.Agreement=1 Application.Language=de Application.ActiveDirectory=$aufnahme # CollectionPanel CollectionPanel.Preview.SliderWidth=0 # WindowPosition WindowPosition.Main.Width=9999 WindowPosition.Main.Y=0 # OptionPanel OptionPanel.NormalLog=0 OptionPanel.closeOnEnd=1" \ > $hauptverzeichnis/X.ini # Playlist für mplayer find $videoclips/* > $hauptverzeichnis/playlist # Löschen echo "Löschen tmp, kann etwas dauern ..." rm -r -- $hauptverzeichnis/tmp1/* 2>/dev/null rm -r -- $hauptverzeichnis/tmp2/* 2>/dev/null rm -r -- $hauptverzeichnis/dvdstruktur/* 2>/dev/null # ----------------------------------Funktionen------------------------------------- # °°°° Abbruch °°°° benutzerabbruch () { echo "Abbruch durch den Benutzer" programmende } funktionsabbruch () { echo "$1" programmende } programmende () { echo "Ende" kdialog --msgbox "Programmende" exit } # °°° Aufgabenmenues °°° hauptmenue () { auswahl_hauptmenue=`kdialog --caption "Hauptmenue" --geometry 200x250+500+400 --radiolist "Bitte einen Aufgabenbereich wählen" \ 1 "VIDEO-DVD" on \ 2 "TS-Stream" off \ 3 "Videoclips" off \ 7 "Abspielen" off \ 8 "DVD bedrucken" off` if [ $? != 0 ] then benutzerabbruch fi } untermenue_video_dvd () { brenn_pfad=${dvdstruktur_pfad} was_tun=`kdialog --caption "Video_DVD" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ 11 "VIDEO-DVD........Fernsehaufnahme schneiden --> als Video-DVD brennen" on \ 12 "VIDEO-DVD........Fernsehaufnahme schneiden --> DVD-Struktur in Datei sichern" off \ 13 "VIDEO-DVD........Sicherung brennen" off` if [ $? != 0 ] then benutzerabbruch fi } untermenue_ts () { was_tun=`kdialog --caption "Daten-DVD" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ 21 "TS-Stream..........Fernsehaufnahme schneiden --> TS als Daten-DVD brennen" on \ 22 "TS-Stream..........Fernsehaufnahme schneiden --> TS sichern" off \ 23 "TS-Stream..........Sicherung als Daten-DVD brennen" off` if [ $? != 0 ] then benutzerabbruch fi } untermenue_videoclip () { was_tun=`kdialog --caption "Videoclips" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ 31 "Videoclip.............Schneiden und speichern (Ton: MP2 normalisiert + AC3)" on \ 32 "Videoclip............ Schneiden und speichern (Ton: AC3)" off \ 33 "Videoclip............ Schneiden und speichern (Ton: MP2 normalisiert)" off \ 34 "Mpeg1-Clip............Schneiden und speichern (Ton: MP2 normalisiert)" off` if [ $? != 0 ] then benutzerabbruch fi } untermenue_abspielen () { was_tun=`kdialog --caption "Abspielen" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ 71 "Videoclip.............Playlist abspielen im Zufallsmodus" on` if [ $? != 0 ] then benutzerabbruch fi } untermenue_direktdruck () { was_tun=`kdialog --caption "Direktdruck" --geometry 600x250+400+400 --radiolist "Was also soll genau getan werden?" \ 81 "DVD bedrucken......Text und Bild (Video-DVD)" on \ 82 "DVD bedrucken......nur Text (Daten-DVD)" off` if [ $? != 0 ] then benutzerabbruch fi } # °°°°Auswahl Quelldateien°°°° filmauswahl () { echo "Quelldatei auswählen" case $was_tun in 11) brenn_pfad=$hauptverzeichnis/dvdstruktur ;; 12) brenn_pfad=$hauptverzeichnis/dvdstruktur ;; 21) brenn_pfad=$hauptverzeichnis/tmp1 ;; 22) brenn_pfad=$hauptverzeichnis/tmp1 ;; esac quelldatei=`kdialog --caption "Filmauswahl" --geometry 600x500-0+0 --getopenfilename "$aufnahme"` if [ $? != 0 ] then benutzerabbruch fi } verzeichnisauswahl () { echo "Quelldatei auswählen" case $was_tun in 13) verzeichnistyp="*_dvd" ;; 23) verzeichnistyp="*_ts" ;; esac anzahl_der_sicherungen=`find $hauptverzeichnis/sicherung/$verzeichnistyp -maxdepth 0 -type d | wc -l` hilfsverzeichnis=`find $hauptverzeichnis/sicherung/$verzeichnistyp -maxdepth 0 -type d` case $anzahl_der_sicherungen in 0) funktionsabbruch "Es gibt nichts passendes zum Brennen. Das Script wird nun beendet." ;; 1) echo "$hilfsverzeichnis" verzeichnis=$hilfsverzeichnis ;; *) verzeichnis=`kdialog --combobox "Welche Datei soll gebrannt werden?" $hilfsverzeichnis` if [ $? != 0 ] then benutzerabbruch fi ;; esac brenn_pfad=$verzeichnis } # °°°°Eingangsverarbeitung°°°° # Schneiden und Demultiplexen pjx_demux_gui () { echo "ProjectX: Schneiden und demultiplexen" java -jar $pjx -demux -gui -ini $hauptverzeichnis/X.ini -out $hauptverzeichnis/tmp1 -name film "$quelldatei" } # Schneiden und Wandeln nach TS pjx_ts_gui () { echo "ProjectX: Schneiden und demultiplexen" java -jar $pjx -tots -gui -split 4300 -ini $hauptverzeichnis/X.ini -out $hauptverzeichnis/tmp1 -name film "$quelldatei" } mpeg1_input () { echo "ffmpeg: Decodierung Audio" $ffmpeg -i "$quelldatei" $hauptverzeichnis/tmp1/film.mp2 -vcodec copy $hauptverzeichnis/tmp1/film.m1v } # °°°°°Bearbeitung°°°° requantisieren () { audio_video_summe=`du -bc $hauptverzeichnis/tmp1/*.ac3 $hauptverzeichnis/tmp1/*.mp2 $hauptverzeichnis/tmp1/*.m2v | cut -f1 | tail -n 1` if [ $audio_video_summe -ge $dvdgroesse ] then kdialog --yesno "Der Film ist zu groß für eine DVD. Requantisieren?" if [ $? = 0 ] then echo "Requantisieren..." videogroesse=`du -bc $hauptverzeichnis/tmp1/*.m2v | cut -f1 | tail -n 1` echo "Teil 1" audio_summe=`du -bc $hauptverzeichnis/tmp1/*.ac3 $hauptverzeichnis/tmp1/*.mp2 | cut -f1 | tail -n 1` echo "Teil 2" requantisierungsfaktor=`echo "scale=8 ; ${videogroesse}/$((dvdgroesse-audio_summe))*1.04" | bc` echo "Teil 3" cat $hauptverzeichnis/tmp1/film.m2v | requant_lxdvdrip $requantisierungsfaktor $videogroesse > $hauptverzeichnis/tmp1/film.requant echo "Rückkopieren..." mv $hauptverzeichnis/tmp1/film.requant $hauptverzeichnis/tmp1/film.m2v else programmende fi fi } # mp2-Ton auf einheitliche Lautstärke bringen (-12dBfs) normalisieren () { mv $hauptverzeichnis/tmp1/film.mp2 $hauptverzeichnis/tmp2 rm -- $hauptverzeichnis/tmp1/*.mp2 echo "ffmpeg: Ton decodieren" $ffmpeg -i $hauptverzeichnis/tmp2/film.mp2 $hauptverzeichnis/tmp2/film.mp2.wav echo "normalize: Ton normalisieren" $normalize $hauptverzeichnis/tmp2/film.mp2.wav echo "ffmpeg: Ton encodieren" $ffmpeg -i $hauptverzeichnis/tmp2/film.mp2.wav -acodec mp2 -ab 192k $hauptverzeichnis/tmp1/film.mp2 rm -- $hauptverzeichnis/tmp2/* } ac3_behalten () { if [ ! -e $hauptverzeichnis/tmp1/*.ac3 ] then funktionsabbruch "Der Clip enthält keinen AC3-Ton. Das Script wird nun beendet." fi rm -- $hauptverzeichnis/tmp1/*.mp2 } mp2_behalten () { if [ ! -e $hauptverzeichnis/tmp1/*.mp2 ] then funktionsabbruch "Der Clip enthält keinen mp2-Ton. Das Script wird nun beendet." fi rm -- $hauptverzeichnis/tmp1/*.ac3 } # °°°°Multiplexen, Codieren°°°° multiplexen () { echo "mplex: Multiplexen, kann etwas dauern ..." mpeg1_video= mpeg2_video= mp2_audio= ac3_audio= mpeg1_video=`find $hauptverzeichnis/tmp1 | grep "m1v"` mpeg2_video=`find $hauptverzeichnis/tmp1 | grep "m2v"` mp2_audio=`find $hauptverzeichnis/tmp1 | grep "mp2"` ac3_audio=`find $hauptverzeichnis/tmp1 | grep "ac3"` $mplex -v1 -f8 -o $hauptverzeichnis/tmp1/film.mpg $mpeg1_video $mpeg2_video $ac3_audio $mp2_audio if [ ! -e $hauptverzeichnis/tmp1/film.mpg ] then funktionsabbruch "Es konnte keine Datei multiplext werden!" fi } # °°°°Authorn°°°° authoring_ohne_menue () { echo "dvdauthor: Erzeugen der DVD-Struktur" $dvdauthor -o $hauptverzeichnis/dvdstruktur -t $hauptverzeichnis/tmp1/film.mpg #VOBs und "Kapitel"-IFOs $dvdauthor -o $hauptverzeichnis/dvdstruktur -T #VIDEO_TS.BUP und VIDEO_TS.IFO } # °°°°Brennen°°°° # Video-DVD brennen_video_dvd () { echo "growisofs: Video-DVD brennen" $growisofs -dry-run -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad while [ $? != 0 ] do kdialog --warningcontinuecancel "DVD nicht bereit" if [ $? != 0 ] then benutzerabbruch fi $growisofs -dry-run -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad done echo "Brennen beginnt" $growisofs -speed=$speed -dvd-compat -Z /dev/dvd -dvd-video $brenn_pfad funktionsabbruch "Brennen fertig. Programm beendet" } # Daten-DVD brennen_ts () { echo "growisofs: Daten-DVD brennen" dvdzahl=`find $brenn_pfad -type f | wc -l` echo "Anzahl der notwendigen DVDs: $dvdzahl" for((i=1; i<=$dvdzahl; i++)) do $growisofs -dry-run -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" while [ $? != 0 ] do kdialog --warningcontinuecancel "Bitte DVD Nr.: $i einlegen" if [ $? != 0 ] then benutzerabbruch fi $growisofs -dry-run -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" done echo "Brennvorgang gestartet" $growisofs -speed=$speed -Z /dev/dvd -allow-limited-size -R -J $brenn_pfad/"film($((i-1)))[remux].ts" done funktionsabbruch "Brennen fertig. Programm beendet" } #°°°°Sichern°°°° sichern_dvd_struktur () { echo "Sichern der DVD-Stuktur" sicherungsordner="$(date +%Y%m%d%H%M%S)_dvd" mkdir $hauptverzeichnis/sicherung/$sicherungsordner mv $hauptverzeichnis/dvdstruktur/* $hauptverzeichnis/sicherung/$sicherungsordner funktionsabbruch "Datei gesichert nach $hauptverzeichnis/sicherung/$sicherungsordner. Programm beendet" } sichern_ts () { echo "Sichern des TS-File" sicherungsordner="$(date +%Y%m%d%H%M%S)_ts" mkdir $hauptverzeichnis/sicherung/$sicherungsordner mv $hauptverzeichnis/tmp1/*.ts $hauptverzeichnis/sicherung/$sicherungsordner funktionsabbruch "Datei gesichert nach $hauptverzeichnis/sicherung/$sicherungsordner. Programm beendet" } sichern_clip () { echo "Speichern des Videoclips" clipspeicher=`kdialog --title "$quelldatei" --getsavefilename $videoclips` if [ $? != 0 ] then benutzerabbruch fi if [ -e "$clipspeicher" ] then kdialog --yesno "Dieser Clip ist schon gespeichert. Überschreiben?" if [ $? != 0 ] then sichern_clip fi fi mv $hauptverzeichnis/tmp1/film.mpg "$clipspeicher" funktionsabbruch "Videoclip gespeichert: $clipspeicher" } #°°°°Abspielen°°°° playlist_abspielen_shuffle () { nohup $xine -P $hauptverzeichnis/playlist -a 1 -l=shuffle & } # --------------------------------Hauptprogramm------------------------------------ #-----Menueauswahl----- hauptmenue case $auswahl_hauptmenue in 1) untermenue_video_dvd ;; 2) untermenue_ts ;; 3) untermenue_videoclip ;; 7) untermenue_abspielen ;; 8) untermenue_direktdruck ;; esac # Video-DVD case $was_tun in 11) filmauswahl pjx_demux_gui requantisieren multiplexen authoring_ohne_menue brennen_video_dvd programmende ;; 12) filmauswahl pjx_demux_gui requantisieren multiplexen authoring_ohne_menue sichern_dvd_struktur programmende ;; 13) verzeichnisauswahl brennen_video_dvd programmende ;; esac # Daten-DVD case $was_tun in 21) filmauswahl pjx_ts_gui brennen_ts programmende ;; 22) filmauswahl pjx_ts_gui sichern_ts programmende ;; 23) verzeichnisauswahl brennen_ts programmende ;; esac # Videoclips case $was_tun in 31) filmauswahl pjx_demux_gui multiplexen sichern_clip programmende ;; 32) filmauswahl pjx_demux_gui ac3_behalten multiplexen sichern_clip programmende ;; 33) filmauswahl pjx_demux_gui mp2_behalten multiplexen sichern_clip programmende ;; 34) filmauswahl mpeg1_input multiplexen sichern_clip programmende ;; 37) filmauswahl pjx_demux_gui mp2_behalten normalisieren multiplexen sichern_clip programmende ;; 38) filmauswahl mpeg1_input normalisieren multiplexen sichern_clip programmende ;; esac # Abspielen case $was_tun in 71) playlist_abspielen_shuffle ;; esac # DVD bedrucken case $was_tun in 81) oodraw -o $druckschablonen/videodvd.odg ;; 82) oodraw -o $druckschablonen/datendvd.odg ;; esac
Vom DVB zur DVD, ein Wikibuch: Übersicht - Der Weg - Die Helferprogramme - Das Script - Installation - Bedienungsanleitung - Programmieranleitung |