All pastes #333091 Raw Edit

Unnamed

public text v1 · immutable
#333091 ·published 2007-01-30 17:59 UTC
rendered paste body
#!/bin/bash

#################################################
# Script zum Schneiden von OTR-Aufnahmen
# (c) 2006, Hagen Meyer -- hagenmeyer@web.de
#
# benutzung auf eigene gefahr...
#################################################

#######################
# CONFIG
#######################

# VORSICHT: tempdir wird komplett geleert!! Vorgabewert is empfehlenswert
tempdir="/tmp/multicut/"

# lokale cutlists (aktueller ordner) verwenden? name ist egal, wird nach inhalt ausgewaehlt
# KEIN vorrang vor heruntergeladenen cutlists bei aktiviertem download und automatischem modus
# 0: nein, 1: ja
local=1

# cutlists downloaden?
# versucht alle verfuegbaren cutlists auf cutlist.de zu finden
# 0: nein, 1: ja
download=1

# automatischer modus
# versucht, selbst die beste cutlist zu finden (lokal und internet, je nach einstellung), und verwendet diese.
# im interaktiven modus (automode=0) werden cutlists auch nach qualitaet sortiert, aber die auswahl erfolgt manuell
automode=0

# Mindest-bewertung (vom Autor) fuer cutlists (schlechter wird ignoriert).
#
# Werte:
# 5: framegenau und keine doppelten Szenen
# 4: framegenau
# 3: +/- 1 sek
# < 3: schlechter (wen interessierts? ;) )
#
# Empfehlung: 4. Wer will schon ungenaue schnitte??
# (wer mit avisplit schneidet kann auch schlechtere cutlists verwenden, das avisplit eh nur an keyframes schneidet)
min_rating=4

# mit welchem programm soll geschnitten werden?
# avidemux
# + kann framegenau schneiden
# - laeuft mit grafischer oberflaeche, kann daher nicht vollstaendig automatisiert werden
#   (die fragen am anfang koennen negativ beantwortet werden - die schritte werden automatisch durchgefuehrt)
# - laeuft nicht aus cronjobs (kann evtl mit "xhost +local:" erlaubt werden - untested)
# 
# avisplit (Standard, falls fehlerhafte angabe)
# - kann nur an keyframes schneiden -> schnitte sind nicht so genau, einige frames/sekunden werbung ist noch drin
# + laeuft vollstaendig auf console, daher auch gut in cronjobs einsetzbar
cutwith="avidemux"

# sollen die schnitte anschliessend mit mplayer ueberprueft werden? 
# check=1 oder 0
# mplayer wird nacheinander ca. 10 sekunden vor dem schnitt gestartet. fuer den naechsten schnitt mplayer einfach beenden (mit q)
# anfang und ende werden auch gezeigt
check=1

# Farben (nur editieren, wenn man weiss was man tut ;) )
# auskommentieren wenn man keine farben moechte

c_filename="\033[00;34m"
c_author="\033[01;37;40m"
c_rating="\033[01;33;41m"
c_cuts="\033[01;33;41m"
c_selection="\033[01;37;40m"
c_error="\033[01;31;40m"
c_end="\033[00m"


#######################
# FUNCTIONS
#######################

