improve planefence web table

This commit is contained in:
kx1t
2025-01-22 16:33:54 -05:00
parent 16608d0a16
commit ddc51b8494

View File

@@ -1,6 +1,6 @@
#!/command/with-contenv bash
#shellcheck shell=bash
#shellcheck disable=SC2015,SC1091,SC2005,SC2006,SC2094
#shellcheck disable=SC2015,SC1091,SC2005,SC2006,SC2094,SC2154
# PLANETWEET - a Bash shell script to send a Tweet when a plane is detected in the
# user-defined fence area.
#
@@ -35,7 +35,6 @@ source /scripts/common
[[ -z "$PLANEFENCEDIR" ]] && PLANEFENCEDIR=/usr/share/planefence
[[ -f "$PLANEFENCEDIR/planefence.conf" ]] && source "$PLANEFENCEDIR/planefence.conf"
APPNAME="$(hostname)/planefence_notify"
#
# These are the input and output directories and file names
# HEADR determines the tags for each of the fields in the Tweet:
@@ -65,59 +64,56 @@ PLANEFILE=/usr/share/planefence/persist/plane-alert-db.txt
# MINTIME is the minimum time we wait before sending a tweet
# to ensure that at least $MINTIME of audio collection (actually limited to the Planefence update runs in this period) to get a more accurste Loudness.
(( TWEET_MINTIME > 0 )) && MINTIME=$TWEET_MINTIME || MINTIME=100
((TWEET_MINTIME > 0)) && MINTIME=$TWEET_MINTIME || MINTIME=100
# $ATTRIB contains the attribution line at the bottom of the tweet
ATTRIB="${ATTRIB:-#adsb #planefence by kx1t - https://sdr-e.com/docker-planefence}"
if [ "$SOCKETCONFIG" != "" ]
then
case "$(grep "^distanceunit=" "$SOCKETCONFIG" |sed "s/distanceunit=//g")" in
nauticalmile)
if [ "$SOCKETCONFIG" != "" ]; then
case "$(grep "^distanceunit=" "$SOCKETCONFIG" | sed "s/distanceunit=//g")" in
nauticalmile)
DISTUNIT="nm"
;;
kilometer)
kilometer)
DISTUNIT="km"
;;
mile)
mile)
DISTUNIT="mi"
;;
meter)
meter)
DISTUNIT="m"
;;
esac
fi
# get ALTITUDE unit:
ALTUNIT="ft"
if [ "$SOCKETCONFIG" != "" ]
then
case "$(grep "^altitudeunit=" "$SOCKETCONFIG" |sed "s/altitudeunit=//g")" in
feet)
if [ "$SOCKETCONFIG" != "" ]; then
case "$(grep "^altitudeunit=" "$SOCKETCONFIG" | sed "s/altitudeunit=//g")" in
feet)
ALTUNIT="ft"
;;
meter)
meter)
ALTUNIT="m"
;;
esac
fi
# determine if altitude is ASL or AGL
(( ALTCORR > 0 )) && ALTPARAM="AGL" || ALTPARAM="MSL"
((ALTCORR > 0)) && ALTPARAM="AGL" || ALTPARAM="MSL"
# -----------------------------------------------------------------------------------
# -----------------------------------------------------------------------------------
#
# First create an function to write to the log
LOG ()
{ if [ "$VERBOSE" != "" ]
then
printf "%s-%s[%s]v%s: %s\n" "$(date +"%Y%m%d-%H%M%S")" "$PROCESS_NAME" "$CURRENT_PID" "$VERSION" "$1" >> $LOGFILE
fi
LOG() {
if [ "$VERBOSE" != "" ]; then
printf "%s-%s[%s]v%s: %s\n" "$(date +"%Y%m%d-%H%M%S")" "$PROCESS_NAME" "$CURRENT_PID" "$VERSION" "$1" >>$LOGFILE
fi
}
getRoute()
{
# Uses MrJackWills's API to look up flight information based on Callsign. See https://github.com/mrjackwills/adsbdb
getRoute() {
# Uses MrJackWills's API to look up flight information based on Callsign. See https://github.com/mrjackwills/adsbdb
# Usage: routeString="$(getRoute "$CallSign")"
#
# Returns a string:
@@ -125,11 +121,10 @@ getRoute()
# if only either Origin or Destination airport are known: "org: #BOS" or "dest: #JFK"
# if neither is available: empty string
#
# Prerequisites/dependencies: JQ, CURL
# Prerequisites/dependencies: JQ, CURL
# first make sure we have an argument
if [[ -z "$1" ]]
then
if [[ -z "$1" ]]; then
return
fi
@@ -137,24 +132,20 @@ getRoute()
routeObj="$(curl -sL "https://api.adsbdb.com/v0/callsign/$1")"
# Unknown Call -> return empty
if [[ "$(jq '.response' <<< "$routeObj")" == "\"unknown callsign\"" ]]
then
if [[ "$(jq '.response' <<<"$routeObj")" == "\"unknown callsign\"" ]]; then
return
fi
# Get origin/dest:
origin="$(jq '.response.flightroute.origin.iata_code' 2>/dev/null <<< "$routeObj"|tr -d '\"')"
destination="$(jq '.response.flightroute.destination.iata_code' 2>/dev/null <<< "$routeObj"|tr -d '\"')"
origin="$(jq '.response.flightroute.origin.iata_code' 2>/dev/null <<<"$routeObj" | tr -d '\"')"
destination="$(jq '.response.flightroute.destination.iata_code' 2>/dev/null <<<"$routeObj" | tr -d '\"')"
response=""
if [[ -n "$origin" ]] && [[ -n "$destination" ]]
then
if [[ -n "$origin" ]] && [[ -n "$destination" ]]; then
response="#$origin - #$destination"
elif [[ -n "$origin" ]]
then
elif [[ -n "$origin" ]]; then
response="org: #$origin"
elif [[ -n "$destination" ]]
then
elif [[ -n "$destination" ]]; then
response="dest: #$destination"
fi
@@ -162,9 +153,8 @@ getRoute()
echo "$response"
}
if [ "$1" != "" ] && [ "$1" != "reset" ]
then # $1 contains the date for which we want to run PlaneFence
TWEETDATE=$(date --date="$1" '+%y%m%d')
if [ "$1" != "" ] && [ "$1" != "reset" ]; then # $1 contains the date for which we want to run PlaneFence
TWEETDATE=$(date --date="$1" '+%y%m%d')
else
TWEETDATE=$(date --date="today" '+%y%m%d')
fi
@@ -184,51 +174,43 @@ LOG "CSVFILE=$CSVFILE"
# Get the hashtaggable headers, and figure out of there is a field with a
# custom "$tag" header
[[ -f "$PLANEFILE" ]] && IFS="," read -ra hashtag < $PLANEFILE || unset hashtag
[[ -f "$PLANEFILE" ]] && IFS="," read -ra hashtag <$PLANEFILE || unset hashtag
tagfield=""
for ((i = 0 ; i < ${#hashtag[@]} ; i++))
do
if [[ "${hashtag[i],,}" == "\$tag" ]] || [[ "${hashtag[i],,}" == "#\$tag" ]]
then
tagfield=$((i+1)) # number tagfield from 1 instead of 0 as we will use AWK to get it
break;
for ((i = 0; i < ${#hashtag[@]}; i++)); do
if [[ "${hashtag[i],,}" == "\$tag" ]] || [[ "${hashtag[i],,}" == "#\$tag" ]]; then
tagfield=$((i + 1)) # number tagfield from 1 instead of 0 as we will use AWK to get it
break
fi
done
if [ -f "$CSVFILE" ]
then
while read -r CSVLINE
do
if [ -f "$CSVFILE" ]; then
while read -r CSVLINE; do
XX=$(echo -n "$CSVLINE" | tr -d '[:cntrl:]')
CSVLINE=$XX
unset RECORD
# Read the line, but first clean it up as it appears to have a newline in it
IFS="," read -ra RECORD <<< "$CSVLINE"
IFS="," read -ra RECORD <<<"$CSVLINE"
# LOG "${#RECORD[*]} records in the current line: (${RECORD[*]})"
# $TIMEDIFF contains the difference in seconds between the current record and "now".
# We want this to be at least $MINDIFF to avoid tweeting before all noise data is captured
# $TWEET_BEHAVIOR determines if we are looking at the end time (POST -> RECORD[3]) or at the
# start time (not POST -> RECORD[2]) of the observation time
[[ "$TWEET_BEHAVIOR" == "POST" ]] && TIMEDIFF=$(( $(date +%s) - $(date -d "${RECORD[3]}" +%s) )) || TIMEDIFF=$(( $(date +%s) - $(date -d "${RECORD[2]}" +%s) ))
[[ "$TWEET_BEHAVIOR" == "POST" ]] && TIMEDIFF=$(($(date +%s) - $(date -d "${RECORD[3]}" +%s))) || TIMEDIFF=$(($(date +%s) - $(date -d "${RECORD[2]}" +%s)))
# shellcheck disable=SC2126
# shellcheck disable=SC2094
if [[ "${RECORD[1]:0:1}" != "@" ]] && [[ $TIMEDIFF -gt $MINTIME ]] && [[ ( "$(grep "${RECORD[0]},@${RECORD[1]}" "$CSVFILE" | wc -l)" == "0" ) || "$TWEETEVERY" == "true" ]]
# ^not tweeted before^ ^older than $MINTIME^ ^No previous occurrence that was tweeted^ ...or... ^$TWEETEVERY is true^
then
if [[ "${RECORD[1]:0:1}" != "@" ]] && [[ $TIMEDIFF -gt $MINTIME ]] && [[ ("$(grep "${RECORD[0]},@${RECORD[1]}" "$CSVFILE" | wc -l)" == "0") || "$TWEETEVERY" == "true" ]]; then # ^not tweeted before^ ^older than $MINTIME^ ^No previous occurrence that was tweeted^ ...or... ^$TWEETEVERY is true^
AIRLINE=$(/usr/share/planefence/airlinename.sh "${RECORD[1]#@}" "${RECORD[0]}" )
AIRLINE=$(/usr/share/planefence/airlinename.sh "${RECORD[1]#@}" "${RECORD[0]}")
AIRLINETAG="#"
if [[ "${RECORD[1]}" != "" ]]
then
if [[ "${RECORD[1]}" != "" ]]; then
AIRLINETAG+="$(echo "$AIRLINE" | tr -d '[:space:]-')"
ROUTE="$(getRoute "${RECORD[1]}")"
fi
# Create a Tweet with the first 6 fields, each of them followed by a Newline character
[[ "${hashtag[0]:0:1}" == "$" ]] && TWEET="${HEADR[0]}: #${RECORD[0]}%0A" || TWEET="${HEADR[0]}: ${RECORD[0]}%0A" # ICAO
if [[ "${RECORD[1]}" != "" ]]
then
if [[ "${RECORD[1]}" != "" ]]; then
[[ "${hashtag[1]:0:1}" == "$" ]] && TWEET+="${HEADR[1]}: #${RECORD[1]//-/}" || TWEET+="${HEADR[1]}: ${RECORD[1]}" # Flight
fi
[[ "$AIRLINETAG" != "#" ]] && TWEET+=" ${AIRLINETAG//[&\'-]/_}" || true
@@ -239,7 +221,7 @@ then
# If there is sound level data, then add a Loudness factor (peak RMS - 1 hr avg) to the tweet.
# There is more data we could tweet, but we're a bit restricted in real estate on twitter.
(( RECORD[7] < 0 )) && TWEET+="${HEADR[9]}: ${RECORD[7]} dBFS%0A${HEADR[8]}: $(( RECORD[7] - RECORD[11] )) dB%0A"
((RECORD[7] < 0)) && TWEET+="${HEADR[9]}: ${RECORD[7]} dBFS%0A${HEADR[8]}: $((RECORD[7] - RECORD[11])) dB%0A"
# figure out of there are custom tags that apply to this ICAO:
[[ "$tagfield" != "" ]] && customtag="$(awk -F "," -v field="$tagfield" -v icao="${RECORD[0]}" '$1 == icao {print $field; exit;}' "$PLANEFILE")" || customtag=""
@@ -253,15 +235,15 @@ then
TWEET="${TWEET//globe.adsbexchange.com/"$TRACKSERVICE"}"
# let's do some calcs on the actual tweet length, so we strip the minimum:
teststring="${TWEET//%0A/ }" # replace newlines with a single character
teststring="$(sed 's/https\?:\/\/[^ ]*\s/12345678901234567890123 /g' <<< "$teststring ")" # replace all URLS with 23 spaces - note the extra space after the string
tweetlength=$(( ${#teststring} - 1 ))
if (( tweetlength > 490 )); then
echo "[$(date)][$APPNAME] Warning: PF tweet length is $tweetlength > 490: tweet will be truncated!"
maxlength=$(( ${#TWEET} + 490 - tweetlength ))
teststring="${TWEET//%0A/ }" # replace newlines with a single character
teststring="$(sed 's/https\?:\/\/[^ ]*\s/12345678901234567890123 /g' <<<"$teststring ")" # replace all URLS with 23 spaces - note the extra space after the string
tweetlength=$((${#teststring} - 1))
if ((tweetlength > 490)); then
"${s6wrap[@]}" echo "Warning: PF tweet length is $tweetlength > 490: tweet will be truncated!"
maxlength=$((${#TWEET} + 490 - tweetlength))
TWEET="${TWEET:0:$maxlength}"
fi
LOG "Assessing ${RECORD[0]}: ${RECORD[1]:0:1}; diff=$TIMEDIFF secs; Tweeting... msg body: $TWEET" 1
# Before anything else, let's add the "tweeted" flag to the flight number:
@@ -275,59 +257,51 @@ then
newsnap="$(find /usr/share/planefence/persist/planepix -iname "${RECORD[0]}.jpg" -print -quit 2>/dev/null || true)"
# echo "-0- in planetweet: newsnap=\"$newsnap\" (find /usr/share/planefence/persist/planepix -iname ${RECORD[0]}.jpg -print -quit)"
if [[ "$newsnap" != "" ]]
then
if [[ "$newsnap" != "" ]]; then
GOTSNAP="true"
rm -f "$snapfile"
ln -sf "$newsnap" "$snapfile"
echo "[$(date)][$APPNAME] Using picture from $newsnap"
"${s6wrap[@]}" echo "Using picture from $newsnap"
else
link=$(awk -F "," -v icao="${RECORD[0],,}" 'tolower($1) == icao { print $2 ; exit }' /usr/share/planefence/persist/planepix.txt 2>/dev/null || true)
if [[ "$link" != "" ]] && curl -A "Mozilla/5.0 (X11; Linux x86_64; rv:97.0) Gecko/20100101 Firefox/97.0" -s -L --fail "$link" -o $snapfile --show-error 2>/dev/stdout
then
echo "[$(date)][$APPNAME] Using picture from $link"
if [[ "$link" != "" ]] && curl -A "Mozilla/5.0 (X11; Linux x86_64; rv:97.0) Gecko/20100101 Firefox/97.0" -s -L --fail "$link" -o $snapfile --show-error 2>/dev/stdout; then
"${s6wrap[@]}" echo "Using picture from $link"
GOTSNAP="true"
[[ ! -f "/usr/share/planefence/persist/planepix/${RECORD[0]}.jpg" ]] && cp "$snapfile" "/usr/share/planefence/persist/planepix/${RECORD[0]}.jpg" || true
else
[[ "$link" != "" ]] && echo "[$(date)][$APPNAME] Failed attempt to get picture from $link" || true
[[ "$link" != "" ]] && "${s6wrap[@]}" echo "Failed attempt to get picture from $link" || true
fi
fi
if [[ "$GOTSNAP" == "false" ]] && curl -s -L --fail --max-time "$SCREENSHOT_TIMEOUT" "$SCREENSHOTURL/snap/${RECORD[0]#\#}" -o "/tmp/snapshot.png"
then
"${s6wrap[@]}" echo "Getting screenshot for ${RECORD[0]}..."
if [[ "$GOTSNAP" == "false" ]] && curl -s -L --fail --max-time "$SCREENSHOT_TIMEOUT" "$SCREENSHOTURL/snap/${RECORD[0]#\#}" -o "/tmp/snapshot.png"; then
GOTSNAP="true"
echo "[$(date)][$APPNAME] Screenshot successfully retrieved at $SCREENSHOTURL for ${RECORD[0]}"
"${s6wrap[@]}" echo "Screenshot successfully retrieved at $SCREENSHOTURL for ${RECORD[0]}"
fi
[[ "$GOTSNAP" == "false" ]] && echo "[$(date)][$APPNAME] Screenshot retrieval unsuccessful at $SCREENSHOTURL for ${RECORD[0]}" || true
[[ "$GOTSNAP" == "false" ]] && "${s6wrap[@]}" echo "Screenshot retrieval unsuccessful at $SCREENSHOTURL for ${RECORD[0]}" || true
# Inject the Discord integration in here so it doesn't have to worry about state management
if [[ "${PF_DISCORD,,}" == "on" || "${PF_DISCORD,,}" == "true" ]] && [[ "x$PF_DISCORD_WEBHOOKS" != "x" ]] && [[ "x$DISCORD_FEEDER_NAME" != "x" ]]
then
if [[ "${PF_DISCORD,,}" == "on" || "${PF_DISCORD,,}" == "true" ]] && [[ "x$PF_DISCORD_WEBHOOKS" != "x" ]] && [[ "x$DISCORD_FEEDER_NAME" != "x" ]]; then
LOG "Planefence sending Discord notification"
timeout 120 python3 "$PLANEFENCEDIR"/send-discord-alert.py "$CSVLINE" "$AIRLINE"
fi
timeout 120 python3 "$PLANEFENCEDIR"/send-discord-alert.py "$CSVLINE" "$AIRLINE"
fi
# log the message we will try to tweet or toot:
if [[ -n "$MASTODON_SERVER" ]] || [ "$TWEETON" == "yes" ]
then
echo "[$(date)][$APPNAME] Attempting to tweet or toot: $(sed -e 's|\\/|/|g' -e 's|\\n| |g' -e 's|%0A| |g' <<< "${TWEET}")"
if [[ -n "$MASTODON_SERVER" ]] || [ "$TWEETON" == "yes" ]; then
"${s6wrap[@]}" echo "Attempting to tweet or toot: $(sed -e 's|\\/|/|g' -e 's|\\n| |g' -e 's|%0A| |g' <<<"${TWEET}")"
fi
# Inject Mastodon integration here:
if [[ -n "$MASTODON_SERVER" ]]
then
if [[ -n "$MASTODON_SERVER" ]]; then
mast_id="null"
MASTTEXT="$(sed -e 's|\\/|/|g' -e 's|\\n|\n|g' -e 's|%0A|\n|g' <<< "${TWEET}")"
if [[ "$GOTSNAP" == "true" ]]
then
MASTTEXT="$(sed -e 's|\\/|/|g' -e 's|\\n|\n|g' -e 's|%0A|\n|g' <<<"${TWEET}")"
if [[ "$GOTSNAP" == "true" ]]; then
# we upload an image
response="$(curl -sS -H "Authorization: Bearer ${MASTODON_ACCESS_TOKEN}" -H "Content-Type: multipart/form-data" -X POST "https://${MASTODON_SERVER}/api/v1/media" --form file="@${snapfile}")"
mast_id="$(jq '.id' <<< "$response"|xargs)"
mast_id="$(jq '.id' <<<"$response" | xargs)"
fi
# now send the message. API is different if text-only vs text+image:
if [[ "${mast_id,,}" == "null" ]]
then
if [[ "${mast_id,,}" == "null" ]]; then
# send without image
response="$(curl -H "Authorization: Bearer ${MASTODON_ACCESS_TOKEN}" -sS "https://${MASTODON_SERVER}/api/v1/statuses" -X POST -F "status=${MASTTEXT}" -F "language=eng" -F "visibility=${MASTODON_VISIBILITY}")"
else
@@ -336,12 +310,11 @@ then
fi
# check if there was an error
if [[ "$(jq '.error' <<< "$response"|xargs)" == "null" ]]
then
echo "[$(date)][$APPNAME] Planefence post to Mastodon generated successfully with visibility=${MASTODON_VISIBILITY}. Mastodon post available at: $(jq '.url' <<< "$response"|xargs)"
(( RECORD[7] < 0 )) && RECORD[12]="$(jq '.url' <<< "${response}"|xargs)" || RECORD[7]="$(jq '.url' <<< "${response}"|xargs)"
if [[ "$(jq '.error' <<<"$response" | xargs)" == "null" ]]; then
"${s6wrap[@]}" echo "Planefence post to Mastodon generated successfully with visibility=${MASTODON_VISIBILITY}. Mastodon post available at: $(jq '.url' <<<"$response" | xargs)"
LINK="$(jq '.url' <<<"${response}" | xargs)" || RECORD[7]="$(jq '.url' <<<"${response}" | xargs)"
else
echo "[$(date)][$APPNAME] Mastodon post error. Mastodon returned this error: $(jq '.url' <<< "$response"|xargs)"
"${s6wrap[@]}" echo "Mastodon post error. Mastodon returned this error: $(jq '.url' <<<"$response" | xargs)"
fi
fi
@@ -354,9 +327,11 @@ then
msg_array[flight]="${RECORD[1]#@}"
msg_array[operator]="$(echo "${AIRLINE}" | xargs)"
if [[ -n "$ROUTE" ]]; then
if [[ "${ROUTE:0:4}" == "org:" ]]; then msg_array[origin]="${ROUTE:6}"
elif [[ "${ROUTE:0:5}" == "dest:" ]]; then msg_array[destination]="${ROUTE:7}"
else
if [[ "${ROUTE:0:4}" == "org:" ]]; then
msg_array[origin]="${ROUTE:6}"
elif [[ "${ROUTE:0:5}" == "dest:" ]]; then
msg_array[destination]="${ROUTE:7}"
else
msg_array[origin]="${ROUTE:1:3}"
msg_array[destination]="${ROUTE: -3}"
fi
@@ -366,99 +341,94 @@ then
msg_array[min_alt]="${RECORD[4]} $ALTUNIT $ALTPARAM"
msg_array[min_dist]="${RECORD[5]} $DISTUNIT"
msg_array[link]="${RECORD[6]//globe.adsbexchange.com/$TRACKSERVICE}"
if (( RECORD[7] < 0 )); then
if ((RECORD[7] < 0)); then
msg_array[peek_audio]="${RECORD[7]} dBFS"
msg_array[loudness]="$(( RECORD[7] - RECORD[11] )) dB"
msg_array[loudness]="$((RECORD[7] - RECORD[11])) dB"
fi
# convert $msg_array[@] into a JSON object:
MQTT_JSON="$(for i in "${!msg_array[@]}"; do printf '{"%s":"%s"}\n' "$i" "${msg_array[$i]}"; done | jq -sc add)"
# prep the MQTT host, port, etc
unset MQTT_TOPIC MQTT_PORT MQTT_USERNAME MQTT_PASSWORD MQTT_HOST
MQTT_HOST="${MQTT_URL,,}"
MQTT_HOST="${MQTT_HOST##*:\/\/}" # strip protocol header (mqtt:// etc)
while [[ "${MQTT_HOST: -1}" == "/" ]]; do MQTT_HOST="${MQTT_HOST:0: -1}"; done # remove any trailing / from the HOST
if [[ $MQTT_HOST == *"/"* ]]; then MQTT_TOPIC="${MQTT_TOPIC:-${MQTT_HOST#*\/}}"; fi # if there's no explicitly defined topic, then use the URL's topic if that exists
MQTT_TOPIC="${MQTT_TOPIC:-$(hostname)/planefence}" # add default topic if there is still none defined
MQTT_HOST="${MQTT_HOST%%/*}" # remove everything from the first / onward
# prep the MQTT host, port, etc
unset MQTT_TOPIC MQTT_PORT MQTT_USERNAME MQTT_PASSWORD MQTT_HOST
MQTT_HOST="${MQTT_URL,,}"
MQTT_HOST="${MQTT_HOST##*:\/\/}" # strip protocol header (mqtt:// etc)
while [[ "${MQTT_HOST: -1}" == "/" ]]; do MQTT_HOST="${MQTT_HOST:0:-1}"; done # remove any trailing / from the HOST
if [[ $MQTT_HOST == *"/"* ]]; then MQTT_TOPIC="${MQTT_TOPIC:-${MQTT_HOST#*\/}}"; fi # if there's no explicitly defined topic, then use the URL's topic if that exists
MQTT_TOPIC="${MQTT_TOPIC:-$(hostname)/planefence}" # add default topic if there is still none defined
MQTT_HOST="${MQTT_HOST%%/*}" # remove everything from the first / onward
if [[ $MQTT_HOST == *"@"* ]]; then
MQTT_USERNAME="${MQTT_USERNAME:-${MQTT_HOST%@*}}"
MQTT_PASSWORD="${MQTT_PASSWORD:-${MQTT_USERNAME#*:}}"
MQTT_USERNAME="${MQTT_USERNAME%:*}"
MQTT_HOST="${MQTT_HOST#*@}"
fi
if [[ $MQTT_HOST == *":"* ]]; then MQTT_PORT="${MQTT_PORT:-${MQTT_HOST#*:}}"; fi
MQTT_HOST="${MQTT_HOST%:*}" # finally strip the host so there's only a hostname or ip address
if [[ $MQTT_HOST == *"@"* ]]; then
MQTT_USERNAME="${MQTT_USERNAME:-${MQTT_HOST%@*}}"
MQTT_PASSWORD="${MQTT_PASSWORD:-${MQTT_USERNAME#*:}}"
MQTT_USERNAME="${MQTT_USERNAME%:*}"
MQTT_HOST="${MQTT_HOST#*@}"
fi
if [[ $MQTT_HOST == *":"* ]]; then MQTT_PORT="${MQTT_PORT:-${MQTT_HOST#*:}}"; fi
MQTT_HOST="${MQTT_HOST%:*}" # finally strip the host so there's only a hostname or ip address
# log the message we are going to send:
echo "[$(date)][$APPNAME] Attempting to send a MQTT notification:"
echo "[$(date)][$APPNAME] MQTT Host: $MQTT_HOST"
echo "[$(date)][$APPNAME] MQTT Port: ${MQTT_PORT:-1883}"
echo "[$(date)][$APPNAME] MQTT Topic: $MQTT_TOPIC"
echo "[$(date)][$APPNAME] MQTT Client ID: ${MQTT_CLIENT_ID:-$(hostname)}"
if [[ -n "$MQTT_USERNAME" ]]; then echo "[$(date)][$APPNAME] MQTT Username: $MQTT_USERNAME"; fi
if [[ -n "$MQTT_PASSWORD" ]]; then echo "[$(date)][$APPNAME] MQTT Password: $MQTT_PASSWORD"; fi
if [[ -n "$MQTT_QOS" ]]; then echo "[$(date)][$APPNAME] MQTT QOS: $MQTT_QOS"; fi
echo "[$(date)][$APPNAME] MQTT Payload JSON Object: $MQTT_JSON"
# log the message we are going to send:
"${s6wrap[@]}" echo "Attempting to send a MQTT notification:"
"${s6wrap[@]}" echo "MQTT Host: $MQTT_HOST"
"${s6wrap[@]}" echo "MQTT Port: ${MQTT_PORT:-1883}"
"${s6wrap[@]}" echo "MQTT Topic: $MQTT_TOPIC"
"${s6wrap[@]}" echo "MQTT Client ID: ${MQTT_CLIENT_ID:-$(hostname)}"
if [[ -n "$MQTT_USERNAME" ]]; then "${s6wrap[@]}" echo "MQTT Username: $MQTT_USERNAME"; fi
if [[ -n "$MQTT_PASSWORD" ]]; then "${s6wrap[@]}" echo "MQTT Password: $MQTT_PASSWORD"; fi
if [[ -n "$MQTT_QOS" ]]; then "${s6wrap[@]}" echo "MQTT QOS: $MQTT_QOS"; fi
"${s6wrap[@]}" echo "MQTT Payload JSON Object: $MQTT_JSON"
# send the MQTT message:
mqtt_string=(--broker "$MQTT_HOST")
if [[ -n "$MQTT_PORT" ]]; then mqtt_string+=(--port "$MQTT_PORT"); fi
mqtt_string+=(--topic \""$MQTT_TOPIC"\")
if [[ -n "$MQTT_QOS" ]]; then mqtt_string+=(--qos "$MQTT_QOS"); fi
mqtt_string+=(--client_id \""${MQTT_CLIENT_ID:-$(hostname)}"\")
if [[ -n "$MQTT_USERNAME" ]]; then mqtt_string+=(--username "$MQTT_USERNAME"); fi
if [[ -n "$MQTT_PASSWORD" ]]; then mqtt_string+=(--password "$MQTT_PASSWORD"); fi
mqtt_string+=(--message "'${MQTT_JSON}'")
# send the MQTT message:
mqtt_string=(--broker "$MQTT_HOST")
if [[ -n "$MQTT_PORT" ]]; then mqtt_string+=(--port "$MQTT_PORT"); fi
mqtt_string+=(--topic \""$MQTT_TOPIC"\")
if [[ -n "$MQTT_QOS" ]]; then mqtt_string+=(--qos "$MQTT_QOS"); fi
mqtt_string+=(--client_id \""${MQTT_CLIENT_ID:-$(hostname)}"\")
if [[ -n "$MQTT_USERNAME" ]]; then mqtt_string+=(--username "$MQTT_USERNAME"); fi
if [[ -n "$MQTT_PASSWORD" ]]; then mqtt_string+=(--password "$MQTT_PASSWORD"); fi
mqtt_string+=(--message "'${MQTT_JSON}'")
# shellcheck disable=SC2068
outputmsg="$(echo ${mqtt_string[@]} | xargs mqtt)"
# shellcheck disable=SC2068
outputmsg="$(echo ${mqtt_string[@]} | xargs mqtt)"
if [[ "${outputmsg:0:6}" == "Failed" ]] || [[ "${outputmsg:0:5}" == "usage" ]] ; then
echo "[$(date)][$APPNAME] MQTT Delivery Error: ${outputmsg//$'\n'/ }"
else
echo "[$(date)][$APPNAME] MQTT Delivery successful!"
if chk_enabled "$MQTT_DEBUG"; then echo "[$(date)][$APPNAME] Results string: ${outputmsg//$'\n'/ }"; fi
fi
if [[ "${outputmsg:0:6}" == "Failed" ]] || [[ "${outputmsg:0:5}" == "usage" ]]; then
"${s6wrap[@]}" echo "MQTT Delivery Error: ${outputmsg//$'\n'/ }"
else
"${s6wrap[@]}" echo "MQTT Delivery successful!"
if chk_enabled "$MQTT_DEBUG"; then "${s6wrap[@]}" echo "Results string: ${outputmsg//$'\n'/ }"; fi
fi
fi
# Insert BlueSky notifications here:
if [[ -n "$BLUESKY_HANDLE" ]] && [[ -n "$BLUESKY_APP_PASSWORD" ]]; then
/scripts/post2bsky.sh "#Planefence $(sed -e 's|\\/|/|g' -e 's|\\n|\n|g' -e 's|%0A|\n|g' <<< "${TWEET}")" "$(if [[ "$GOTSNAP" == "true" ]]; then echo "$snapfile"; fi)" || true
/scripts/post2bsky.sh "#Planefence $(sed -e 's|\\/|/|g' -e 's|\\n|\n|g' -e 's|%0A|\n|g' <<<"${TWEET}")" "$(if [[ "$GOTSNAP" == "true" ]]; then echo "$snapfile"; fi)" || true
if [[ -f /tmp/bsky.link ]]; then
LINK="$(</tmp/bsky.link)"
(( RECORD[7] < 0 )) && RECORD[12]="$LINK" || RECORD[7]="$LINK"
rm -f /tmp/bsky.link
fi
fi
# And now, let's tweet!
if [ "$TWEETON" == "yes" ]
then
if [ "$TWEETON" == "yes" ]; then
TWIMG="false"
if [[ "$GOTSNAP" == "true" ]]
then
if [[ "$GOTSNAP" == "true" ]]; then
# If the curl call succeeded, we have a snapshot.png file saved!
TW_MEDIA_ID=$(twurl -X POST -H upload.twitter.com "/1.1/media/upload.json" -f $snapfile -F media | sed -n 's/.*\"media_id\":\([0-9]*\).*/\1/p')
(( TW_MEDIA_ID > 0 )) && TWIMG="true" || TW_MEDIA_ID=""
((TW_MEDIA_ID > 0)) && TWIMG="true" || TW_MEDIA_ID=""
fi
[[ "$TWIMG" == "true" ]] && echo "[$(date)][$APPNAME] Twitter Media ID=$TW_MEDIA_ID" || echo "[$(date)][$APPNAME] Twitter screenshot upload unsuccessful for ${RECORD[0]}"
[[ "$TWIMG" == "true" ]] && "${s6wrap[@]}" echo "Twitter Media ID=$TW_MEDIA_ID" || "${s6wrap[@]}" echo "Twitter screenshot upload unsuccessful for ${RECORD[0]}"
# send a tweet and read the link to the tweet into ${LINK[1]}
if [[ "$TWIMG" == "true" ]]
then
LINK="$(echo "`twurl -r "status=$TWEET&media_ids=$TW_MEDIA_ID" /1.1/statuses/update.json`" | tee -a /tmp/tweets.log | jq '.entities."urls" | .[] | .url' | tr -d '\"')"
if [[ "$TWIMG" == "true" ]]; then
LINK="$(echo "$(twurl -r "status=$TWEET&media_ids=$TW_MEDIA_ID" /1.1/statuses/update.json)" | tee -a /tmp/tweets.log | jq '.entities."urls" | .[] | .url' | tr -d '\"')"
else
LINK="$(echo "`twurl -r "status=$TWEET" /1.1/statuses/update.json`" | tee -a /tmp/tweets.log | jq '.entities."urls" | .[] | .url' | tr -d '\"')"
LINK="$(echo "$(twurl -r "status=$TWEET" /1.1/statuses/update.json)" | tee -a /tmp/tweets.log | jq '.entities."urls" | .[] | .url' | tr -d '\"')"
fi
# shellcheck disable=SC2028
[[ "${LINK:0:12}" == "https://t.co" ]] && echo "[$(date)][$APPNAME] Planefence post to Twitter generated successfully. Tweet available at: $LINK" || echo "[$(date)][$APPNAME] PlaneFence Tweet error. Twitter returned:\n$(tail -1 /tmp/tweets.log)"
[[ "${LINK:0:12}" == "https://t.co" ]] && "${s6wrap[@]}" echo "Planefence post to Twitter generated successfully. Tweet available at: $LINK" || "${s6wrap[@]}" echo "PlaneFence Tweet error. Twitter returned:\n$(tail -1 /tmp/tweets.log)"
rm -f $snapfile
else
@@ -466,7 +436,7 @@ then
fi
# Add a reference to the tweet to RECORD[7] (if no audio is available) or RECORD[11] (if audio is available)
(( RECORD[7] < 0 )) && RECORD[12]="$LINK" || RECORD[7]="$LINK"
if [[ -z "${RECORD[7]}" ]] && [[ -n "$LINK" ]]; then RECORD[12]="$LINK"; else RECORD[7]="$LINK"; fi
# LOG "Tweet sent!"
LOG "TWURL results: $LINK"
else
@@ -474,10 +444,16 @@ then
fi
# Now write everything back to $CSVTMP
( IFS=','; echo "${RECORD[*]}" >> "$CSVTMP" )
LOG "The record now contains $(IFS=','; echo "${RECORD[*]}")"
(
IFS=','
echo "${RECORD[*]}" >>"$CSVTMP"
)
LOG "The record now contains $(
IFS=','
echo "${RECORD[*]}"
)"
done < "$CSVFILE"
done <"$CSVFILE"
# last, copy the TMP file back to the CSV file
[ -f "$CSVTMP" ] && mv -f "$CSVTMP" "$CSVFILE"
else