Release 5.30 - add Planespotters photos to Planefence (#234)

This commit is contained in:
kx1t
2025-03-16 19:14:44 +01:00
committed by GitHub
6 changed files with 179 additions and 49 deletions

View File

@@ -22,7 +22,12 @@ LOOPTIME="3h"
# It specifically applies to files in the HTML directory.
# If $PF_DELETEAFTER is set to "0" then we never delete.
# Note - files in /tmp will get deleted if they are older than 2 days.
# -----------------------------------------------------------------------
# CACHETIME is the time that the planespotters photo cache expires. By TOC of the planespotters site,
# we may not keep cached thumbnails for more than 24 hours.
CACHETIME="${LOOPTIME//h/ hours}"
CACHETIME="${CACHETIME//m/ minutes}"
CACHETIME="${CACHETIME//s/ seconds}"
if [[ -f /usr/share/planefence/persist/planefence.config ]]; then
source /usr/share/planefence/persist/planefence.config
@@ -36,7 +41,6 @@ OLDERTHAN=${PF_DELETEAFTER:-14}
# MAXLOGLINES contains the max number of lines that we will keep in /tmp/planefence.log
MAXLOGLINES=500
#
#
# this function cleans out stuff. Make additions to it as needed.
CLEANUP ()
{
@@ -52,7 +56,8 @@ CLEANUP ()
mv -f /usr/share/planefence/persist/*.log /usr/share/planefence/persist/.internal 2>/dev/null
mv -f /usr/share/planefence/persist/planeownerscache.txt /usr/share/planefence/persist/.internal 2>/dev/null
touch -t "$(date -d "yesterday 00:00:00" +%Y%m%d%H%M)" /tmp/timestamp
touch -d "yesterday 00:00:00" /tmp/timestamp
touch -d "yesterday +$CACHETIME" /tmp/timestamp.planespottercache
find /usr/share/planefence/html/plane*{.html,.js,.csv,.rss} -mtime +"$OLDERTHAN" -delete 2>/dev/null
find /usr/share/planefence/html/noise*.png -mtime +"$OLDERTHAN" -delete 2>/dev/null
rm -f /run/socket30003/*.log
@@ -60,10 +65,11 @@ CLEANUP ()
find /usr/share/planefence/persist/.internal/*.tmp -type f ! -newer /tmp/timestamp -delete 2>/dev/null
find /usr/share/planefence/persist/.internal/*.log -type f ! -newer /tmp/timestamp -delete 2>/dev/null
find /usr/share/planefence/persist/.internal/dump1090-pf-*.tmp -type f ! -newer /tmp/timestamp -delete 2>/dev/null
find /usr/share/planefence/persist/planepix/cache/* -type f ! -newer /tmp/timestamp -delete 2>/dev/null
find /usr/share/planefence/persist/plane{fence,-alert}-discord.template.~[0-9]*~ -type f ! -newer /tmp/timestamp -delete 2>/dev/null
rm -f /tmp/heatmap-*.log
find /tmp -mindepth 1 -type f ! -newer /tmp/timestamp -delete 2>/dev/null
rm -f /tmp/timestamp
rm -f /tmp/timestamp /tmp/timestamp.planespottercache
shopt -s nullglob && for f in /run/socket30003/*.txt
do
[[ "$f" == "" ]] && continue || true

View File

@@ -404,16 +404,18 @@ set +a
BLUESKY_API=""
#
# ---------------------------------------------------------------------
# These are the parameters for PF web page dark mode:
# This is the parameter for PF web page dark mode:
DARKMODE=false
#
# ---------------------------------------------------------------------
# Parameter to set the default table size:
TABLESIZE=50
# ---------------------------------------------------------------------
# This parameter determines if planespotters.net images are used on the PF website and in PF notifications
SHOWIMAGES=true
# ---------------------------------------------------------------------
# Last, the version. Although you could change this, for tracking purposes, we'd like you to leave it to whatever the
# official version number is. If you fork this software, we'd appreciate if you add on to the version number rather than
# replace the entire number. That way, it's easy to understand from which version you forked. For example, VERSION=3.11-myfork-1.0
VERSION=5.29-release
VERSION=5.30-release

View File

@@ -164,6 +164,52 @@ LOG ()
fi
done
}
GET_PS_PHOTO () {
# Function to get a photo from PlaneSpotters.net
# Usage: GET_PS_PHOTO ICAO
# Returns: file location of the photo
# First, let's see if we have a cache file for the photos
local starttime
local link
local json
starttime="$(date +%s)"
if chk_disabled "$SHOWIMAGES"; then return 0; fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/$1.notavailable" ]]; then
echo "pf - $(date) - $(( $(date +%s) - starttime )) secs - $1 - no picture available (checked previously)" >> /tmp/getpi.log
return 0
fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/$1.jpg" ]] && \
[[ -f "/usr/share/planefence/persist/planepix/cache/$1.link" ]] && \
[[ -f "/usr/share/planefence/persist/planepix/cache/$1.thumb.link" ]]; then
echo "$(<"/usr/share/planefence/persist/planepix/cache/$1.link")"
echo "pf - $(date) - $(( $(date +%s) - starttime )) secs - $1 - picture was in cache" >> /tmp/getpi.log
return 0
fi
# If we don't have a cached file, let's see if we can get one from PlaneSpotters.net
if json="$(curl -ssL --fail "https://api.planespotters.net/pub/photos/hex/$1")" && \
link="$(jq -r 'try .photos[].link | select( . != null )' <<< "$json")" && \
thumb="$(jq -r 'try .photos[].thumbnail_large.src | select( . != null )' <<< "$json")" && \
[[ -n "$link" ]] && [[ -n "$thumb" ]]; then
# If we have a link, let's download the photo
curl -ssL --fail --clobber "$thumb" -o "/usr/share/planefence/persist/planepix/cache/$1.jpg"
echo "$link" > "/usr/share/planefence/persist/planepix/cache/$1.link"
echo "$thumb" > "/usr/share/planefence/persist/planepix/cache/$1.thumb.link"
echo "$link"
echo "pf - $(date) - $(( $(date +%s) - starttime )) secs - $1 - picture retrieved from planespotters.net" >> /tmp/getpi.log
else
# If we don't have a link, let's clear the cache and return an empty string
rm -f "/usr/share/planefence/persist/planepix/cache/$1.*"
touch "/usr/share/planefence/persist/planepix/cache/$1.notavailable"
echo "pf - $(date) - $(( $(date +%s) - starttime )) secs - $1 - no picture available (new)" >> /tmp/getpi.log
fi
}
LOG "-----------------------------------------------------"
# Function to write an HTML table from a CSV file
LOG "Defining WRITEHTMLTABLE"
@@ -212,7 +258,8 @@ WRITEHTMLTABLE () {
<th>No.</th>
<th>Transponder ID</th>
<th>Flight</th>
$([[ "$AIRLINECODES" != "" ]] && echo "<th>Airline or Owner</th>")
$([[ -n "${AIRLINECODES}" ]] && echo "<th>Airline or Owner</th>" || true)
$(! chk_disabled "${SHOW_IMAGES}" && echo "<th>Aircraft Image</th>" || true)
<th>Time First Seen</th>
<th>Time Last Seen</th>
<th>Min. Altitude</th>
@@ -397,15 +444,22 @@ EOF
NEWNAMES[${CALLSIGN}]="${AIRLINENAME}"
fi
if [[ $CALLSIGN =~ ^N[0-9][0-9a-zA-Z]+$ ]] && [[ "${CALLSIGN:0:4}" != "NATO" ]] && [[ "${NEWVALUES[0]:0:1}" == "A" ]]; then
printf " <td><a href=\"https://registry.faa.gov/AircraftInquiry/Search/NNumberResult?nNumberTxt=%s\" target=\"_blank\">%s</a></td>\n" "${CALLSIGN}" "${AIRLINENAME}" >&3
else
printf " <td>%s</td>\n" "${AIRLINENAME}" >&3 || printf " <td></td>\n" >&3
printf " <td>%s</td>\n" "${AIRLINENAME}" >&3
fi
else
printf " <td></td>\n" >&3
printf " <td></td>\n" >&3
fi
fi
if ! chk_disabled "${SHOW_IMAGES}"; then photo="$(GET_PS_PHOTO "${NEWVALUES[0]}")"; else photo=""; fi # get the photo from PlaneSpotters.net. If a notification was sent, it should already be in the cache so this should be quick
if [[ -n "$photo" ]]; then
printf " <td><a href=\"%s\" target=_blank><img src=\"%s\" alt=\"%s\" style=\"width: auto; height: 75px;\"></a></td>\n" "$photo" "imgcache/${NEWVALUES[0]}.jpg" "${NEWVALUES[0]}" >&3
elif ! chk_disabled "${SHOW_IMAGES}"; then
printf " <td></td>\n" >&3
fi
printf " <td style=\"text-align: center\">%s</td>\n" "$(date -d "${NEWVALUES[2]}" "+${NOTIF_DATEFORMAT:-%F %T %Z}")" >&3 # time first seen
printf " <td style=\"text-align: center\">%s</td>\n" "$(date -d "${NEWVALUES[3]}" "+${NOTIF_DATEFORMAT:-%F %T %Z}")" >&3 # time last seen
printf " <td>%s %s %s</td>\n" "${NEWVALUES[4]}" "$ALTUNIT" "$ALTREFERENCE" >&3 # min altitude

View File

@@ -153,6 +153,51 @@ getRoute() {
echo "$response"
}
GET_PS_PHOTO () {
# Function to get a photo from PlaneSpotters.net
# Usage: GET_PS_PHOTO ICAO
# Returns: link to photo page (and a cached image should become available)
# First, let's see if we have a cache file for the photos
local link
local json
local starttime
starttime="$(date +%s)"
if chk_disabled "$SHOWIMAGES"; then return 0; fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/$1.notavailable" ]]; then
echo "pfn - $(date) - $(( $(date +%s) - starttime )) secs - $1 - no picture available (checked previously)" >> /tmp/getpi.log
return 0
fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/$1.jpg" ]] && \
[[ -f "/usr/share/planefence/persist/planepix/cache/$1.link" ]] && \
[[ -f "/usr/share/planefence/persist/planepix/cache/$1.thumb.link" ]]; then
echo "$(<"/usr/share/planefence/persist/planepix/cache/$1.link")"
echo "pfn - $(date) - $(( $(date +%s) - starttime )) secs - $1 - picture was in cache" >> /tmp/getpi.log
return 0
fi
# If we don't have a cache file, let's see if we can get one from PlaneSpotters.net
if json="$(curl -ssL --fail "https://api.planespotters.net/pub/photos/hex/$1")" && \
link="$(jq -r 'try .photos[].link | select( . != null )' <<< "$json")" && \
thumb="$(jq -r 'try .photos[].thumbnail_large.src | select( . != null )' <<< "$json")" && \
[[ -n "$link" ]] && [[ -n "$thumb" ]]; then
# If we have a link, let's download the photo
curl -ssL --fail --clobber "$thumb" -o "/usr/share/planefence/persist/planepix/cache/$1.jpg"
echo "$link" > "/usr/share/planefence/persist/planepix/cache/$1.link"
echo "$thumb" > "/usr/share/planefence/persist/planepix/cache/$1.thumb.link"
echo "$link"
echo "pfn - $(date) - $(( $(date +%s) - starttime )) secs - $1 - picture retrieved from planespotters.net" >> /tmp/getpi.log
else
# If we don't have a link, let's clear the cache and return an empty string
rm -f "/usr/share/planefence/persist/planepix/cache/$1.*"
touch "/usr/share/planefence/persist/planepix/cache/$1.notavailable"
echo "pfn - $(date) - $(( $(date +%s) - starttime )) secs - $1 - no picture available (new)" >> /tmp/getpi.log
fi
}
if [ "$1" != "" ] && [ "$1" != "reset" ]; then # $1 contains the date for which we want to run Planefence
TWEETDATE=$(date --date="$1" '+%y%m%d')
else
@@ -234,16 +279,6 @@ if [ -f "$CSVFILE" ]; then
# swap adsbexchange for the $TRACKSERVICE:
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
"${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:
@@ -252,32 +287,45 @@ if [ -f "$CSVFILE" ]; then
# First, let's get a screenshot if there's one available!
rm -f /tmp/snapshot.png
GOTSNAP="false"
GOTSNAP=false
GOTIMG=false
snapfile="/tmp/snapshot.png"
newsnap="$(find /usr/share/planefence/persist/planepix -iname "${RECORD[0]}.jpg" -print -quit 2>/dev/null || true)"
# img will contain the path to an image file:
# - first prio is one that is stored in the planepix directory
# - second prio is one that is stored in the planepix/cache directory
imgfile="$(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
GOTSNAP="true"
rm -f "$snapfile"
ln -sf "$newsnap" "$snapfile"
"${s6wrap[@]}" echo "Using picture from $newsnap"
if [[ -n "$imgfile" ]]; then
GOTIMG=true
"${s6wrap[@]}" echo "Using picture from $imgfile"
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
"${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" != "" ]] && "${s6wrap[@]}" echo "Failed attempt to get picture from $link" || true
imglink=$(awk -F "," -v icao="${RECORD[0],,}" 'tolower($1) == icao { print $2 ; exit }' /usr/share/planefence/persist/planepix.txt 2>/dev/null || true)
if [[ -n "$imglink" ]] && curl -A "Mozilla/5.0 (X11; Linux x86_64; rv:97.0) Gecko/20100101 Firefox/97.0" -s -L --fail "$imglink" --clobber -o $snapfile 2>/dev/stdout; then
"${s6wrap[@]}" echo "Got picture from $link"
GOTIMG=true
cp -n "$snapfile" "/usr/share/planefence/persist/planepix/cache/${RECORD[0]}.jpg"
rm -f "$snapfile"
imgfile="/usr/share/planefence/persist/planepix/cache/${RECORD[0]}.jpg"
elif [[ -n "$imglink" ]]; then
"${s6wrap[@]}" echo "Failed attempt to get picture from planepix.txt link $link"
fi
fi
# If there's no image, let's see if we can get one from planespotters.net
if ! $GOTIMG && [[ -n "$(GET_PS_PHOTO "${RECORD[0]}")" ]]; then
imgfile="/usr/share/planefence/persist/planepix/cache/${RECORD[0]}.jpg"
GOTIMG=true
"${s6wrap[@]}" echo "Got picture from PlaneSpotters.net"
fi
"${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"
if curl -s -L --fail --max-time "$SCREENSHOT_TIMEOUT" "$SCREENSHOTURL/snap/${RECORD[0]#\#}" --clobber -o "/tmp/snapshot.png"; then
GOTSNAP=true
"${s6wrap[@]}" echo "Screenshot successfully retrieved at $SCREENSHOTURL for ${RECORD[0]}"
fi
[[ "$GOTSNAP" == "false" ]] && "${s6wrap[@]}" echo "Screenshot retrieval unsuccessful at $SCREENSHOTURL for ${RECORD[0]}" || true
if ! $GOTSNAP; then "${s6wrap[@]}" echo "Screenshot retrieval unsuccessful at $SCREENSHOTURL for ${RECORD[0]}"; fi
# 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
@@ -286,28 +334,35 @@ if [ -f "$CSVFILE" ]; then
fi
# log the message we will try to tweet or toot:
if [[ -n "$MASTODON_SERVER" ]] || [ "$TWEETON" == "yes" ]; then
if [[ -n "$MASTODON_SERVER" ]]; 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
mast_id="null"
mast_id=()
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)"
if $GOTSNAP && response="$(curl -sS --fail -H "Authorization: Bearer ${MASTODON_ACCESS_TOKEN}" -H "Content-Type: multipart/form-data" -X POST "https://${MASTODON_SERVER}/api/v1/media" --form file="@${snapfile}")"; then
# we upload an screenshot
mast_id+=("$(jq '.id' <<<"$response" | xargs)")
fi
if $GOTIMG && 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="@${imgfile}")"; then
# we upload an image file
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
# send without image
if [[ -z "${mast_id[*]}" ]]; then
# send without image(s)
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
# send with 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}" -F "media_ids[]=${mast_id}")"
# send with image(s)
# shellcheck disable=SC2068
printf -v media_ids -- '-F media_ids[]=%s ' ${mast_id[@]}
# shellcheck disable=SC2086
response="$(curl -H "Authorization: Bearer ${MASTODON_ACCESS_TOKEN}" -s "https://${MASTODON_SERVER}/api/v1/statuses" -X POST $media_ids -F "status=${MASTTEXT}" -F "language=eng" -F "visibility=${MASTODON_VISIBILITY}")"
fi
# check if there was an error
@@ -349,6 +404,12 @@ if [ -f "$CSVFILE" ]; then
msg_array[peek_audio]="${RECORD[7]} dBFS"
msg_array[loudness]="$((RECORD[7] - RECORD[11])) dB"
fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/${msg_array[icao]}.thumb.link" ]]; then
msg_array[thumbnail]="$(<"/usr/share/planefence/persist/planepix/cache/${msg_array[icao]}.thumb.link")"
fi
if [[ -f "/usr/share/planefence/persist/planepix/cache/${msg_array[icao]}.link" ]]; then
msg_array[planespotter_link]="$(<"/usr/share/planefence/persist/planepix/cache/${msg_array[icao]}.link")"
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)"
@@ -406,7 +467,7 @@ if [ -f "$CSVFILE" ]; then
# 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; then echo "$snapfile"; fi)" "$(if $GOTIMG; then echo "$imgfile"; fi)" || true
if [[ -f /tmp/bsky.link ]]; then
LINK="$(</tmp/bsky.link)"
rm -f /tmp/bsky.link

View File

@@ -48,7 +48,7 @@ function configure_both() {
# (by default exposed to ~/.planefence) then export all of those variables as well
# note that the grep strips off any spaces at the beginning of a line, and any commented line
mkdir -p /usr/share/planefence/persist/.internal
mkdir -p /usr/share/planefence/persist/planepix
mkdir -p /usr/share/planefence/persist/planepix/cache
mkdir -p /usr/share/planefence/html/plane-alert/silhouettes
mkdir -p /usr/share/planefence/html/scripts
chmod -f a=rwx /usr/share/planefence/persist /usr/share/planefence/persist/planepix
@@ -60,6 +60,8 @@ chmod u=rwx,go=rx \
/usr/share/planefence/html/plane-alert/silhouettes \
/usr/share/planefence/html/scripts
ln -sf /usr/share/planefence/html/scripts /usr/share/planefence/html/plane-alert/scripts
if [[ ! -e /usr/share/planefence/html/imgcache ]]; then ln -sf /usr/share/planefence/persist/planepix/cache /usr/share/planefence/html/imgcache; fi
chmod a+rx /usr/share/planefence/html/imgcache
if [[ -f /usr/share/planefence/persist/planefence.config ]]; then
set -o allexport
# shellcheck disable=SC1091
@@ -180,6 +182,7 @@ else
fi
configure_planealert "HISTTIME" "$PA_HISTTIME"
configure_planealert "ALERTHEADER" "'$PF_ALERTHEADER'"
configure_planefence "SHOWIMAGES" "$PF_SHOWIMAGES"
if [[ -n "$PF_SOCK30003HOST" ]]; then
# shellcheck disable=SC2001

View File

@@ -312,6 +312,10 @@ PA_HISTTIME=14
# This field is used to match the plane type to an icon.
PA_SILHOUETTES_LINK=
# ---------------------------------------------------------------------
# PF_SHOWIMAGES determines if the Planefence web page and Planefence notifications will attempt to get an aircraft image from
# planespotters.net. The default value if the parameter is omitted, is TRUE. Set to 0/off/false/no to disable including aircraft images.
PF_SHOWIMAGES=true
# ---------------------------------------------------------------------
# The following parameters enable posting Planefence or Plane-Alerts to a Discord channel.
# When posting to the #planefence-alert channel on the SDR-Enthusiasts Discord Server,
# PLEASE only post your Plane-Alerts and refrain from posting Planefence Alerts. This is