# Laed ALLE verfuegbaren cutlists fuer diese datei herunter, die beste wird spaeter gesucht...
##############################################################################################
function dlCutlists () { # filename
  cd $tempdir
  filename=${1##*/}
### alter download, ohne suche
#   for filename in $filename ${filename%.avi} ${filename%.mpg.avi} ; do
#     i=0
#     wget -q "http://cutlist.de/upload/$filename.cutlist"
#     while [ $? -eq 0 ]; do
#       let i++
#       wget -q "http://cutlist.de/upload/$filename.$i.cutlist"
#     done
#   done
#   echo "fertig."
  echo -n "Lade cutlists fuer $filename herunter..."
  # suche bei cutlist.de
  search=${filename%.avi}
  search=${search%.mpg}
  content=$( wget -q -O - --post-data="seek_in=$search&submit=OK" "http://cutlist.de/index.php?cat=seek" )
  urls=$( echo $content | egrep -o "getfile\.php\?id=[[:digit:]]+" )
  # user-wertung
  oldifs=$IFS
  IFS="
"
  userrating=( $( echo $content | egrep -o "[^\"]*User haben bewertet" ) )
  IFS=$oldifs
  i=0
  for url in $urls ; do
    # finde den cutlist-dateinamen heraus (wget kann bisher nur in der Beta den filename aus dem server-header verwenden, workaround fuer aeltere versionen)
    cutlist=$( wget -S --spider "http://cutlist.de/$url" 2>&1 | egrep -o "filename=[^;]+" )
    cutlist=${cutlist##filename=}
    # lade die cutlist herunter
    wget -q -O "$cutlist" "http://cutlist.de/$url"
    rating=${userrating[$i]%%/*}
    users=${userrating[$i]% User haben bewertet}
    users=${users##**[ ]}
    if [ $users == "0" ] ; then
      echo -n "0|0" > ${cutlist}.rating
    else
      echo -n "$rating|$users" > ${cutlist}.rating
    fi
    let i++
  done
  echo "fertig. $i gefunden."
}

# sucht die beste cutlist fuer eine datei aus dem ordner $tempdir
#############################################################
function findBestCutlist () { # filename
  echo "Filtere Cutlists nach gegebenen Kriterien..."
  cd $tempdir
  unset cutlist
  filename=${1##*/}
  i=1
  # Lade die wichtigen daten der passenden cutlists in arrays (cutlist, rating, cuts)
  for cl in `find . -exec grep -q "ApplyToFile=$filename" {} \; -print`; do
    # FIELD: RatingByAuthor
    tmp=`grep RatingByAuthor $cl`
    tmp=${tmp%[[:cntrl:]]} # letztes zeichen loeschen (\r)
    rating[$i]=${tmp#RatingByAuthor=}
    [ ${rating[$i]} -lt $min_rating ]  && continue	# naechste cutlist, wenn rating zu gering
    # "FIELD": Cutlist-Format
    if grep -q "StartFrame=" $cl ; then
      vcf2format[$i]=1
    elif grep -q "Start=" $cl ; then
      vcf2format[$i]=0
    else
      echo "ERROR: unbekanntes Cutlist-Format: ${cl##*/}" >&2
      continue # cutlist ignorieren, unbekanntes format...
    fi
    # FIELD: Author
    tmp=`grep "^Author" $cl`
    tmp=${tmp%[[:cntrl:]]}
    author[$i]=${tmp#Author=}
    author[$i]=${author[$i]:-Unbekannt}
    # FIELD: NoOfCuts
    tmp=`grep NoOfCuts $cl`
    tmp=${tmp%[[:cntrl:]]} # letztes zeichen loeschen (\r)
    cuts[$i]=${tmp#NoOfCuts=}
    # FIELD: Comment
    tmp=`grep UserComment $cl`
    tmp=${tmp%[[:cntrl:]]} # letztes zeichen loeschen (\r)
    comment[$i]=${tmp#UserComment=}
    # verschiedene fehler...
    unset error content errordesc
    if grep -q "EPGError=1" $cl ; then
      tmp=`grep ActualContent $cl`
      tmp=${tmp%[[:cntrl:]]} # letztes zeichen loeschen (\r)
      content[$i]="Tatsaechlicher Inhalt: ${tmp#ActualContent=}"
      error[$i]=" EPG-Fehler! "
    fi
    if grep -q "MissingBeginning=1" $cl ; then
      error[$i]="${error[$i]} Anfang fehlt! "
    fi
    if grep -q "MissingEnding=1" $cl ; then
      error[$i]="${error[$i]} Ende fehlt! "
    fi
    if grep -q "MissingAudio=1" $cl ; then
      error[$i]="${error[$i]} Ton fehlt! "
    fi
    if grep -q "MissingVideo=1" $cl ; then
      error[$i]="${error[$i]} Bild fehlt! "
    fi
    if grep -q "OtherError=1" $cl ; then
      tmp=`grep OtherErrorDescription $cl`
      tmp=${tmp%[[:cntrl:]]} # letztes zeichen loeschen (\r)
      errordesc[$i]="Fehlerbeschreibung: ${tmp#OtherErrorDescription=}"
      error[$i]="${error[$i]} Sonstiger Fehler! "
    fi
    # Nicht vergessen: dateiname ;)
    cutlist[$i]=${cl##*/}
    # userrating
    if [ -f "${cutlist[$i]}.rating" ] ; then
      userrating[$i]=$( cat "${cutlist[$i]}.rating" )
    else
      unset userrating[$i]
    fi
    # erst hier increment, vorher kann das speichern dieser cutlist abgebrochen werden
    let i++
  done
  if [ ${#cutlist[@]} -eq 0 ] ; then
    echo -e "Keine passende Cutlist für $c_filename$filename$c_end gefunden. Abbruch."
    return 0
  fi
  sortCutlists		# gesammelte cutlists nach "qualitaet" sortieren
  [ $automode -ne 0 ] && return 1	# interaktive auswahl nicht noetig, ersten eintrag der arrays verwenden
  # interaktive auswahl...
  clear
  echo -e "\nFuer die Datei $c_filename$filename$c_end wurden folgende cutlists gefunden:\n\n"
  i=1
  while [ $i -le ${#cutlist[@]} ] ; do
    format_string=$( [ ${vcf2format[$i]} -eq 1 ] && echo "VCF2Cutlist-Standard" || echo "Assistant-Standard" )
    printf "$c_selection[%d]$c_end\t%s von $c_author %s $c_end\n\tAutor-Wertung: $c_rating %d $c_end\t\tUser-Wertung: $c_rating %s $c_end (%d Stimmen)\n\tFormat: %s\tAnzahl Schnitte: $c_cuts %d $c_end\n\tKommentar: %s\n" $i "${cutlist[$i]}" "${author[$i]}" "${rating[$i]}" "${userrating[$i]%|*}" "${userrating[$i]#*|}" "$format_string" "${cuts[$i]}" "${comment[$i]}"
    if [ -n "${error[$i]}" ] ; then
      echo -e "\t$c_error${error[$i]}$c_end"
    fi
    if [ -n "${content[$i]}" ] ; then
      echo -e "\t${content[$i]}"
    fi
    if [ -n "${errordesc[$i]}" ] ; then
      echo -e "\t${errordesc[$i]}"
    fi
    echo
    let i++
  done
  printf "$c_selection[0]$c_end\tKeine Auswahl. Diesen Film nicht schneiden.\n\n\n"
  read -p "Auswahl: " ret
  # hier koennte noch ein plausi-check erfolgen...
  return $ret
}

# sortiere cutlists nach "qualitaet" (absteigend): RatingByAuthor->User-Rating->VCF2Format?->NoOfCuts->ActualContent
##########################################################################################
# Erklaerung:
# RatingByAuthor gibt die beste Auskunft der Schnittqualitaet
# VCF2Format schneidet nach Frames, nicht nach zeit ==> duerfte meistens besser sein
# Mehr Cuts duerfte meistens besser sein, (ueberschuessiges Ende weg, keine Werbung uebersehen, etc.)
# ActualContent: wenn leer, dann besser (meistens gesetzt, wenn es nicht um den eigentlich aufgenommenen film geht,
# sondern um das ende des vorhergehenden o.ae.)
# !! vollautomatisch kann NIE die absolut beste cutlist gefunden werden, es ist nur der versuch eine moeglichst gute zu finden...
##################################################################################################################################
function sortCutlists () { # greift auf die arrays zu, die in "findBestCutlist" erstellt werden
  local changed=1
  while [ $changed -eq 1 ] ; do	
    changed=0
    i=2
    while [ $i -le ${#cutlist[@]} ] ; do
      if [ ${rating[$i-1]} -lt ${rating[$i]} ] ; then
        swap $i
        changed=1
      elif [ ${rating[$i-1]} -eq ${rating[$i]} ] && [ "${userrating[$i-1]%|*}" \< "${userrating[$i]%|*}" ] ; then
        swap $i
        changed=1
      elif [ ${rating[$i-1]} -eq ${rating[$i]} ] && [ "${userrating[$i-1]%|*}" = "${userrating[$i]%|*}" ] && [ ${vcf2format[$i-1]} -lt ${vcf2format[$i]} ] ; then
        swap $i
        changed=1
      elif [ ${rating[$i-1]} -eq ${rating[$i]} ] && [ "${userrating[$i-1]%|*}" = "${userrating[$i]%|*}" ] && [ ${vcf2format[$i-1]} -eq ${vcf2format[$i]} ] && [ ${cuts[$i-1]} -lt ${cuts[$i]} ] ; then
        swap $i
        changed=1
      elif [ ${rating[$i-1]} -eq ${rating[$i]} ] && [ "${userrating[$i-1]%|*}" = "${userrating[$i]%|*}" ] && [ ${vcf2format[$i-1]} -eq ${vcf2format[$i]} ] && [ ${cuts[$i-1]} -eq ${cuts[$i]} ] && [ -z "${content[$i]}" ] && [ -n "${content[$i-1]}" ]; then
        swap $i
        changed=1
      fi
      let i++
    done
  done
}

function swap () { # parameter: i: elemente i-1 und i werden (von allen arrays) vertauscht 
  local tmp=${cutlist[$1-1]}
  cutlist[$1-1]=${cutlist[$1]}
  cutlist[$1]=$tmp
  tmp=${rating[$1-1]}
  rating[$1-1]=${rating[$1]}
  rating[$1]=$tmp
  tmp=${userrating[$1-1]}
  userrating[$1-1]=${userrating[$1]}
  userrating[$1]=$tmp
  tmp=${vcf2format[$i-1]}
  vcf2format[$i-1]=${vcf2format[$i]}
  vcf2format[$i]=$tmp
  tmp=${cuts[$1-1]}
  cuts[$1-1]=${cuts[$1]}
  cuts[$1]=$tmp
  tmp=${comment[$1-1]}
  comment[$1-1]=${comment[$1]}
  comment[$1]=$tmp
  tmp=${content[$1-1]}
  content[$1-1]=${content[$1]}
  content[$1]=$tmp
  tmp=${author[$1-1]}
  author[$1-1]=${author[$1]}
  author[$1]=$tmp
  tmp=${error[$1-1]}
  error[$1-1]=${error[$1]}
  error[$1]=$tmp
  tmp=${errordesc[$1-1]}
  errordesc[$1-1]=${errordesc[$1]}
  errordesc[$1]=$tmp
}

# schneide datei mit gegebener cutlist
########################################################################
function cutfilm () { # film, cutlist, vcf2format?
  film=$1
  cutlist=$2
  vcf2format=$3
  cuts=""
  unset checktimes
  checktimes[0]=0
  checkcnt=0
  cd $tempdir
  [ $cutwith == "avidemux" ] && project_start $film
  if [ $vcf2format -eq 1 ] ; then
    lines=$( egrep "(StartFrame|DurationFrames)" $cutlist | tr -d "\r" )
  else
    lines=$( egrep "(Start|Duration)" $cutlist | tr -d "\r" )
  fi
  for line in $lines ; do
    if echo $line | grep -q "Start" ; then 	######### startcut ##########
      startcut=${line##*=}
      if [ $vcf2format -eq 1 ] ; then
        if [ $cutwith == "avidemux" ] ; then
          echo -n "app.addSegment(0,$startcut," >> project.js
        else
          cuts=$cuts$startcut-
        fi
      else
        secs=${startcut%%.*}
        decimalsecs=${startcut##*.}
        decimalsecs=${decimalsecs::2}
        decimalsecs=${decimalsecs#0}
        if [ $cutwith == "avidemux" ] ; then
          frames=$(( $secs*25 + ${decimalsecs:-0} / 4 ))
          echo -n "app.addSegment(0,$frames," >> project.js
        else
          time=$( date -u -d @$secs +%T )		# wandelt sekunden.dezimalen in hh:mm:ss um...
          frames=$(( ${decimalsecs:-0} / 4 ))		# frames ausrechnen runden ist egal
          cuts=$cuts$time.$frames-			# hh:mm:ss.ms (ms ist frames, nicht millisekunden!!)
        fi
      fi
    else					######### endcut ############
      if [ $vcf2format -eq 1 ] ; then
        if [ $cutwith == "avidemux" ] ; then
          echo "${line##*=})" >> project.js
        else
          let endcut=$startcut+${line##*=}
          cuts=$cuts$endcut
        fi
        let checkcnt++
        let checktimes[$checkcnt]=${checktimes[$checkcnt-1]}+${line##*=}/25
      else
        length=${line##*=}
        if [ $cutwith == "avidemux" ] ; then
          decimalsecs=${length##*.}
          decimalsecs=${decimalsecs::2}
          decimalsecs=${decimalsecs#0}
          frames=$(( ${length%%.*}*25 + ${decimalsecs:-0}/4 ))
          echo "$frames)" >> project.js
        else
          add_decimal $startcut ${line##*=}
          time=$( date -u -d @$solution +%T )
          decimalsecs=${solution##*.}
          decimalsecs=${decimalsecs::2}
          decimalsecs=${decimalsecs#2}
          frames=$(( ${decimalsecs:-0} / 4 ))
          cuts=$cuts$time.$frames,
        fi
        let checkcnt++
        let checktimes[$checkcnt]=${checktimes[$checkcnt-1]}+${length%%.*}
      fi
    fi
  done
  name=${film##*/}
  outname="$cutdir/${name%.mpg.avi}-cut.avi"
  if [ $cutwith == "avidemux" ] ; then
    project_end "$outname"
    echo "Starte avidemux2 mit den errechneten Schnitten..."
    avidemux2 --run project.js
    if [ $? -eq 0 ] ; then
      echo "$name erfolgreich geschnitten!"
      mv $film $uncutdir/$name
    else
      echo "Avidemux2 hat einen Fehler gemeldet! $name moeglicherweise nicht geschnitten!"
      return
    fi
  else 
    cuts=${cuts%,}	# letztes komma abtrennen...
    echo "Uebergebe die errechneten Cuts an avisplit..."
    echo avisplit -i $film -o "$outname" -t $cuts -c
    # Auftrag an avisplit uebergeben... (mergen wird hier durch -c auch erreicht)
    avisplit -i $film -o "$outname" -t $cuts -c
    if [ $? -eq 0 ] ; then
      echo "$name erfolgreich geschnitten!"
      mv $film $uncutdir/$name
    else
      echo "Avisplit hat einen Fehler gemeldet! $name moeglicherweise nicht geschnitten!"
      return
    fi
  fi
  ## schnittstellen ueberpruefen
  echo "Schnitte bei folgenden Zeiten:"
  i=0
  while [ $i -lt ${#checktimes[@]} ] ; do
    date -u -d @${checktimes[$i]} +%T
    [ $check -eq 1 ] && type mplayer && mplayer -ss $(( ${checktimes[$i]} - 10 )) "$outname" 1>/dev/null 2>/dev/null
    let i++
  done
}

function project_start () { # film
cat << HEADER > project.js
//AD
var app = new Avidemux();
app.load("$1");
app.rebuildIndex();
app.clearSegments();
HEADER
}

function project_end () { # save-as
cat << FOOTER >> project.js
app.video.setPostProc(3,3,0);
app.video.setFps1000(25000);
app.video.codec("Copy","CQ=4","0 ");
app.audio.reset();
app.audio.codec("copy",128,0,"");
app.audio.normalizeMode=0;
app.audio.normalizeValue=0;
app.audio.delay=0;
app.audio.mixer("NONE");
app.audio.scanVBR();
app.setContainer("AVI");
setSuccess(app.save("$1"));
FOOTER
}

# dezimales addieren
########################
function add_decimal () { # zahl1, zahl2, ==> ergebnis in $solution
  int1=${1%.*}
  int2=${2%.*}
  let ret_int=$int1+$int2
  dec1=${1#*.}
  dec2=${2#*.}
  while [ ${#dec1} -lt ${#dec2} ] ; do		# solange die erste zahl "kuerzer" ist...
    dec1=${dec1}0
  done
  while [ ${#dec2} -lt ${#dec1} ] ; do		# umgekehrt...
    dec2=${dec2}0
  done
  length=${#dec1}				# maximale laenge der nachkommastellen
  shopt -s extglob
  dec1=${dec1#*[0]}				# fuehrende nuller entfernen
  dec1=${dec1:-0}				# und sicherstellen, dass nicht leer
  dec2=${dec2#*[0]}
  dec2=${dec2:-0}
  let ret_dec=$dec1+$dec2
  if [ ${#ret_dec} -gt $length ] ; then		# laenger, also uebertragen
    let ret_int++
    ret_dec=${ret_dec#1}
  fi
  solution=$ret_int.$ret_dec
}

#######################
# START
#######################

if [ $cutwith == "avidemux" ] && ! type avidemux2 > /dev/null ; then
  echo "Bitte installieren Sie avidemux! Abbruch."
  exit 1
elif ! type avisplit > /dev/null ; then
  echo "Bitte installieren Sie das Paket 'transcode'! Abbruch."
  exit 1
fi

# benoetigte ordner (falls nicht vorhanden) erstellen
workdir=$PWD
cd $PWD
if [ ! -d cut ] ; then
  mkdir cut
fi
cutdir=${PWD%/}/cut
if [ ! -d cut/uncut ] ; then
  mkdir cut/uncut
fi
uncutdir=${PWD%/}/cut/uncut
if [ ! -d $tempdir ] ; then
  mkdir $tempdir || (echo "Kann temporaeren Ordner nicht erstellen! Exit." && exit 1)
fi
tempdir=${tempdir%/}

# temporaeren ordner loeschen
rm -r $tempdir/* 2>/dev/null

# lokale cutlists kopieren (passende wird nach inhalt ausgewaehlt)
[ $local -ne 0 ] && cp *.cutlist $tempdir 2>/dev/null

# zu schneidende dateien durchgehen...
for file in ${@:-*.mpg.avi}; do
  cd $workdir
  file=`cd ${file%/*} 2>/dev/null ; pwd`/${file##*/}	# absoluten dateinamen ermitteln
  [ $download -ne 0 ] && dlCutlists $file
  findBestCutlist $file
  usecl=$?	# zurueckgegebene cutlist verwenden. (array-index)
  [ $usecl -eq 0 ] && continue	# abbruch, film nicht schneiden
  clear 2>/dev/null	# fehler ignorieren (tritt bei cron-aufrufen auf, da $TERM nicht gesetzt ist)
  format_string=$( [ ${vcf2format[$usecl]} -eq 1 ] && echo "VCF2Cutlist-Standard" || echo "Assistant-Standard" )
  printf "\nSchneide Film $c_filename%s$c_end mit folgender Cutlist:\n\n%s von $c_author %s $c_end\nAutor-Wertung: $c_rating %d $c_end\t\tUser-Wertung: $c_rating %s $c_end (%d Stimmen)\nFormat: %s\tAnzahl Schnitte: $c_cuts %d $c_end\nKommentar: %s\n" ${file##*/} "${cutlist[$usecl]}" "${author[$usecl]}" "${rating[$usecl]}" "${userrating[$usecl]%|*}" "${userrating[$usecl]#*|}" "$format_string" "${cuts[$usecl]}" "${comment[$usecl]}"
  if [ -n "${error[$usecl]}" ] ; then
    echo -e "$c_error${error[$usecl]}$c_end"
  fi
  if [ -n "${content[$usecl]}" ] ; then
    echo -e "${content[$usecl]}"
  fi
  if [ -n "${errordesc[$usecl]}" ] ; then
    echo -e "${errordesc[$usecl]}"
  fi
  echo
  cutfilm $file ${cutlist[$usecl]} ${vcf2format[$usecl]}
done

# temporaeren ordner loeschen
rm -r $tempdir/* 2>/dev/null