This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
fuss:bash [2021/02/04 23:57] – office | fuss:bash [2023/10/15 10:16] (current) – [Publishing Incoming TCP Connections to MQTT Broker] office | ||
---|---|---|---|
Line 146: | Line 146: | ||
listFiles FILES DIR_PATH TYPES | listFiles FILES DIR_PATH TYPES | ||
</ | </ | ||
+ | |||
+ | ====== Recursively Convert Video Files ====== | ||
+ | |||
+ | As the title would imply, the following script will recursively convert video files to conform to the following parameters: | ||
+ | |||
+ | * MPEG-4 | ||
+ | * 720p or less, | ||
+ | * AVC (H.264), | ||
+ | * AAC | ||
+ | |||
+ | Its main design was meant to convert recorded TV shows where a set quality should not necessarily exceed the mentioned parameters for the sake of storage conservation. | ||
+ | |||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | ########################################################################### | ||
+ | ## Copyright (C) Wizardry and Steamworks 2021 - License: GNU GPLv3 ## | ||
+ | ########################################################################### | ||
+ | # The script is a way of converting all video files recursively in a # | ||
+ | # directory tree in order to conform to the following parameters: | ||
+ | # * MPEG-4 (MP4) # | ||
+ | # * 480p or less # | ||
+ | # * AVC (H.264) | ||
+ | # * AAC # | ||
+ | # # | ||
+ | # Notes: | ||
+ | # * There are some added optimizations such as switching to just # | ||
+ | # converting to MPEG-4 in case no more than a container change is # | ||
+ | # necessary | ||
+ | # * This is a long-running script and best ran within a detachable | ||
+ | # terminal such as tmux or screen. | ||
+ | # * This is a bash script that will not run on other shells. | ||
+ | ########################################################################### | ||
+ | |||
+ | ########################################################################### | ||
+ | ## CONFIGURATION | ||
+ | ########################################################################### | ||
+ | |||
+ | # The path to the ffmpeg binary. | ||
+ | FFMPEG='/ | ||
+ | # The ffmpeg flags to use when converting. | ||
+ | # veryfast vs. veryslow https:// | ||
+ | FFMPEG_OPTIONS=`tr -d ' | ||
+ | -c:v libx264 \ | ||
+ | -crf 23 \ | ||
+ | -level 3.1 \ | ||
+ | -preset veryfast \ | ||
+ | -tune film \ | ||
+ | -sws_flags lanczos \ | ||
+ | -sn \ | ||
+ | -c:a libfdk_aac \ | ||
+ | -vbr 5 \ | ||
+ | -q:a 2 \ | ||
+ | -ac 2 \ | ||
+ | -b:a 128k \ | ||
+ | -c:s mov_text \ | ||
+ | -map 0:v:0 \ | ||
+ | -map 0:a:0 \ | ||
+ | -map_metadata -1 \ | ||
+ | -movflags +faststart \ | ||
+ | -strict -2 | ||
+ | EOF` | ||
+ | # The maximal height of the video files. | ||
+ | FFMPEG_HEIGHT=480 | ||
+ | # The maximal integral CPU percentage that will be allowed to be used. | ||
+ | FFMPEG_CPU=600 | ||
+ | # The file types to convert. | ||
+ | TYPES=(mp4 mkv avi) | ||
+ | |||
+ | ########################################################################### | ||
+ | ## INTERNALS | ||
+ | ########################################################################### | ||
+ | |||
+ | if [ -z " | ||
+ | echo " | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | DIR_PATH=" | ||
+ | |||
+ | # By: https:// | ||
+ | listFiles() { | ||
+ | local -n _OUTPUT_=" | ||
+ | local -n _DIRECTORY_=" | ||
+ | local -n _TYPES_=" | ||
+ | local _FILTER_ | ||
+ | |||
+ | _FILTER_=" | ||
+ | _FILTER_=" | ||
+ | while read -d $' | ||
+ | _OUTPUT_+=( " | ||
+ | done < <( find " | ||
+ | } | ||
+ | |||
+ | TEMP_FILE="" | ||
+ | |||
+ | # Cleanup on file termination. | ||
+ | trap '{ | ||
+ | rm -rf " | ||
+ | exit 0 | ||
+ | }' KILL QUIT TERM EXIT INT HUP | ||
+ | |||
+ | # Iterate over all matching files. | ||
+ | FILES=() | ||
+ | listFiles FILES DIR_PATH TYPES | ||
+ | for FILE in " | ||
+ | FILE_NAME=`basename " | ||
+ | DIR_NAME=`dirname " | ||
+ | FILE_EXTENSION=`echo " | ||
+ | TEMP_FILE="/ | ||
+ | INFO=`mediainfo " | ||
+ | HAS_AVC=`echo " | ||
+ | HAS_AAC=`echo " | ||
+ | HAS_MP4=`echo " | ||
+ | HAS_2CH=`echo " | ||
+ | HAS_TXT=`mediainfo $FILE | grep " | ||
+ | HEIGHT=`mediainfo --Inform=" | ||
+ | | ||
+ | # If all criteria matches then proceed to the next file. | ||
+ | if [[ $HEIGHT -le $FFMPEG_HEIGHT ]] && \ | ||
+ | [[ ! -z $HAS_AVC ]] && \ | ||
+ | [[ ! -z $HAS_AAC ]] && \ | ||
+ | [[ ! -z $HAS_MP4 ]] && \ | ||
+ | [[ ! -z $HAS_2CH ]] && \ | ||
+ | [[ -z $HAS_TXT ]] | ||
+ | then | ||
+ | echo " | ||
+ | continue | ||
+ | fi | ||
+ | |||
+ | FFMPEG_ACTION=$FFMPEG_OPTIONS | ||
+ | # Resize down to $FFMPEG_HEIGHT or less depending on the height of the file. | ||
+ | if [[ $HEIGHT -gt $FFMPEG_HEIGHT ]]; then | ||
+ | FFMPEG_SIZE=" | ||
+ | fi | ||
+ | | ||
+ | # Start the conversion. | ||
+ | echo -n " | ||
+ | # -loglevel quiet | ||
+ | " | ||
+ | FFMPEG_PID=$! | ||
+ | cpulimit -q -z -e ffmpeg -l $FFMPEG_CPU >/ | ||
+ | T1=`date +%s` | ||
+ | wait $FFMPEG_PID | ||
+ | T2=`date +%s` | ||
+ | RUNTIME=$(( T2 - T1 )) | ||
+ | T_H=$((RUNTIME / 3600)) | ||
+ | T_M=$((RUNTIME % 3600 / 60 )) | ||
+ | T_S=$(((RUNTIME % 3600) % 60 )) | ||
+ | if [[ " | ||
+ | echo "Done ($T_H: | ||
+ | # Permute the files on successful conversion. | ||
+ | rm " | ||
+ | cp " | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo " | ||
+ | continue | ||
+ | fi | ||
+ | rm " | ||
+ | else | ||
+ | echo " | ||
+ | fi | ||
+ | done | ||
+ | |||
+ | </ | ||
+ | |||
+ | ====== Netstat without Netstat ====== | ||
+ | |||
+ | The following code allows a user to print out a list of established connections without having to resort to using the command-line tool '' | ||
+ | |||
+ | <code bash> | ||
+ | # | ||
+ | ########################################################################### | ||
+ | ## Copyright (C) Wizardry and Steamworks 2022 - License: GNU GPLv3 ## | ||
+ | ## Please see: http:// | ||
+ | ## rights of fair usage, the disclaimer and warranty conditions. | ||
+ | ########################################################################### | ||
+ | # # | ||
+ | # This script processes the TCP connections from / | ||
+ | # output a list of locally listening TCP IP addresses and ports (sockets) # | ||
+ | # mapped to a list of remotely connecting TCP IP addresses and ports. | ||
+ | # # | ||
+ | # The script is written with a minimalistic environment in mind with just # | ||
+ | # a few tools available that should be present within most busyboxes. | ||
+ | # # | ||
+ | # For best results, disable IPv6 on the executing machine (via the kernel # | ||
+ | # command line) because some TCP connections are processed through IPv6 # | ||
+ | # even if they are IPv4 such that / | ||
+ | # # | ||
+ | ########################################################################### | ||
+ | |||
+ | decode () { | ||
+ | DUO=$1 | ||
+ | LEN=`echo -n $DUO | wc -c` | ||
+ | OUT="" | ||
+ | for X in `seq 0 2 $(($LEN-2))`; | ||
+ | OUT=$((16# | ||
+ | done | ||
+ | OUT=${OUT:: | ||
+ | echo $OUT | ||
+ | } | ||
+ | |||
+ | tcp_state() { | ||
+ | OUT="" | ||
+ | for SET in $1; do | ||
+ | IP_HEX=`echo $SET | awk -F':' | ||
+ | PO_HEX=`echo $SET | awk -F':' | ||
+ | IP=`decode $IP_HEX` | ||
+ | PO=$((16# | ||
+ | OUT=$OUT" | ||
+ | done | ||
+ | echo $OUT | ||
+ | } | ||
+ | |||
+ | TMP_STATE=/ | ||
+ | trap '{ rm -rf $TMP_STATE; }' KILL QUIT TERM EXIT INT HUP | ||
+ | cat / | ||
+ | |||
+ | TCP_STATE_LEN=`cat $TMP_STATE | wc -l` | ||
+ | LISTEN_LOCAL=`cat $TMP_STATE | \ | ||
+ | awk 'NR==1 { for (i=1; | ||
+ | tail +2` | ||
+ | REMOTE_ADDRS=`cat $TMP_STATE | \ | ||
+ | awk 'NR==1 { for (i=1; | ||
+ | tail +2` | ||
+ | |||
+ | LISTEN=`tcp_state " | ||
+ | REMOTE=`tcp_state " | ||
+ | |||
+ | for I in `seq 1 1 $(($TCP_STATE_LEN-1))`; | ||
+ | A=`echo $LISTEN | awk -v var=$I '{ print $var }'` | ||
+ | B=`echo $REMOTE | awk -v var=$I '{ print $var }'` | ||
+ | echo $A" - "$B | ||
+ | done | ||
+ | |||
+ | </ | ||
+ | |||
+ | ====== Publishing Incoming TCP Connections to MQTT Broker ====== | ||
+ | |||
+ | The following script is meant to run in the background and poll ''/ | ||
+ | |||
+ | < | ||
+ | server -> FQDN hostname of the machine that the script is running on, | ||
+ | this -> the listening IP address followed by the port separated by a colon | ||
+ | that -> the connecting IP address followed by the port separated by a colon | ||
+ | </ | ||
+ | |||
+ | <code bash> | ||
+ | # | ||
+ | ########################################################################### | ||
+ | ## Copyright (C) Wizardry and Steamworks 2022 - License: GNU GPLv3 ## | ||
+ | ## Please see: http:// | ||
+ | ## rights of fair usage, the disclaimer and warranty conditions. | ||
+ | ########################################################################### | ||
+ | # # | ||
+ | # This script publishes the state of TCP connections to the machine over # | ||
+ | # a specified port to an MQTT broker. The script leverages polling | ||
+ | # / | ||
+ | # just the most basic commands making it suitable for various cases. | ||
+ | # # | ||
+ | ########################################################################### | ||
+ | |||
+ | ########################################################################### | ||
+ | # | ||
+ | ########################################################################### | ||
+ | |||
+ | # path to the mosquitto publishing tool | ||
+ | MOSQUITTO_PUBLISHER=/ | ||
+ | # the host name of the MQTT broker | ||
+ | MOSQUITTO_HOST=iot.internal | ||
+ | # the MQTT topic to publish on | ||
+ | MOSQUITTO_TOPIC=arcade | ||
+ | # the TCP port to monitor for connections | ||
+ | MONITOR_PORT=55435 | ||
+ | |||
+ | # the time to sleep between polling | ||
+ | SLEEP_TIME=1 | ||
+ | |||
+ | ########################################################################### | ||
+ | # | ||
+ | ########################################################################### | ||
+ | |||
+ | decode () { | ||
+ | DUO=$1 | ||
+ | LEN=`echo -n $DUO | wc -c` | ||
+ | OUT="" | ||
+ | for X in `seq 0 2 $(($LEN-2))`; | ||
+ | OUT=$((16# | ||
+ | done | ||
+ | OUT=${OUT:: | ||
+ | echo $OUT | ||
+ | } | ||
+ | |||
+ | tcp_state() { | ||
+ | OUT="" | ||
+ | for SET in $1; do | ||
+ | IP_HEX=`echo $SET | awk -F':' | ||
+ | PO_HEX=`echo $SET | awk -F':' | ||
+ | IP=`decode $IP_HEX` | ||
+ | PO=$((16# | ||
+ | OUT=$OUT" | ||
+ | done | ||
+ | echo $OUT | ||
+ | } | ||
+ | |||
+ | |||
+ | TMP_STATE=/ | ||
+ | RUN=1 | ||
+ | trap '{ rm -rf $TMP_STATE; RUN=0; }' KILL QUIT TERM EXIT INT HUP SIGUSR1 | ||
+ | |||
+ | while [ $RUN -ne 0 ]; do | ||
+ | cat / | ||
+ | TCP_STATE_LEN=`cat $TMP_STATE | wc -l` | ||
+ | LISTEN_LOCAL=`cat $TMP_STATE | \ | ||
+ | awk 'NR==1 { for (i=1; | ||
+ | tail +2` | ||
+ | REMOTE_ADDRS=`cat $TMP_STATE | \ | ||
+ | awk 'NR==1 { for (i=1; | ||
+ | tail +2` | ||
+ | |||
+ | LISTEN=`tcp_state " | ||
+ | REMOTE=`tcp_state " | ||
+ | |||
+ | for I in `seq 1 1 $(($TCP_STATE_LEN-1))`; | ||
+ | X=`echo $LISTEN | awk -v var=$I '{ print $var }'` | ||
+ | Y=`echo $REMOTE | awk -v var=$I '{ print $var }'` | ||
+ | NETPLAY=`echo $X $Y | grep $MONITOR_PORT | grep -v 0.0.0.0` | ||
+ | if [ ! -z " | ||
+ | THIS=`echo $NETPLAY | awk '{ print $1 }'` | ||
+ | THAT=`echo $NETPLAY | awk '{ print $2 }'` | ||
+ | | ||
+ | $MOSQUITTO_PUBLISHER \ | ||
+ | -h $MOSQUITTO_HOST \ | ||
+ | -t $MOSQUITTO_TOPIC \ | ||
+ | -m "{ \" | ||
+ | fi | ||
+ | done | ||
+ | sleep $SLEEP_TIME | ||
+ | done | ||
+ | |||
+ | </ | ||
+ | |||
+ | ====== Text Activity Spinners in Bash ====== | ||
+ | |||
+ | In order to use the [[/ | ||
+ | |||
+ | <code bash> | ||
+ | # | ||
+ | |||
+ | ASCII_SPINNER=( " | ||
+ | while [ 1 = 1 ]; do | ||
+ | CAR=" | ||
+ | CDR=(" | ||
+ | ASCII_SPINNER=(${CDR[@]} ${CAR}) | ||
+ | echo -n -e " | ||
+ | done | ||
+ | |||
+ | </ | ||
+ | |||
+ | The logic is pretty straight-forward: | ||
+ | * the spinner is loaded as a bash array, | ||
+ | * the array is shuffled by shifting the first element, keeping a copy it and then adding the first element to the end of the spinner array, | ||
+ | * the first element is printed out, without any newlines and by prepending a carriage-return '' | ||
+ | |||
+ | |||
+ | |||