243 lines
8.6 KiB
Bash
Executable File
243 lines
8.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# discord colors are standard 6-digit hex, but converted to a base-10 integer
|
|
# colors taken from https://xkcd.com/color/rgb/
|
|
# and built into a palette based on https://sashamaps.net/docs/resources/20-colors/
|
|
# into my color palette https://color.digitaladapt.com/
|
|
#
|
|
# DARK: maroon(#650021), brown(#653700), olive(#6e750e), teal(#029386), navy(#01153e), black(#000000),
|
|
# BRIGHT: red(#e50000), orange(#f97306), yellow(#ffff14), lime(#aaff32), green(#15b01a),
|
|
# cyan(#00ffff), blue(#0343df), purple(#7e1e9c), magenta(#c20078), grey(#929591),
|
|
# LIGHT: pink(#ff81c0), apricot(#ffb16d), beige(#e6daa6), mint(#9ffeb0), lavender(#c79fef), white(#ffffff).
|
|
|
|
scriptRoot=$(dirname "$0")
|
|
alert=false
|
|
quiet=false
|
|
skipMsg=false
|
|
declare -A colors
|
|
colors=(
|
|
["maroon"]=6619169 ["brown"]=6633216 ["olive"]=7238926 ["teal"]=168838 ["navy"]=70974 ["black"]=0
|
|
["red"]=15007744 ["orange"]=16347910 ["yellow"]=16776980 ["lime"]=11206450 ["green"]=1421338
|
|
["cyan"]=65535 ["blue"]=213983 ["purple"]=8265372 ["magenta"]=12714104 ["grey"]=9606545
|
|
["pink"]=16744896 ["apricot"]=16757101 ["beige"]=15129254 ["mint"]=10485424 ["lavender"]=13082607 ["white"]=16777215
|
|
)
|
|
declare -A ansiColors
|
|
ansiColors=(
|
|
["maroon"]="\e[37m\e[48;2;101;0;33m" ["brown"]="\e[37m\e[48;2;101;55;0m" ["olive"]="\e[37m\e[48;2;110;117;14m" ["teal"]="\e[37m\e[48;2;2;147;134m" ["navy"]="\e[37m\e[48;2;1;21;62m" ["black"]="\e[37m\e[48;2;0;0;0m"
|
|
["red"]="\e[30m\e[48;2;229;0;0m" ["orange"]="\e[30m\e[48;2;249;115;6m" ["yellow"]="\e[30m\e[48;2;255;255;20m" ["lime"]="\e[30m\e[48;2;170;255;50m" ["green"]="\e[30m\e[48;2;21;176;26m"
|
|
["cyan"]="\e[30m\e[48;2;0;255;255m" ["blue"]="\e[30m\e[48;2;3;67;223m" ["purple"]="\e[30m\e[48;2;126;30;156m" ["magenta"]="\e[30m\e[48;2;194;0;120m" ["grey"]="\e[30m\e[48;2;146;149;145m"
|
|
["pink"]="\e[30m\e[48;2;255;129;192m" ["apricot"]="\e[30m\e[48;2;255;177;109m" ["beige"]="\e[30m\e[48;2;230;218;166m" ["mint"]="\e[30m\e[48;2;159;254;176m" ["lavender"]="\e[30m\e[48;2;199;159;239m" ["white"]="\e[30m\e[48;2;255;255;255m"
|
|
)
|
|
|
|
print_usage() {
|
|
echo "Usage: $0 [[-h hook-url] | -a] [-c color] [-d [distinct-name]] [-t title] [-q] (message... | -z | < file.msg)"
|
|
}
|
|
|
|
# handle all arguments provided
|
|
while getopts ':h:c:d:t:zaq' flag; do
|
|
case "$flag" in
|
|
h)
|
|
if [[ "$OPTARG" == "http"*"?wait=true" ]]; then
|
|
hookUrl="$OPTARG"
|
|
else
|
|
echo "Invalid hook-url provided, should be something like:"
|
|
echo "https://discord.com/api/webhooks/***?wait=true"
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
;;
|
|
c)
|
|
if [[ -v "colors[$OPTARG]" ]]; then
|
|
color="$OPTARG"
|
|
else
|
|
echo "Invalid color provided"
|
|
"${scriptRoot}/colors-discord.sh"
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
;;
|
|
d)
|
|
# whatever the distinct key, we clean it up, since it will be used as a filename
|
|
# replace "/" and "|" with "_"
|
|
distinct=$(echo "$OPTARG" | sed 's/[\/\|]/_/g')
|
|
;;
|
|
:)
|
|
# '-d' without value is allowed, but generates a warning
|
|
# in which case we'll use name of parent command with arguments
|
|
# whatever the distinct key, we clean it up, since it will be used as a filename
|
|
# replace "/" and "|" with "_"
|
|
if [[ "$OPTARG" = "d" ]]; then
|
|
distinct=$(ps -o args= $PPID | sed 's/[\/\|]/_/g')
|
|
echo "Warning: doing distinct by parent, with key '$distinct'" >&2
|
|
else
|
|
echo "option '$OPTARG' provided with value"
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
;;
|
|
t)
|
|
# title, for supplying a title, without activing the "distinct" feature
|
|
title="$OPTARG"
|
|
;;
|
|
z)
|
|
skipMsg=true
|
|
;;
|
|
q)
|
|
quiet=true
|
|
;;
|
|
a)
|
|
alert=true
|
|
;;
|
|
*)
|
|
echo "unknown option provided '$flag'"
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
shift "$((OPTIND-1))"
|
|
|
|
# load in defaults from config
|
|
configFile="$scriptRoot/config.sh"
|
|
if [[ -f "$configFile" ]]; then
|
|
source "$configFile"
|
|
|
|
botName="$DISCORD_SERVER_NAME"
|
|
if [[ -z "$hookUrl" ]]; then
|
|
hookUrl="$DISCORD_GENERAL_HOOK"
|
|
|
|
if [[ "$alert" = true ]]; then
|
|
hookUrl="$DISCORD_ALERT_HOOK"
|
|
fi
|
|
fi
|
|
if [[ -n "$title" ]]; then
|
|
title="$title $DISCORD_TITLE_SUFFIX"
|
|
fi
|
|
fi
|
|
|
|
# stop if we have no hook to send message to
|
|
if [[ -z "$hookUrl" ]]; then
|
|
echo "Discord Hook URL must either be in config file, or supplied via '-h' argument."
|
|
exit 1
|
|
fi
|
|
|
|
# get full message, read from arguments
|
|
message=$(echo "$@" | sed 's/^ *//' | sed 's/ *$//')
|
|
|
|
# if we have no message, read from stdin instead
|
|
if [[ -z "$message" ]] && [[ "$skipMsg" = false ]]; then
|
|
message=$(cat - | sed 's/^ *//' | sed 's/ *$//')
|
|
fi
|
|
|
|
# sed removes blank lines from the end of the message
|
|
message=$(echo "$message" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}')
|
|
fullMsg="$message"
|
|
|
|
# output the given message, unless instructed to be quiet
|
|
if [[ "$quiet" = false ]]; then
|
|
if [[ -n "$distinct" ]] || [[ -n "$title" ]] || [[ -n "$color" ]]; then
|
|
if [[ -n "$color" ]]; then
|
|
echo -e "${ansiColors[$color]} ${title-$distinct} \e[m"
|
|
else
|
|
# no color specified, make title bold and underlined
|
|
echo -e "\e[1m\e[4m ${title-$distinct} \e[m"
|
|
fi
|
|
fi
|
|
if [[ -n "$fullMsg" ]] && [[ "$skipMsg" = false ]]; then
|
|
echo "$fullMsg"
|
|
fi
|
|
fi
|
|
|
|
# if message is too long, split it, and after curl, recursively call with remainder
|
|
# 4k max, but we must account for escaping text in json, so limit to 90% capacity
|
|
extra="${message:3600}"
|
|
|
|
if [ -n "$extra" ]; then
|
|
message="${message:0:3600}"
|
|
|
|
# as an added elegance, when spliting into pieces, find the last \n newline,
|
|
# and break there instead, but only if the new smaller chunk is of sufficient size
|
|
chunk1=$(echo "$message" | head -n -1)
|
|
chunks=$(echo "$message" | tail -n 1)
|
|
if (( "${#chunk1}" >= 1000 )); then
|
|
message="$chunk1"
|
|
extra="$chunks$extra"
|
|
fi
|
|
fi
|
|
|
|
# sed: rewrite json string, because "\u001b[m" needs to "\u001b[0m" instead
|
|
# linux is fine with the missing zero, but discord needs it
|
|
message=$(echo "$message" | jq -aRs . | sed 's/\\u001b\[m/\\u001b[0m/g')
|
|
|
|
if [[ "$message" = '"\n"' ]]; then
|
|
if [[ "$quiet" = true ]]; then
|
|
# quiet was specified, and there was no message, so stop now
|
|
exit 0
|
|
else
|
|
# message empty, so denote as such
|
|
message='"\ud83d\udea9 MESSAGE EMPTY \ud83d\udea9"'
|
|
fi
|
|
else
|
|
if [[ "$message" = *"\\u001b"* ]]; then
|
|
prefix="ansi\n"
|
|
fi
|
|
# wrap message into "ansi" block, for text color support
|
|
message="\"\`\`\`$prefix${message:1:-1}\`\`\`\""
|
|
fi
|
|
|
|
# handle distinct stuff
|
|
oldMsg=""
|
|
if [[ -n "$distinct" ]]; then
|
|
if [[ -f "$scriptRoot/unique/$distinct.msg" ]]; then
|
|
oldMsg=$(cat "$scriptRoot/unique/$distinct.msg")
|
|
fi
|
|
|
|
if [[ "$fullMsg" = "$oldMsg" ]]; then
|
|
echo "duplicate message"
|
|
exit 0
|
|
fi
|
|
|
|
echo "$fullMsg" > "$scriptRoot/unique/$distinct.msg"
|
|
fi
|
|
|
|
# build content json
|
|
content="{"
|
|
if [[ -n "$botName" ]]; then
|
|
content="$content\"username\": $(echo "$botName" | jq -aRs .), "
|
|
fi
|
|
content="$content\"embeds\":[{\"description\": "
|
|
if [[ "$skipMsg" = false ]]; then
|
|
content="$content$message"
|
|
else
|
|
content="$content\"\""
|
|
fi
|
|
if [[ -n "$color" ]]; then
|
|
content="$content, \"color\": ${colors[$color]}"
|
|
fi
|
|
if [[ -n "$distinct" ]] || [[ -n "$title" ]]; then
|
|
content="$content, \"title\": $(echo "${title-$distinct}" | jq -aRs .)"
|
|
fi
|
|
content="$content}]}"
|
|
|
|
# actually send the message to discord
|
|
response=$(curl -s -H "Content-Type: application/json" -X POST -d "$content" "$hookUrl" | jq -r '.message')
|
|
|
|
# response message is null unless there was an issue
|
|
if [[ "$response" != "null" ]]; then
|
|
echo "$response" >&2
|
|
fi
|
|
|
|
# if the message was too long, send along the rest as a separate message
|
|
if [ -n "$extra" ]; then
|
|
script=$(basename "$0")
|
|
args=("-h" "$hookUrl")
|
|
# when we call again, we convert distinct into a title
|
|
if [[ -n "$distinct" ]] || [[ -n "$title" ]]; then
|
|
args+=("-t" "${title-$distinct}")
|
|
fi
|
|
if [[ -n "$color" ]]; then
|
|
args+=("-c" "$color")
|
|
fi
|
|
"$scriptRoot/$script" ${args[@]} "$extra"
|
|
fi
|