#!/bin/bash # # BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ # # Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). # # This program is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 3.0 of the License, or (at your option) any later # version. # # BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with BigBlueButton; if not, see . # # Author(s): # Fred Dixon # Gustavo Salazar # Ghazi Triki # Daniel Petri Rocha # # Changelog: # 2011-08-18 FFD Inital Version # 2011-11-20 FFD Added more checks for processing of recording # 2012-01-04 GUG Add option to check for errors # 2012-02-27 GUG Add option to delete one meeting and recording # 2012-08-13 GUG Republish recording # 2012-10-22 FFD Use combination of /var/bigbluebutton and /var/bigbluebutton/recording/raw # to get the list of recent recordings for bbb-record --watch # 2013-04-03 GUG Enable/Disable a recording workflow # 2013-04-05 GUG Description is optional in bbb-record --watch # 2013-04-05 GUG Map internal meeting id with external meeting id # 2016-07-02 FFD Updates for 1.1-beta # 2016-10-17 GTR Stricter rule for detection of recording directories names # 2017-04-28 FFD Updated references to systemd processing units # 2019-05-13 GTR Delete caption files # 2019-08-30 GTR Count SVG slides fallaback # 2020-10-22 AGG Remove traces of red5 apps # 2022-01-07 DPR Refactoring with shellcheck; more checks for recording configuration; # option to list workflows #set -e #set -x source /etc/bigbluebutton/bigbluebutton-release declare -r BBB_USER=bigbluebutton declare -r BBB_YML=/usr/local/bigbluebutton/core/scripts/bigbluebutton.yml # $1: Desired property # Only returns 'PRODUCTION' values get_yml_value(){ yq read "$BBB_YML" "$1" --prettyPrint } PLAYBACK_PROTOCOL=$(get_yml_value playback_protocol) readonly PLAYBACK_PROTOCOL RECORDING_DIR=$(get_yml_value recording_dir) readonly RECORDING_DIR LOG_DIR=$(get_yml_value log_dir) readonly LOG_DIR PUBLISHED_DIR=$(get_yml_value published_dir) readonly PUBLISHED_DIR RAW_AUDIO_SRC=$(get_yml_value raw_audio_src) readonly RAW_AUDIO_SRC RAW_VIDEO_SRC=$(get_yml_value raw_video_src) readonly RAW_VIDEO_SRC RAW_SCREENSHARE_SRC=$(get_yml_value raw_screenshare_src) readonly RAW_SCREENSHARE_SRC RAW_PRESENTATION_SRC=$(get_yml_value raw_presentation_src) readonly RAW_PRESENTATION_SRC declare -r BASE=$RAW_PRESENTATION_SRC/recording declare -r STATUS=$BASE/status TYPES=$(cd /usr/local/bigbluebutton/core/scripts/process || exit; find -- *.rb | sed s/.rb//g) readonly TYPES declare -r MEETING_PATTERN="^[0-9a-f]\{40\}-[[:digit:]]\{13\}$" mark_for_rebuild() { MEETING_ID=$1 echo "Marking for rebuild $MEETING_ID" if [[ ! -d $BASE/raw/$MEETING_ID ]]; then echo "Raw files for $MEETING_ID do not exist, can't rebuild" exit 1 fi # Clear out the relevant done files rm -vf "$STATUS"/archived/"$MEETING_ID".norecord rm -vf "$STATUS"/sanity/"$MEETING_ID"* rm -vf "$STATUS"/processed/"$MEETING_ID"* rm -vf "$STATUS"/published/"$MEETING_ID"* # Remove the existing 'published' recording files for type in $TYPES; do rm -rf "${PUBLISHED_DIR:?}"/"$type"/"$MEETING_ID" rm -rf "$RAW_PRESENTATION_SRC"/unpublished/"$type"/"$MEETING_ID" rm -rf "$RAW_PRESENTATION_SRC"/deleted/"$type"/"$MEETING_ID" done # Restart processing at the 'sanity' step /usr/local/bigbluebutton/core/scripts/rap-enqueue.rb sanity "$MEETING_ID" } mark_for_republish() { MEETING_ID=$1 echo "Marking for republish $MEETING_ID" for type in $TYPES; do if [[ ! -d $BASE/process/$type/$MEETING_ID ]]; then echo "Processed files for $MEETING_ID ($type) do not exist, can't republish" echo "Try rebuilding the recording instead." continue fi # Clear out the publish done files rm -vf "$STATUS"/published/"$MEETING_ID"* # Remove the existing 'published' recording files rm -rf "${PUBLISHED_DIR:?}"/"$type"/"$MEETING_ID" rm -rf "$RAW_PRESENTATION_SRC"/unpublished/"$type"/"$MEETING_ID" rm -rf "$RAW_PRESENTATION_SRC"/deleted/"$type"/"$MEETING_ID" # Restart processing at the 'publish' step /usr/local/bigbluebutton/core/scripts/rap-enqueue.rb "publish:$type" "$MEETING_ID" done } need_root() { if [ $EUID != 0 ]; then echo "Need to be root to run this option" exit 1 fi } need_root_or_bigbluebutton() { if [ $EUID != 0 ] && [ "$USER" != $BBB_USER ]; then echo "Need to be user root or bigbluebutton to run this option" exit 1 fi } print_header() { if [ ! "$HEADER" ]; then echo echo "** Potential problems described below **" HEADER=1 fi } # Checks if the passed file/directory exists, and if they are owned by BBB's user # $1: Path to directory or file # $2: -d or -f # $3: -R flag for chown check_path_owner_group() { if test "$2" "$1"; then if [ "$(stat -c "%U:%G" "$1")" != "$BBB_USER:$BBB_USER" ]; then echo "#" echo "# Warning: owner:group of $1 not $BBB_USER:$BBB_USER." if [ "$3" ]; then echo "# chown -R $BBB_USER:$BBB_USER $1" else echo "# chown $BBB_USER:$BBB_USER $1" fi echo "#" echo fi else echo "#" echo "# Warning: $1 is missing." echo "#" echo fi } usage() { echo "BigBlueButton Recording Diagnostic Utility (BigBlueButton Version $BIGBLUEBUTTON_RELEASE)" echo echo " bbb-record [options]" echo echo "Reporting:" echo " --list List all recordings" echo " --list-recent List recent recordings" echo " --list-recent --withDesc List recent recordings and show their description" echo " --list-workflows List available recording workflows" echo echo "Monitoring:" echo " --watch Watch processing of recordings" echo " --watch --withDesc Watch processing of recordings and show their description" echo echo "Administration:" echo " --rebuild rebuild the output for the given internal meetingID" echo " --rebuildall rebuild every recording" echo " --delete delete one meeting and recording" echo " --deleteall delete all meetings and recordings" echo " --debug check for recording errors" echo " --check check for configuration errors" echo " --enable enable a recording workflow" echo " --disable disable a recording workflow" echo " --tointernal get the internal meeting ids for the given external meetingId" echo " --toexternal get the external meeting id for the given internal meetingId" echo " --republish republish the recording for meetingID. (Only for Matterhorn Integration)" #echo " --rearchive [meetingId] rearchive the recording (created before a restart)" echo } if [ $# -eq 0 ]; then usage exit 1 fi # Parse the parameters while [ $# -gt 0 ]; do if [ "$1" = "-watch" ] || [ "$1" = "--watch" ]; then WATCH=1 if [ "$2" = "--withDesc" ]; then WITHDESC=1 shift fi shift continue fi if [ "$1" = "-list" ] || [ "$1" = "--list" ]; then LIST=1 shift continue fi if [ "$1" = "-list-workflows" ] || [ "$1" = "--list-workflows" ]; then LISTWORKFLOWS=1 shift continue fi if [ "$1" = "--list-recent" ]; then LIST=1 HEAD=10 if [ "$2" ]; then WITHDESC=1 shift fi shift continue fi if [ "$1" = "-rebuild" ] || [ "$1" = "--rebuild" ]; then need_root if [ ! -z "${2}" ]; then MEETING_ID="${2}" shift fi REBUILD=1 shift continue fi if [ "$1" = "-rebuildall" ] || [ "$1" = "--rebuildall" ]; then need_root if [ ! -z "${2}" ]; then MEETING_ID="${2}" shift fi REBUILDALL=1 shift continue fi if [ "$1" = "-republish" ] || [ "$1" = "--republish" ]; then need_root if [ ! -z "${2}" ]; then MEETING_ID="${2}" shift fi REPUBLISH=1 shift continue fi if [ "$1" = "-delete" ] || [ "$1" = "--delete" ]; then need_root_or_bigbluebutton if [ ! -z "${2}" ]; then MEETING_ID="${2}" shift fi DELETE=1 shift continue fi if [ "$1" = "-deleteall" ] || [ "$1" = "--deleteall" ]; then need_root DELETEALL=1 shift continue fi if [ "$1" = "-check" ] || [ "$1" = "--check" ]; then need_root CHECK=1 shift continue fi if [ "$1" = "-debug" ] || [ "$1" = "--debug" ]; then need_root DEBUG=1 shift continue fi if [ "$1" = "-clean" ] || [ "$1" = "--clean" ]; then need_root CLEAN=1 shift continue fi if [ "$1" = "-disable" ] || [ "$1" = "--disable" ]; then need_root if [ ! -z "${2}" ]; then WORKFLOW="${2}" shift fi DISABLE=1 shift continue fi if [ "$1" = "-enable" ] || [ "$1" = "--enable" ]; then need_root if [ ! -z "${2}" ]; then WORKFLOW="${2}" shift fi ENABLE=1 shift continue fi if [ "$1" = "-toexternal" ] || [ "$1" = "--toexternal" ]; then need_root if [ ! -z "${2}" ]; then INTERNAL_MEETINGID="${2}" shift fi TOEXTERNAL=1 shift continue fi if [ "$1" = "-tointernal" ] || [ "$1" = "--tointernal" ]; then need_root if [ ! -z "${2}" ]; then EXTERNAL_MEETINGID="${2}" shift fi TOINTERNAL=1 shift continue fi usage exit 1 done if [ $REBUILD ]; then if [ -z "$MEETING_ID" ]; then echo "Pass an internal meeting id as parameter." else mark_for_rebuild "$MEETING_ID" fi fi if [ $REBUILDALL ]; then echo "Rebuilding all recordings" for recording in $(dir "$BASE"/raw); do [[ ! -e $STATUS/archived/$recording.norecord ]] && mark_for_rebuild "$recording" done fi if [ $REPUBLISH ]; then if [ -z "$MEETING_ID" ]; then # # Republish all meetings # for recording in $(dir "$BASE"/raw); do echo "Marking for republish: $recording" mark_for_republish "$recording" done else echo "Marking for republish: $MEETING_ID" mark_for_republish "$MEETING_ID" fi fi if [ $CLEAN ]; then sudo /etc/init.d/bbb-record-core stop for type in $TYPES; do echo " clearning logs in $LOG_DIR/$type" find "$LOG_DIR"/"$type" -name "*.log" -exec sudo rm '{}' \; done sudo /etc/init.d/bbb-record-core start fi if [ $DELETE ]; then if [[ -z $MEETING_ID ]]; then echo "No meeting id given" exit 1 fi echo "deleting: $MEETING_ID" # Remove the status files first to avoid issues with concurrent # recording processing rm -f "$STATUS"/ended/"$MEETING_ID"* rm -f "$STATUS"/recorded/"$MEETING_ID"* rm -f "$STATUS"/archived/"$MEETING_ID"* rm -f "$STATUS"/sanity/"$MEETING_ID"* rm -f "$STATUS"/processed/"$MEETING_ID"* rm -f "$STATUS"/published/"$MEETING_ID"* # Remove all of the related files for type in $TYPES; do rm -rf "${PUBLISHED_DIR:?}"/"$type"/"$MEETING_ID"* rm -rf "$RAW_PRESENTATION_SRC"/unpublished/"$type"/"$MEETING_ID"* rm -rf "$RAW_PRESENTATION_SRC"/deleted/"$type"/"$MEETING_ID"* rm -rf "$RECORDING_DIR"/process/"$type"/"$MEETING_ID"* rm -rf "$RECORDING_DIR"/publish/"$type"/"$MEETING_ID"* rm -rf "${LOG_DIR:?}"/"$type"/*"$MEETING_ID"* done rm -rf "$RAW_PRESENTATION_SRC"/captions/"$MEETING_ID"* rm -f "$RAW_PRESENTATION_SRC"/inbox/"$MEETING_ID"*.json rm -f "$RAW_PRESENTATION_SRC"/inbox/"$MEETING_ID"*.txt rm -rf "$RECORDING_DIR"/raw/"$MEETING_ID"* rm -f "$RAW_PRESENTATION_SRC"/screenshare/"$MEETING_ID"*.flv rm -f "$RAW_AUDIO_SRC"/"$MEETING_ID"*.wav rm -f "$RAW_AUDIO_SRC"/"$MEETING_ID"*.opus rm -rf "${RAW_PRESENTATION_SRC:?}"/"$MEETING_ID" fi if [ $DELETEALL ]; then # Remove the status files first to avoid issues with concurrent # recording processing rm -f "$STATUS"/recorded/* rm -f "$STATUS"/archived/* rm -f "$STATUS"/sanity/* rm -f "$STATUS"/processed/* rm -f "$STATUS"/published/* for type in $TYPES; do rm -rf "${PUBLISHED_DIR:?}"/"$type"/* rm -rf "$RAW_PRESENTATION_SRC"/unpublished/"$type"/* rm -rf "$RAW_PRESENTATION_SRC"/deleted/"$type"/* rm -rf "$RECORDING_DIR"/process/"$type"/* rm -rf "$RECORDING_DIR"/publish/"$type"/* rm -rf "${LOG_DIR:?}"/"$type"/* done rm -rf "$RECORDING_DIR"/raw/* rm -f "$RAW_PRESENTATION_SRC"/captions/inbox/* rm -f "$RAW_PRESENTATION_SRC"/screenshare/*.flv rm -f "$RAW_AUDIO_SRC"/*.wav rm -f "$RAW_AUDIO_SRC"/*.opus for meeting in $(ls "$RAW_PRESENTATION_SRC" | grep "$MEETING_PATTERN"); do echo "deleting: $meeting" rm -rf "${RAW_PRESENTATION_SRC:?}"/"$meeting" rm -rf "$RAW_PRESENTATION_SRC"/captions/"$meeting" done fi if [ $LIST ]; then # Does the meeting contain: # A -- Audio # P -- Presentation # V -- Video # D -- Desktop # # Does the archive contain # A -- Audio # P -- Presentation # V -- Video # D -- Desktop # E -- Events # # Is there a done flag (trigger rap-worker.rb to process) for # R -- Recording # A -- Archiving # if [ $WITHDESC ]; then echo "Internal MeetingID Time APVD APVDE RAS Slides Processed Published External MeetingID Description" echo "------------------------------------------------------ ---------------------------- ---- ----- --- ------ -------------------- ------------------ ------------------- -----------" else echo "Internal MeetingID Time APVD APVDE RAS Slides Processed Published External MeetingID" echo "------------------------------------------------------ ---------------------------- ---- ----- --- ------ -------------------- ------------------ -------------------" fi if [ -z $HEAD ]; then # If we're not called with --list-recent, show all recordings HEAD=99999 fi tmp_file=$(mktemp) ls -t "$RAW_PRESENTATION_SRC" | grep "$MEETING_PATTERN" -m $HEAD > "$tmp_file" ls -t "$RECORDING_DIR"/raw | grep "$MEETING_PATTERN" -m $HEAD >> "$tmp_file" #for meeting in $(ls -t $RAW_PRESENTATION_SRC | grep $MEETING_PATTERN -m $HEAD); do for meeting in $(sort -t - -k 2 -r < "$tmp_file" | uniq); do echo -n "$meeting" timestamp=${meeting//[0-9a-f]*-/} epoc=$((timestamp/1000)) echo -n " " echo -n "$(date --date "Jan 1, 1970 00:00:00 +0000 + $epoc seconds")" | awk '{ printf("%-28s",$0) }' echo -n " " # # Monitor the live recordings # # # Check if there is any recorded audio if ls -A "$RAW_AUDIO_SRC"/"$meeting"-*.wav &> /dev/null; then echo -n "X" else echo -n " " fi # # Check if there is any uploaded presentations if [ -d "$RAW_PRESENTATION_SRC"/"$meeting"/"$meeting" ]; then if [ "$(ls -A "$RAW_PRESENTATION_SRC"/"$meeting"/"$meeting")" ]; then echo -n "X" else echo -n " " fi else echo -n " " fi # # Check if there is any recorded videos if [ -d "$RAW_VIDEO_SRC"/"$meeting" ]; then if [ "$(ls -A "$RAW_VIDEO_SRC"/"$meeting")" ]; then echo -n "X" else echo -n " " fi else echo -n " " fi #echo "## $RAW_SCREENSHARE_SRC/$meeting-*.flv" #exit # # Check if there is any recorded desktop sharing if ls -A "$RAW_SCREENSHARE_SRC"/"$meeting"/*.flv &> /dev/null; then echo -n "X" else echo -n " " fi # # Monitor the archived files # RAW_DIR=$RAW_PRESENTATION_SRC/recording/raw/$meeting echo -n " " # Check if there area uploaded presentations #echo "$RAW/audio" DIRS="audio presentation video deskshare" for dir in $DIRS; do if [ -d "$RAW_DIR"/"$dir" ]; then if [ "$(ls -A "$RAW_DIR"/"$dir")" ]; then echo -n "X" else echo -n " " fi else echo -n " " fi done if [ -f "$RAW_DIR"/events.xml ]; then echo -n "X" else echo -n " " fi # # Check the status files # echo -n " " DIRS="recorded archived sanity" for dir in $DIRS; do if [ -f "$STATUS"/"$dir"/"$meeting".done ]; then echo -n "X" else echo -n " " fi done # # Number of slides if [ -d "$RAW_PRESENTATION_SRC"/"$meeting"/"$meeting" ]; then SLIDES_COUNT=$(find "$RAW_PRESENTATION_SRC"/"$meeting"/"$meeting" -name "*.swf" | wc -l) if [ "$SLIDES_COUNT" -eq 0 ]; then SLIDES_COUNT=$(find "$RAW_PRESENTATION_SRC"/"$meeting"/"$meeting" -name "*.svg" | wc -l) fi printf "%7s" "$SLIDES_COUNT" else SLIDES_COUNT=$(find "$RECORDING_DIR"/raw/"$meeting" -name "*.swf" | wc -l) if [ "$SLIDES_COUNT" -eq 0 ]; then SLIDES_COUNT=$(find "$RECORDING_DIR"/raw/"$meeting" -name "*.svg" | wc -l) fi printf "%7s" "$SLIDES_COUNT" fi echo -n " " #echo $BASE/raw/$meeting if [ -d "$BASE"/raw/"$meeting" ]; then recording=$meeting # # Check processed processed="" for type in $TYPES; do if [ -f "$STATUS"/processed/"$recording"-"$type".done ]; then if [ ! -z "$processed" ]; then processed="$processed," fi processed="$processed$type" fi done printf "%-21s" "$processed" # # Check archived published="" for type in $TYPES; do if [ -f "$PUBLISHED_DIR"/"$type"/"$recording"/metadata.xml ]; then if [ ! -z "$published" ]; then published="$published," fi published="$published$type" fi done printf "%-17s" "$published" if [ -f "$RECORDING_DIR"/raw/"$recording"/events.xml ]; then echo -n " " echo -n "$(head -n 5 "$RECORDING_DIR"/raw/"$recording"/events.xml | grep meetingId | sed s/.*meetingId=\"//g | sed s/\".*//g)" | sed -e 's/<[^>]*>//g' -e 's/<//g' -e 's/&/\&/g' -e 's/ \{1,\}/ /g' | tr -d '\n' if [ $WITHDESC ]; then echo -n " " echo -n "$(head -n 5 "$RECORDING_DIR"/raw/"$recording"/events.xml | grep description | sed s/.*description=\"//g | sed s/\".*//g)" | sed -e 's/<[^>]*>//g' -e 's/<//g' -e 's/&/\&/g' -e 's/ \{1,\}/ /g' | tr -d '\n' fi fi fi echo done if [ -f "$tmp_file" ]; then rm "$tmp_file" fi echo echo "--" systemctl --all --no-pager list-timers bbb-record-core.timer echo "--" systemctl --no-pager status bbb-rap-starter.service bbb-rap-resque-worker.service echo "--" if tail -n 20 "$LOG_DIR"/bbb-web.log | grep -q "is recorded. Process it."; then echo -n "Last meeting processed (bbb-web.log): " tail -n 20 "$LOG_DIR"/bbb-web.log | grep "is recorded. Process it." | sed "s/.*\[//g" | sed "s/\].*//g" fi fi if [ $WATCH ]; then watch -n 2 "bbb-record --list-recent $WITHDESC" fi if [ $ENABLE ]; then SCRIPTS_DIR=/usr/local/bigbluebutton/core/scripts PROCESS_SCRIPT=$SCRIPTS_DIR/process/$WORKFLOW PUBLISH_SCRIPT=$SCRIPTS_DIR/publish/$WORKFLOW if [ -f "$PROCESS_SCRIPT".rb.bk ]; then echo "Enabling process script in workflow '$WORKFLOW'" mv "$PROCESS_SCRIPT".rb.bk "$PROCESS_SCRIPT".rb echo "Enabling publish script in workflow '$WORKFLOW'" mv "$PUBLISH_SCRIPT".rb.bk "$PUBLISH_SCRIPT".rb elif [ -f "$PROCESS_SCRIPT".rb ]; then echo "Workflow '$WORKFLOW' is already enabled." else echo "Workflow '$WORKFLOW' does not exist or is not installed" fi fi if [ $DISABLE ]; then SCRIPTS_DIR=/usr/local/bigbluebutton/core/scripts PROCESS_SCRIPT=$SCRIPTS_DIR/process/$WORKFLOW PUBLISH_SCRIPT=$SCRIPTS_DIR/publish/$WORKFLOW if [ -f "$PROCESS_SCRIPT".rb ]; then echo "Disabling process script in workflow '$WORKFLOW'" mv "$PROCESS_SCRIPT".rb "$PROCESS_SCRIPT".rb.bk echo "Disabling publish script in workflow '$WORKFLOW'" mv "$PUBLISH_SCRIPT".rb "$PUBLISH_SCRIPT".rb.bk elif [ -f "$PROCESS_SCRIPT".rb.bk ]; then echo "Workflow '$WORKFLOW' is already disabled." else echo "Workflow '$WORKFLOW' does not exist or is not installed" fi fi if [ $TOEXTERNAL ]; then echo echo "External meeting id related to the given internal meeting id:" echo "-------------------------------------------------------------" expr "$(grep meetingId "$RECORDING_DIR"/raw/"$INTERNAL_MEETINGID"/events.xml 2> /dev/null)" : '.*meetingId="\(.*\)"' echo "-------------------------------------------------------------" echo fi if [ $TOINTERNAL ]; then echo echo "Internal meeting ids related to the given external meeting id:" echo "-------------------------------------------------------------" grep "meetingId=\"$EXTERNAL_MEETINGID\"" "$RECORDING_DIR"/raw/*/events.xml | cut -f6 -d'/' echo "-------------------------------------------------------------" echo fi #if [ $REARCHIVE ]; then # ARCHIVE_DONE_FILE=$STATUS/archived/$MEETING_ID.done # SANITY_FAIL_FILE=$STATUS/sanity/$MEETING_ID.fail # if [ -f $SANITY_FAIL_FILE ]; then # max_days=$(expr "$(grep history= /etc/cron.daily/bigbluebutton)" : 'history=\(.*\)') # # The recording has not been removed. # still_exists=$(find $STATUS/recorded/*.done -mtime -$max_days | grep $MEETING_ID) # if [ -n "$still_exists" ]; then # if [ -f $ARCHIVE_DONE_FILE ]; then # echo "Removing archived .done file, sanity .fail fail, and raw directory for meeting $MEETING_ID" # rm $ARCHIVE_DONE_FILE # rm -r $RECORDING_DIR/raw/$MEETING_ID # rm $SANITY_FAIL_FILE # else # echo "$MEETING_ID is not archived." # fi # fi # else # echo "The meeting you want to re archive has not failed in sanity check." # fi #fi if [ $LISTWORKFLOWS ]; then echo echo "# Enabled recording processing steps:" echo "#" prev_workflow="" for workflow in $(get_yml_value steps); do # Remove trailing : if present workflow=$(sed "s/:$//" <<< $workflow) if [ "$prev_workflow" != "$workflow" ]; then echo "# $workflow" fi prev_workflow=$workflow done echo "#" echo "# Available processing scripts: " echo "#" for type in $TYPES; do echo "# $type" done echo fi if [ $CHECK ]; then print_header echo if [ -d "$RECORDING_DIR"/process/slides ]; then if [ ! -w "$RECORDING_DIR"/process/slides ]; then echo "# Error: The output directory for slides" echo "#" echo "# $RECORDING_DIR/process/slides" echo "#" echo "# is not writeable." echo fi fi if [ "$PLAYBACK_PROTOCOL" != "https" ]; then echo "#" echo "# Info: playback protocol set to $PLAYBACK_PROTOCOL instead of https" echo "#" echo fi if [ -d "$LOG_DIR" ]; then if [ "$(stat -c %a "$LOG_DIR")" != "755" ]; then echo "#" echo "# Warning: access rights of BigBlueButton's log directory should be set to rwxr-xr-x, not $(stat -c %A "$LOG_DIR"):" echo "# chmod 755 $LOG_DIR" echo "#" echo fi check_path_owner_group "$LOG_DIR" "-d" "-R" check_path_owner_group "$LOG_DIR/bbb-rap-worker.log" "-f" check_path_owner_group "$LOG_DIR/sanity.log" "-f" check_path_owner_group "$LOG_DIR/post_process.log" "-f" check_path_owner_group "$LOG_DIR/post_publish.log" "-f" check_path_owner_group "$LOG_DIR/bbb-recording-cleanup.log" "-f" else echo "# Error: Recording log directory $LOG_DIR is missing." echo fi check_path_owner_group "$RECORDING_DIR" "-d" "-R" check_path_owner_group "$RECORDING_DIR/raw" "-d" "-R" check_path_owner_group "$RECORDING_DIR/process" "-d" "-R" check_path_owner_group "$RECORDING_DIR/publish" "-d" "-R" check_path_owner_group "$STATUS" "-d" "-R" check_path_owner_group "$STATUS/recorded" "-d" "-R" check_path_owner_group "$STATUS/archived" "-d" "-R" check_path_owner_group "$STATUS/processed" "-d" "-R" check_path_owner_group "$STATUS/sanity" "-d" "-R" check_path_owner_group "$STATUS/published" "-d" "-R" check_path_owner_group "$RAW_PRESENTATION_SRC" "-d" "-R" check_path_owner_group "$RAW_PRESENTATION_SRC/captions" "-d" "-R" check_path_owner_group "$RAW_PRESENTATION_SRC/events" "-d" check_path_owner_group "$PUBLISHED_DIR" "-d" check_path_owner_group "$RAW_PRESENTATION_SRC/deleted" "-d" check_path_owner_group "$RAW_PRESENTATION_SRC/unpublished" "-d" check_path_owner_group "$RAW_PRESENTATION_SRC/basic_stats" "-d" for type in $TYPES; do check_path_owner_group "$LOG_DIR/$type" "-d" "-R" if [ "$(find "$LOG_DIR"/"$type" \! -user $BBB_USER \! -group $BBB_USER | wc -l)" -gt 0 ]; then echo "#" echo "# Some recording log files in $LOG_DIR/$type may not be writeable." echo "# Consider running 'chown -hR $BBB_USER:$BBB_USER $LOG_DIR/$type'" echo "# if recording processing is not automatically starting." echo "#" echo fi done fi if [ $DEBUG ]; then if [ -f "$LOG_DIR"/bbb-rap-worker.log ]; then grep -i error "$LOG_DIR"/bbb-rap-worker.* fi # #Failures while archiving files # if [ -f "$LOG_DIR"/archive.log ]; then grep "Failed to" "$LOG_DIR/archive.log" > /tmp/t if [ -s /tmp/t ]; then echo " -- ERRORS found while archiving files -- " cat /tmp/t echo grep "on ASCII" /tmp/t > /tmp/u if [ -s /tmp/u ]; then echo " -- events.xml was not created. There is a problem with the character encoding " echo fi fi fi # # We're going to look through the output files for each of the processed types # STAGES="process publish" for type in $TYPES; do for stage in $STAGES; do LOC=$LOG_DIR/$type/$stage if ls -A "$LOC"-* &> /dev/null; then rm -rf /tmp/t grep -B 3 "ERROR -- : Error:" "$LOC"-* | grep -E -w 'Error:' | grep -v "ffmpeg version" > /tmp/t if [ -s /tmp/t ]; then echo " -- ERRORS found while processing slides $LOC-* -- " cat /tmp/t echo fi fi done done # # Additional checks for record and playback # rm -rf /tmp/t if ls "$LOG_DIR"/slides-process-* > /dev/null 2>&1; then sudo grep -i Error "$LOG_DIR"/slides-process-* | sudo tee /tmp/t if [ -s /tmp/t ]; then echo " -- Ingest and Processing errors found in $LOG_DIR/slides-process-*.log -- " cat /tmp/t echo fi fi rm -rf /tmp/t if ls "$LOG_DIR"/slides-publish-* > /dev/null 2>&1; then sudo grep -i Error "$LOG_DIR"/slides-publish-* | sudo tee /tmp/t if [ -s /tmp/t ]; then echo " -- Ingest and Processing errors found in $LOG_DIR/slides-publish-*.log -- " cat /tmp/t echo fi fi rm -rf /tmp/t if ls "$LOG_DIR"/slides-process-* > /dev/null 2>&1; then for file in $LOG_DIR/slides-process-*; do if [ ! -f "${file//process/publish}" ]; then echo " $file" >> /tmp/t fi done if [ -s /tmp/t ]; then echo " -- Ingest and Processing: found process file but not publish -- " cat /tmp/t echo fi fi rm -rf /tmp/t if ls "$STATUS"/recorded/*.done > /dev/null 2>&1; then for file in $STATUS/recorded/*.done; do if [ ! -f "${file//recorded/archived}" ]; then echo " $file" >> /tmp/t fi done if [ -s /tmp/t ]; then echo " -- Ingest and Processing: found recorded meeting but no archive files-- " cat /tmp/t echo fi fi exit 0 fi