Cleanup.
This commit is contained in:
@@ -10,7 +10,9 @@ A simple, modular IRC bot written in bash
|
|||||||
./bot.sh
|
./bot.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Edit `bot.cfg` with your IRC server, channel, and bot settings
|
2. Edit `bot.cfg` with your IRC server, channels, and bot settings
|
||||||
|
- Configure multiple channels using an array: `channels=("channel1" "channel2")`
|
||||||
|
- Channel names should NOT include the # prefix
|
||||||
|
|
||||||
3. Run the bot again:
|
3. Run the bot again:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#enter channels here in quotes before the )
|
# Enter channels here as an array. Add multiple channels like: channels=("a11y" "channel2" "channel3")
|
||||||
channel="a11y"
|
# Channel names should NOT include the # prefix
|
||||||
|
channels=("a11y")
|
||||||
# The date format for log entries. man date for details.
|
# The date format for log entries. man date for details.
|
||||||
dateFormat='%B %d, %I:%m%P'
|
dateFormat='%B %d, %I:%m%P'
|
||||||
# Greet people who enter the channel? (true/false)
|
# Greet people who enter the channel? (true/false)
|
||||||
|
|||||||
29
bot.sh
29
bot.sh
@@ -30,7 +30,7 @@ done
|
|||||||
|
|
||||||
# Variables important to modules need to be exported here.
|
# Variables important to modules need to be exported here.
|
||||||
export allowList
|
export allowList
|
||||||
export channel
|
export channels
|
||||||
export input
|
export input
|
||||||
export ignoreList
|
export ignoreList
|
||||||
export nick
|
export nick
|
||||||
@@ -90,7 +90,10 @@ while true; do
|
|||||||
echo -e "Session started $(date "+%I:%M%p%n %A, %B %d, %Y").\n\nTo gracefully exit, make sure you are in the allow list and send the command exit to the bot.\n\n" | tee -a "$log"
|
echo -e "Session started $(date "+%I:%M%p%n %A, %B %d, %Y").\n\nTo gracefully exit, make sure you are in the allow list and send the command exit to the bot.\n\n" | tee -a "$log"
|
||||||
echo "NICK $nick" > "$input"
|
echo "NICK $nick" > "$input"
|
||||||
echo "USER $user" >> "$input"
|
echo "USER $user" >> "$input"
|
||||||
echo "JOIN #$channel" >> "$input"
|
# Join all configured channels
|
||||||
|
for channelName in "${channels[@]}"; do
|
||||||
|
echo "JOIN #$channelName" >> "$input"
|
||||||
|
done
|
||||||
|
|
||||||
# The main loop of the program where we watch for output from irc.
|
# The main loop of the program where we watch for output from irc.
|
||||||
# Use SSL if enabled, otherwise plain TCP
|
# Use SSL if enabled, otherwise plain TCP
|
||||||
@@ -136,12 +139,17 @@ while true; do
|
|||||||
;;
|
;;
|
||||||
# for pings on nick/user
|
# for pings on nick/user
|
||||||
*"You have not"*)
|
*"You have not"*)
|
||||||
echo "JOIN #$channel" | tee -a "$input"
|
for channelName in "${channels[@]}"; do
|
||||||
|
echo "JOIN #$channelName" | tee -a "$input"
|
||||||
|
done
|
||||||
;;
|
;;
|
||||||
# Run on kick
|
# Run on kick
|
||||||
:*!*@*" KICK "*" $nick :"*)
|
:*!*@*" KICK "*" $nick :"*)
|
||||||
if [ "$autoRejoinChannel" = "true" ]; then
|
if [ "$autoRejoinChannel" = "true" ]; then
|
||||||
echo "JOIN #$channel" | tee -a "$input"
|
# Extract channel name from kick message and rejoin that specific channel
|
||||||
|
kickedChannel="${result##*#}"
|
||||||
|
kickedChannel="#${kickedChannel%% *}"
|
||||||
|
echo "JOIN $kickedChannel" | tee -a "$input"
|
||||||
fi
|
fi
|
||||||
if [ "$curseKicker" = "true" ]; then
|
if [ "$curseKicker" = "true" ]; then
|
||||||
kickerName="${result%!*}"
|
kickerName="${result%!*}"
|
||||||
@@ -197,7 +205,8 @@ while true; do
|
|||||||
echo "Calling module ./modules/${command% *}/${command% *}/${command% *}.sh \"$who\" \"$from\" $willSanitized" >> "$log"
|
echo "Calling module ./modules/${command% *}/${command% *}/${command% *}.sh \"$who\" \"$from\" $willSanitized" >> "$log"
|
||||||
# Disable wildcards
|
# Disable wildcards
|
||||||
set -f
|
set -f
|
||||||
"./modules/${command% *}/${command% *}.sh" "$who" "#$channel" "$will"
|
# For PMs, respond directly to the user, not to a channel
|
||||||
|
"./modules/${command% *}/${command% *}.sh" "$who" "$from" "$will"
|
||||||
# Enable wildcards
|
# Enable wildcards
|
||||||
set +f
|
set +f
|
||||||
else
|
else
|
||||||
@@ -213,7 +222,7 @@ while true; do
|
|||||||
who="${who:1}"
|
who="${who:1}"
|
||||||
from="${result#*#}"
|
from="${result#*#}"
|
||||||
from="${from%% *}"
|
from="${from%% *}"
|
||||||
from="#${from:-$channel}"
|
from="#${from:-${channels[0]}}"
|
||||||
# Trigger stuff happens here.
|
# Trigger stuff happens here.
|
||||||
# Call link trigger if msg contains a link:
|
# Call link trigger if msg contains a link:
|
||||||
if [[ "$result" =~ .*http://|https://|www\..* ]]; then
|
if [[ "$result" =~ .*http://|https://|www\..* ]]; then
|
||||||
@@ -229,6 +238,8 @@ while true; do
|
|||||||
command="${command//# /}"
|
command="${command//# /}"
|
||||||
will="${command#* }"
|
will="${command#* }"
|
||||||
command="${command%% *}"
|
command="${command%% *}"
|
||||||
|
# If will equals command, there were no arguments
|
||||||
|
[[ "$will" == "$command" ]] && will=""
|
||||||
willSanitized="${will//[$'\001'-$'\037'$'\177']/}"
|
willSanitized="${will//[$'\001'-$'\037'$'\177']/}"
|
||||||
echo "DEBUG: command='$command' will='$willSanitized'" >> "$log"
|
echo "DEBUG: command='$command' will='$willSanitized'" >> "$log"
|
||||||
if command -v "./modules/${command% *}/${command% *}.sh" &>/dev/null ; then
|
if command -v "./modules/${command% *}/${command% *}.sh" &>/dev/null ; then
|
||||||
@@ -245,6 +256,12 @@ while true; do
|
|||||||
if ! [[ "$who" =~ ^($ignoreList)$ ]]; then
|
if ! [[ "$who" =~ ^($ignoreList)$ ]]; then
|
||||||
set -f
|
set -f
|
||||||
./triggers/keywords/keywords.sh "$who" "$from" "$result"
|
./triggers/keywords/keywords.sh "$who" "$from" "$result"
|
||||||
|
# Only call wordtrack for valid channel messages
|
||||||
|
if [[ "$from" =~ ^#[a-zA-Z0-9_-]+$ ]]; then
|
||||||
|
# Extract just the message text for wordtrack
|
||||||
|
messageText="${result#*PRIVMSG*:}"
|
||||||
|
./triggers/wordtrack/wordtrack.sh "$who" "$from" "$messageText"
|
||||||
|
fi
|
||||||
set +f
|
set +f
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
userNick="$1"
|
|
||||||
shift
|
|
||||||
chan="$1"
|
|
||||||
shift
|
|
||||||
snack="${@#botsnack}"
|
|
||||||
snack="${snack:-$(shuf -n1 -e\
|
|
||||||
"BBQ microchips" \
|
|
||||||
"BBQ sunflower seeds" \
|
|
||||||
"BBQ corn nuts" \
|
|
||||||
"deep fried goat placenta" \
|
|
||||||
"steak")} "
|
|
||||||
thanks="$(shuf -n1 -e "Thank you" "You're so awesome" "You shouldn't have" "You rock")"
|
|
||||||
favorite="$(shuf -n1 -e "my favorite" "yum yum" "this is bot heaven" "DELICIOUS")"
|
|
||||||
|
|
||||||
msg "$chan" "$thanks $userNick: $snack! $favorite!"
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
# Add phrases in quotes to the array.
|
|
||||||
phrases=(
|
|
||||||
"cuss words, just let 'em roll, mother fucking shit god damn ass hole!"
|
|
||||||
"cuss words, just don't quit, mother fuck you damn shit head bitch!"
|
|
||||||
"damn!"
|
|
||||||
"fuck the fucking fuckers!"
|
|
||||||
"fuck the fuck off!"
|
|
||||||
"fuck!"
|
|
||||||
"fuck. fuck. fuck. Mother mother fuck. Mother mother fuck fuck. Mother fuck mother fuck. Noise noise noise."
|
|
||||||
"god damn it!"
|
|
||||||
"motherfucker"
|
|
||||||
"shit, piss, fuck, cunt, cocksucker, motherfucker, and tits."
|
|
||||||
"shit!"
|
|
||||||
"son of a bitch!"
|
|
||||||
)
|
|
||||||
msg "$2" "${phrases[$(($RANDOM % ${#phrases[@]}))]}"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
douchebag=(
|
|
||||||
"Don't ask to ask, just ask!"
|
|
||||||
"STOP! READ THIS BEFORE YOU SPEAK! http://www.rockbox.org/wiki/IrcGuidelines"
|
|
||||||
"The human requesting this service can't be bothered to help you in person, so they requested a bot tell you that we don't discuss blah here, only blah+ which is totally different."
|
|
||||||
'Use a pastebin website, bun only the one approved by the users of this channel, else someone may flood your screen with whining and bitching!')
|
|
||||||
msg "$2" "$1: $(shuf -n1 -e "${douchebag[@]}")"
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
# Dependencies required by this module
|
|
||||||
dependencies=("curl")
|
|
||||||
|
|
||||||
# Check dependencies before running
|
|
||||||
if ! check_dependencies "${dependencies[@]}"; then
|
|
||||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
type="$(shuf -n1 -e "off" "you" "donut" "shakespeare" "linus" "king" "chainsaw" "madison")"
|
|
||||||
response="$(curl -s --connect-timeout 5 --max-time 10 -H "Accept: text/plain" "https://foaas.com/${type}/$3/$nick")"
|
|
||||||
if [[ -z "$response" || ${#response} -lt 5 ]]; then
|
|
||||||
msg "$2" "$1: Sorry, the FOAAS service is unavailable right now."
|
|
||||||
else
|
|
||||||
msg "$2" "$response"
|
|
||||||
fi
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
shift
|
|
||||||
chan="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
pimp() {
|
|
||||||
echo -n "$*" | sed \
|
|
||||||
-r -e "s/(^| )ask( |\?|\.|!)/\1aks\2/gI" \
|
|
||||||
-e "s/(^| )A /\1Uh $(shuf -e -n1 "god damn" "motha fuckin'") /gI" \
|
|
||||||
-e "s/(^| )I /\1Ah /gI" \
|
|
||||||
-e "s/(^| )is /\1be /gI" \
|
|
||||||
-e "s/(^| )are /\1is /gI" \
|
|
||||||
-e "s/(^| )(boy|dude|friend|guy|man)( |\?|\.|!)/\1$(shuf -n1 -e "bruh" "bruh-man" "brutha")\3/gI" \
|
|
||||||
-e "s/(^| )for( |\?|\.|!)/\1fuh\2/gI" \
|
|
||||||
-e "s/(^| )(appartment|house)( |\?|\.|!)/\1crib\3/gI" \
|
|
||||||
-e "s/(\w)ing( |\?|\.|!)/\1in'\2/gI" \
|
|
||||||
-e "s/(^| )my /\1mah /gI" \
|
|
||||||
-e "s/(^| )people /\1people /gI" \
|
|
||||||
-e "s/(^| )that( |\?|\.|!)/\1dat\2/gI" \
|
|
||||||
-e "s/(^| )this( |\?|\.|!)/\1dis\2/gI"
|
|
||||||
|
|
||||||
echo " $(shuf -n1 -e \
|
|
||||||
"Brace yourself foo'!" \
|
|
||||||
"What 'chew thinking Gee!" \
|
|
||||||
"and shit!" \
|
|
||||||
"sho 'nuff! ya'eard!?" \
|
|
||||||
"nd git Sheniquah's ass back ova' heeah!" \
|
|
||||||
)"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg "$chan" "$(pimp "$*")"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# The site on which this module relied is now down.
|
|
||||||
# This module is here in the hopes that it will one day come back.
|
|
||||||
# Thanks to joel.net for years of laughs.
|
|
||||||
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
shift
|
|
||||||
chan="$1"
|
|
||||||
shift
|
|
||||||
pimpText="${*#pimp }"
|
|
||||||
echo "$chan" "$(curl -L -s --data-urlencode English="$pimpText" --data-urlencode submit="Submit send" http://joel.net/EBONICS/Translator | grep ' <textarea id="Ebonics" name="Ebonics" class="materialize-textarea validate" required>' | sed -e 's/^ <textarea id="Ebonics" name="Ebonics" class="materialize-textarea validate" required>//' -e "s/'/'/g" -e 's#</textarea>##' -e 's/^$//g' -e 's/"/\\"/g')"
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
shift
|
|
||||||
chan="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
redneck() {
|
|
||||||
echo -n "$*" | sed \
|
|
||||||
-r -e "s/ass/ice/gI" \
|
|
||||||
-e "s/(^| )finger( |,|\?|\.|!|$)/\1fanger\2/gI" \
|
|
||||||
-e "s/(^| )thing( |,|\?|\.|!|$)/\1thang\2/gI" \
|
|
||||||
-e "s/(.\w+)ink(.*)/\1ank\2/gI" \
|
|
||||||
-e "s/(^| )A /\1uh /gI" \
|
|
||||||
-e "s/(.*)i([^a|^e|^u|^ble|^ck|^ft|^ll|^ndo|^on|^ps|^s|^v].*)/\1ah\2/gI" \
|
|
||||||
-e "s/(^| )I( |,|\?|\.|!|$)/\1Ah\2/g" \
|
|
||||||
-e "s/(^| )(boy|dude|fellow|guy|man)([?s])( |,|\?|\.|!|$)/\1feller\3\4/gI" \
|
|
||||||
-e "s/(^| )for( |,|\?|\.|!|$)/\1fer\2/gI" \
|
|
||||||
-e "s/(^| )(hello|hey|hi|how's it going|hows it going)( |,|\?|\.|!|$)/\1howdy\3/gI" \
|
|
||||||
-e "s/(^| )men( |,|\?|\.|!|$)/\1fellers\2/gI" \
|
|
||||||
-e "s/(^| )get( |,|\?|\.|!|$)/\1git\2/gI" \
|
|
||||||
-e "s/(^| )(appartment|cottage|house)( |,|\?|\.|!|$)/\1shack\3/gI" \
|
|
||||||
-e "s/(^| )(god damn|goddam)( |,|\?|\.|!|$)/\1gol-durn\3/gI" \
|
|
||||||
-e "s/(^| )damn( |,|\?|\.|!|$)/\1durn\2/gI" \
|
|
||||||
-e "s/(^| )(am not|is not|isn't|are not|aren't|will not)( |,|\?|\.|!|$)/\1ain't\3/gI" \
|
|
||||||
-e "s/(.*)backward(.*)/\1backerd\2/gI" \
|
|
||||||
-e "s/(^| )bear( |,|\?|\.|!|$)/\1bar\2/gI" \
|
|
||||||
-e "s/(^| )(cannot|can't)( |,|\?|\.|!|$)/\1cain't\3/gI" \
|
|
||||||
-e "s/(^| )careful( |,|\?|\.|!|$)/\1kerful\2/gI" \
|
|
||||||
-e "s/(^| )terrible( |,|\?|\.|!|$)/\1ter'ble\2/gI" \
|
|
||||||
-e "s/(\w)ing( |,|\?|\.|!|$)/\1in'\2/gI" \
|
|
||||||
-e "s/(\w)(i|ah)ght( |,|\?|\.|!|$)/\1aht'\3/gI" \
|
|
||||||
-e "s/(^| )my /\1mah /gI" \
|
|
||||||
-e "s/(^| )people( |,|\?|\.|!|$)/\1folks\2/gI" \
|
|
||||||
-e "s/(^| )pretty( |,|\?|\.|!|$)/\1purdy\2/gI" \
|
|
||||||
-e "s/(^| )sure( |,|\?|\.|!|$)/\1shore\2/gI" \
|
|
||||||
-e "s/(^| )there( |,|\?|\.|!|$)/\1thar'\2/gI" \
|
|
||||||
-e "s/(.*)window(.*)/\1windder\2/gI" \
|
|
||||||
-e "s/(.*)where|we're(.*)/\1wer\2/gI" \
|
|
||||||
-e "s/(^| )that( |,|\?|\.|!|$)/\1'at thar'\2/gI" \
|
|
||||||
-e "s/(^| )this( |,|\?|\.|!|$)/\1'is here\2/gI" \
|
|
||||||
-e "s/(^| )wash( |,|\?|\.|!|$)/\1wahrsh\2/gI" \
|
|
||||||
-e "s/(^| )([bg])ah([g|t])( |,|\?|\.|!|'|$)/\1\2i\3\4/gI" \
|
|
||||||
-e "s/(^| )aht( |,|\?|\.|!|'|$)/\1it\2/gI" \
|
|
||||||
-e "s/(^| )(ahf|if)( |,|\?|\.|!|$)/\1iffen\3/gI" \
|
|
||||||
-e "s/^[Yy]ou( |,|\.|\?\!|$)/Y'all\1/g"
|
|
||||||
|
|
||||||
echo " $(shuf -n1 -e \
|
|
||||||
"Hold Mah beer." \
|
|
||||||
"You're darn tootn" \
|
|
||||||
"Y'all come back now, ye'hear?" \
|
|
||||||
"Yyyyyyeeeeeeeeehaaaaaaaaawwwwww!" \
|
|
||||||
)"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg "$chan" "$(redneck "$*")"
|
|
||||||
@@ -335,7 +335,7 @@ case "$subcommand" in
|
|||||||
# Set user's location
|
# Set user's location
|
||||||
shift
|
shift
|
||||||
if [[ $# -eq 0 ]]; then
|
if [[ $# -eq 0 ]]; then
|
||||||
msg "$channelName" "$name: Usage: weather set <location>"
|
msg "$channelName" "$name: Usage: weather -set <location>"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
101
modules/wordtrack-leaders/wordtrack-leaders.sh
Executable file
101
modules/wordtrack-leaders/wordtrack-leaders.sh
Executable file
@@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Word tracking leaderboard module - shows top users in a category
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f functions.sh ] && source functions.sh
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f triggers/wordtrack/categories.sh ] && source triggers/wordtrack/categories.sh
|
||||||
|
|
||||||
|
name="$1"
|
||||||
|
channelName="$2"
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
category="$1"
|
||||||
|
|
||||||
|
# If no category specified, list available categories
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
if [[ -z "$category" ]]; then
|
||||||
|
msg "$channelName" "$name: Available categories: ${categories[*]}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate category exists
|
||||||
|
categoryValid=0
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
for cat in "${categories[@]}"; do
|
||||||
|
if [[ "$cat" == "$category" ]]; then
|
||||||
|
categoryValid=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ((categoryValid == 0)); then
|
||||||
|
msg "$channelName" "$name: Invalid category. Available: ${categories[*]}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Data directory for this channel
|
||||||
|
dataDir="triggers/wordtrack/data/${channelName}"
|
||||||
|
|
||||||
|
if [[ ! -d "$dataDir" ]]; then
|
||||||
|
msg "$channelName" "$name: No tracking data available yet."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all users' counts for this category
|
||||||
|
declare -A leaderboard
|
||||||
|
|
||||||
|
for userFile in "$dataDir"/*.dat; do
|
||||||
|
[[ -f "$userFile" ]] || continue
|
||||||
|
|
||||||
|
userName=$(basename "$userFile" .dat)
|
||||||
|
|
||||||
|
while IFS='=' read -r cat count; do
|
||||||
|
if [[ "$cat" == "$category" ]]; then
|
||||||
|
leaderboard["$userName"]="$count"
|
||||||
|
fi
|
||||||
|
done < "$userFile"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if anyone has been tracked
|
||||||
|
if [[ ${#leaderboard[@]} -eq 0 ]]; then
|
||||||
|
msg "$channelName" "$name: No one has been tracked in the ${category} category yet."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sort users by count (descending)
|
||||||
|
sortedUsers=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
sortedUsers+=("$line")
|
||||||
|
done < <(for user in "${!leaderboard[@]}"; do
|
||||||
|
echo "${leaderboard[$user]} $user"
|
||||||
|
done | sort -rn | head -5)
|
||||||
|
|
||||||
|
# Get level names for this category
|
||||||
|
levelsArrayName="${category}Levels"
|
||||||
|
declare -n levelsRef="$levelsArrayName"
|
||||||
|
|
||||||
|
# Build leaderboard message
|
||||||
|
leaderParts=()
|
||||||
|
position=1
|
||||||
|
|
||||||
|
for entry in "${sortedUsers[@]}"; do
|
||||||
|
count="${entry%% *}"
|
||||||
|
userName="${entry#* }"
|
||||||
|
|
||||||
|
# Find level for this count
|
||||||
|
level="Unranked"
|
||||||
|
for threshold in $(printf '%s\n' "${!levelsRef[@]}" | sort -n); do
|
||||||
|
if ((count >= threshold)); then
|
||||||
|
level="${levelsRef[$threshold]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
leaderParts+=("${position}. ${userName}: ${level} (${count} words)")
|
||||||
|
((position++))
|
||||||
|
done
|
||||||
|
|
||||||
|
unset -n levelsRef
|
||||||
|
|
||||||
|
msg "$channelName" "$name: Top ${category} users: $(IFS=' | '; echo "${leaderParts[*]}")"
|
||||||
74
modules/wordtrack-stats/wordtrack-stats.sh
Executable file
74
modules/wordtrack-stats/wordtrack-stats.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Word tracking stats module - shows user's current stats
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f functions.sh ] && source functions.sh
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f triggers/wordtrack/categories.sh ] && source triggers/wordtrack/categories.sh
|
||||||
|
|
||||||
|
name="$1"
|
||||||
|
channelName="$2"
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
# Optional: check another user's stats
|
||||||
|
targetUser="${1:-$name}"
|
||||||
|
|
||||||
|
# User data file
|
||||||
|
dataDir="triggers/wordtrack/data/${channelName}"
|
||||||
|
userDataFile="${dataDir}/${targetUser}.dat"
|
||||||
|
|
||||||
|
# Check if user has any data
|
||||||
|
if [[ ! -f "$userDataFile" ]]; then
|
||||||
|
msg "$channelName" "$name: ${targetUser} has not been tracked yet."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load user data
|
||||||
|
declare -A userCounts
|
||||||
|
while IFS='=' read -r category count; do
|
||||||
|
userCounts["$category"]="$count"
|
||||||
|
done < "$userDataFile"
|
||||||
|
|
||||||
|
# Build stats message
|
||||||
|
statsMessage="${targetUser}'s word tracking stats: "
|
||||||
|
statsParts=()
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
for category in "${categories[@]}"; do
|
||||||
|
count="${userCounts[$category]:-0}"
|
||||||
|
|
||||||
|
if ((count > 0)); then
|
||||||
|
# Get current level for this category
|
||||||
|
levelsArrayName="${category}Levels"
|
||||||
|
declare -n levelsRef="$levelsArrayName"
|
||||||
|
|
||||||
|
currentLevel="Unranked"
|
||||||
|
nextThreshold=""
|
||||||
|
|
||||||
|
# Find current level and next threshold
|
||||||
|
for threshold in $(printf '%s\n' "${!levelsRef[@]}" | sort -n); do
|
||||||
|
if ((count >= threshold)); then
|
||||||
|
currentLevel="${levelsRef[$threshold]}"
|
||||||
|
elif [[ -z "$nextThreshold" ]]; then
|
||||||
|
nextThreshold="$threshold"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset -n levelsRef
|
||||||
|
|
||||||
|
# Build stat string
|
||||||
|
if [[ -n "$nextThreshold" ]]; then
|
||||||
|
remaining=$((nextThreshold - count))
|
||||||
|
statsParts+=("${category}: ${currentLevel} (${count}/${nextThreshold}, ${remaining} to next)")
|
||||||
|
else
|
||||||
|
statsParts+=("${category}: ${currentLevel} (MAX LEVEL - ${count} words)")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#statsParts[@]} -eq 0 ]]; then
|
||||||
|
msg "$channelName" "$name: ${targetUser} has not earned any levels yet."
|
||||||
|
else
|
||||||
|
statsMessage+=$(IFS=' | '; echo "${statsParts[*]}")
|
||||||
|
msg "$channelName" "$statsMessage"
|
||||||
|
fi
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
[ -f functions.sh ] && source functions.sh
|
|
||||||
|
|
||||||
# Dependencies required by this module
|
|
||||||
dependencies=("curl" "sed")
|
|
||||||
|
|
||||||
# Check dependencies before running
|
|
||||||
if ! check_dependencies "${dependencies[@]}"; then
|
|
||||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
joke="$(curl -s --connect-timeout 5 --max-time 10 https://api.yomomma.info | sed -e 's/{"joke":"//' -e 's/"}$//')"
|
|
||||||
if [[ -z "$joke" || ${#joke} -lt 5 ]]; then
|
|
||||||
msg "$2" "$1: Sorry, couldn't fetch a yo momma joke right now."
|
|
||||||
else
|
|
||||||
joke="${joke//[[:space:]]/ }"
|
|
||||||
msg "$2" "$joke"
|
|
||||||
fi
|
|
||||||
@@ -24,28 +24,7 @@ keywords[windows]="msg \"$chan\" \"$(shuf -n1 -e\
|
|||||||
"Windows - Just another pain in the glass."\
|
"Windows - Just another pain in the glass."\
|
||||||
"Windows, it's not pretty, it's not ugly, but it's pretty ugly.")!\""
|
"Windows, it's not pretty, it's not ugly, but it's pretty ugly.")!\""
|
||||||
keywords[emacs]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
keywords[emacs]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
||||||
keywords[eloquence]="msg \"$chan\" \"$(shuf -n1 -e \
|
keywords[jaws]="msg \"$chan\" \"${who}: watch out for sharks!\""
|
||||||
"anticaesure" \
|
|
||||||
"caesure" \
|
|
||||||
"Goodhesville" \
|
|
||||||
"hh've" \
|
|
||||||
"Hoobhestank" \
|
|
||||||
"tzsche" \
|
|
||||||
"uncosp" \
|
|
||||||
"webhesday" \
|
|
||||||
"wedhesday")\""
|
|
||||||
keywords[eloquents]="msg \"$chan\" \"$(shuf -n1 -e \
|
|
||||||
"anticaesure" \
|
|
||||||
"caesure" \
|
|
||||||
"hh've" \
|
|
||||||
"tzsche" \
|
|
||||||
"uncosp" \
|
|
||||||
"webhesday" \
|
|
||||||
"wedhesday")\""
|
|
||||||
keywords[jaws]="msg \"$chan\" \"$(shuf -n1 -e \
|
|
||||||
"${who}: watch out for sharks!"\
|
|
||||||
"Ooooo! Jaws! Yeah, let's spend 1,500 bucks to buy what NVDA can do for free... Not much of an accountant are you ${who}?")\""
|
|
||||||
keywords[jfw]="msg \"$chan\" JFW: Acronym that means: Jaws! FUCKING WORTHLESS!"
|
|
||||||
keywords[emacspeak]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
keywords[emacspeak]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
||||||
keywords[nano]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
keywords[nano]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
||||||
keywords[pidgin]="msg \"$chan\" \"$who, Real men of genius use irssi!\""
|
keywords[pidgin]="msg \"$chan\" \"$who, Real men of genius use irssi!\""
|
||||||
@@ -53,9 +32,6 @@ keywords[weechat]="msg \"$chan\" \"$who, Real men of genius use irssi!\""
|
|||||||
keywords[thunderbird]="msg \"$chan\" \"$who, Real dogs use mutt, real men of genius use cat on a mailbox file!\""
|
keywords[thunderbird]="msg \"$chan\" \"$who, Real dogs use mutt, real men of genius use cat on a mailbox file!\""
|
||||||
keywords[gedit]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
keywords[gedit]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
||||||
keywords[pluma]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
keywords[pluma]="msg \"$chan\" \"$who, Real men of genius use vim!\""
|
||||||
keywords[chicken]="msg \"$chan\" \"$who, I'm gonna grab me $(shuf -n1 -e "a case of beer" "a weed eater" "a 5 gallon jug of vaseline" "a can of wd40") and a $(shuf -n1 -e dead frozen live young baby) chicken, and $(shuf -n1 -e "have fun" "make chicks" "lay it like an egg" "put my beak where it don't belong") ALL NIGHT LONG!!!\""
|
|
||||||
keywords[feather]="msg \"$chan\" \"$who: Erotic is using a feather. Kinky is using the whole chicken!!!\""
|
|
||||||
keywords[feathers]="msg \"$chan\" \"$who: Erotic is using a feather. Kinky is using the whole chicken!!!\""
|
|
||||||
keywords[dragonforce]="msg \"$chan\" \"$who: I love DragonForce!!!\""
|
keywords[dragonforce]="msg \"$chan\" \"$who: I love DragonForce!!!\""
|
||||||
keywords[vim]="msg \"$chan\" \"$(shuf -n1 -e \
|
keywords[vim]="msg \"$chan\" \"$(shuf -n1 -e \
|
||||||
"Praise vim! HA"\
|
"Praise vim! HA"\
|
||||||
@@ -76,9 +52,5 @@ done
|
|||||||
# Reset wordList without sorting it and with spaces removed.
|
# Reset wordList without sorting it and with spaces removed.
|
||||||
wordList="$(echo "${@,,}" | tr -d '[:space:]')"
|
wordList="$(echo "${@,,}" | tr -d '[:space:]')"
|
||||||
if [[ "${wordList,,}" =~ .*nowplaying:.* ]]; then
|
if [[ "${wordList,,}" =~ .*nowplaying:.* ]]; then
|
||||||
if [ "$who" = "lilmike" ]; then
|
|
||||||
msg "$chan" "Ewww, it sounds like 2 robots making out!"
|
|
||||||
else
|
|
||||||
act "$chan" "$(shuf -n1 -e "cranks the volume up to 11" "got soooo high at that show" "boogies down to the sound of the band")!"
|
act "$chan" "$(shuf -n1 -e "cranks the volume up to 11" "got soooo high at that show" "boogies down to the sound of the band")!"
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|||||||
103
triggers/wordtrack/README.md
Normal file
103
triggers/wordtrack/README.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# Wordtrack Trigger
|
||||||
|
|
||||||
|
Automatically tracks word usage by users and awards level-ups based on configurable thresholds.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The wordtrack trigger monitors all channel messages and counts occurrences of tracked words across different categories. Users automatically level up when they reach configured thresholds.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `wordtrack.sh` - Main trigger script (called automatically on messages)
|
||||||
|
- `categories.sh` - Configuration file defining categories, words, and levels
|
||||||
|
- `data/<channel>/<nick>.dat` - Per-user tracking data
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
Users can interact with wordtrack using these command modules:
|
||||||
|
|
||||||
|
### `.wordtrack-stats [nick]`
|
||||||
|
Shows word tracking statistics for yourself or another user.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
.wordtrack-stats
|
||||||
|
.wordtrack-stats alice
|
||||||
|
```
|
||||||
|
|
||||||
|
Output: `alice's word tracking stats: coffee: Coffee Lover (50/100, 50 to next) | tea: Tea Sipper (12/25, 13 to next)`
|
||||||
|
|
||||||
|
### `.wordtrack-leaders <category>`
|
||||||
|
Shows top 5 users in a category.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
.wordtrack-leaders coffee
|
||||||
|
.wordtrack-leaders
|
||||||
|
```
|
||||||
|
|
||||||
|
Output: `Top coffee users: 1. alice: Coffee Lover (50 words) | 2. bob: Coffee Drinker (30 words) | 3. charlie: Coffee Newbie (15 words)`
|
||||||
|
|
||||||
|
If no category is provided, lists available categories.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit `categories.sh` to add new categories or modify existing ones.
|
||||||
|
|
||||||
|
### Adding a New Category
|
||||||
|
|
||||||
|
1. Create a word array: `categoryWords=("word1" "word2" "word3")`
|
||||||
|
2. Create a levels array: `declare -A categoryLevels=([threshold1]="Level Name" [threshold2]="Level Name")`
|
||||||
|
3. Add category to the categories list: `categories=("coffee" "tea" "yournewcategory")`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
# Category: programming
|
||||||
|
programmingWords=("code" "coding" "python" "javascript" "rust" "git" "debug")
|
||||||
|
|
||||||
|
declare -A programmingLevels=(
|
||||||
|
[10]="Code Newbie"
|
||||||
|
[25]="Junior Dev"
|
||||||
|
[50]="Developer"
|
||||||
|
[100]="Senior Dev"
|
||||||
|
[200]="Code Wizard"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add to categories list
|
||||||
|
categories=("coffee" "tea" "gaming" "programming")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Array Structure
|
||||||
|
|
||||||
|
- **Word arrays**: Simple indexed arrays containing words to track
|
||||||
|
- Words are matched case-insensitively
|
||||||
|
- Multiple word matches in one message count separately
|
||||||
|
|
||||||
|
- **Level arrays**: Associative arrays with threshold as key, level name as value
|
||||||
|
- Keys must be integers representing word counts
|
||||||
|
- Users advance when their count meets or exceeds the threshold
|
||||||
|
- Thresholds can be any positive integer
|
||||||
|
|
||||||
|
## Data Format
|
||||||
|
|
||||||
|
User data files (`data/<channel>/<nick>.dat`) use simple key=value format:
|
||||||
|
|
||||||
|
```
|
||||||
|
coffee=45
|
||||||
|
tea=12
|
||||||
|
gaming=78
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with bot.sh
|
||||||
|
|
||||||
|
The wordtrack trigger is called automatically for all channel messages from users not in the ignoreList (bot.sh:254-262). It processes messages after the keywords trigger.
|
||||||
|
|
||||||
|
Level-up announcements are sent to the channel automatically when thresholds are crossed.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Users in the `ignoreList` are not tracked
|
||||||
|
- Word matching is case-insensitive
|
||||||
|
- Multiple occurrences of tracked words in a single message all count
|
||||||
|
- Data persists across bot restarts (stored in flat files)
|
||||||
|
- Each channel has independent tracking data
|
||||||
61
triggers/wordtrack/categories.sh
Normal file
61
triggers/wordtrack/categories.sh
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Word tracking categories configuration
|
||||||
|
# Add your own categories by following the pattern below
|
||||||
|
|
||||||
|
# Category: coffee
|
||||||
|
# Words that trigger tracking for coffee category
|
||||||
|
coffeeWords=("coffee" "espresso" "latte" "mocha" "cappuccino" "americano" "frappuccino" "macchiato" "cortado" "affogato")
|
||||||
|
|
||||||
|
# Level thresholds and reward names for coffee category
|
||||||
|
# Array key is the threshold (word count needed), value is the level name
|
||||||
|
declare -A coffeeLevels=(
|
||||||
|
[10]="Coffee Newbie"
|
||||||
|
[25]="Coffee Drinker"
|
||||||
|
[50]="Coffee Lover"
|
||||||
|
[100]="Coffee Addict"
|
||||||
|
[200]="Coffee Fiend"
|
||||||
|
[500]="Coffee God"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Category: tea
|
||||||
|
teaWords=("tea" "matcha" "chai" "oolong" "earl" "green tea" "black tea" "herbal" "chamomile" "rooibos")
|
||||||
|
|
||||||
|
declare -A teaLevels=(
|
||||||
|
[10]="Tea Sipper"
|
||||||
|
[25]="Tea Enthusiast"
|
||||||
|
[50]="Tea Connoisseur"
|
||||||
|
[100]="Tea Master"
|
||||||
|
[200]="Tea Guru"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Category: gaming
|
||||||
|
gamingWords=("game" "gaming" "play" "played" "console" "steam" "xbox" "playstation" "nintendo" "pc gaming")
|
||||||
|
|
||||||
|
declare -A gamingLevels=(
|
||||||
|
[10]="Casual Gamer"
|
||||||
|
[25]="Regular Player"
|
||||||
|
[50]="Dedicated Gamer"
|
||||||
|
[100]="Hardcore Gamer"
|
||||||
|
[200]="Gaming Enthusiast"
|
||||||
|
[500]="Gaming Legend"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Words that trigger tracking for drugs category
|
||||||
|
drugsWords=("kratom" "gummy" "hemp" "nicotine")
|
||||||
|
|
||||||
|
# Level thresholds and reward names for drugs category
|
||||||
|
# Array key is the threshold (word count needed), value is the level name
|
||||||
|
declare -A drugsLevels=(
|
||||||
|
[10]="Adict"
|
||||||
|
[20]="Junky"
|
||||||
|
[40]="Burnout"
|
||||||
|
[80]="Dope Fiend"
|
||||||
|
[160]="Intervention Candidate"
|
||||||
|
[320]="Drug Lord"
|
||||||
|
[640]="Pickled"
|
||||||
|
)
|
||||||
|
|
||||||
|
# List all active categories (must match the prefix of your arrays above)
|
||||||
|
# This is used by the trigger to know which categories to track
|
||||||
|
categories=("coffee" "tea" "gaming" "drugs")
|
||||||
46
triggers/wordtrack/categories.sh.example
Normal file
46
triggers/wordtrack/categories.sh.example
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Word tracking categories configuration
|
||||||
|
# Add your own categories by following the pattern below
|
||||||
|
|
||||||
|
# Category: coffee
|
||||||
|
# Words that trigger tracking for coffee category
|
||||||
|
coffeeWords=("coffee" "espresso" "latte" "mocha" "cappuccino" "americano" "frappuccino" "macchiato" "cortado" "affogato")
|
||||||
|
|
||||||
|
# Level thresholds and reward names for coffee category
|
||||||
|
# Array key is the threshold (word count needed), value is the level name
|
||||||
|
declare -A coffeeLevels=(
|
||||||
|
[10]="Coffee Newbie"
|
||||||
|
[25]="Coffee Drinker"
|
||||||
|
[50]="Coffee Lover"
|
||||||
|
[100]="Coffee Addict"
|
||||||
|
[200]="Coffee Fiend"
|
||||||
|
[500]="Coffee God"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Category: tea
|
||||||
|
teaWords=("tea" "matcha" "chai" "oolong" "earl" "green tea" "black tea" "herbal" "chamomile" "rooibos")
|
||||||
|
|
||||||
|
declare -A teaLevels=(
|
||||||
|
[10]="Tea Sipper"
|
||||||
|
[25]="Tea Enthusiast"
|
||||||
|
[50]="Tea Connoisseur"
|
||||||
|
[100]="Tea Master"
|
||||||
|
[200]="Tea Guru"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Category: gaming
|
||||||
|
gamingWords=("game" "gaming" "play" "played" "console" "steam" "xbox" "playstation" "nintendo" "pc gaming")
|
||||||
|
|
||||||
|
declare -A gamingLevels=(
|
||||||
|
[10]="Casual Gamer"
|
||||||
|
[25]="Regular Player"
|
||||||
|
[50]="Dedicated Gamer"
|
||||||
|
[100]="Hardcore Gamer"
|
||||||
|
[200]="Gaming Enthusiast"
|
||||||
|
[500]="Gaming Legend"
|
||||||
|
)
|
||||||
|
|
||||||
|
# List all active categories (must match the prefix of your arrays above)
|
||||||
|
# This is used by the trigger to know which categories to track
|
||||||
|
categories=("coffee" "tea" "gaming")
|
||||||
1
triggers/wordtrack/data/#bots/storm.dat
Normal file
1
triggers/wordtrack/data/#bots/storm.dat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
gaming=30
|
||||||
116
triggers/wordtrack/wordtrack.sh
Executable file
116
triggers/wordtrack/wordtrack.sh
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Word tracking trigger - monitors messages and tracks word usage
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f functions.sh ] && source functions.sh
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -f triggers/wordtrack/categories.sh ] && source triggers/wordtrack/categories.sh
|
||||||
|
|
||||||
|
name="$1"
|
||||||
|
channelName="$2"
|
||||||
|
shift 2
|
||||||
|
message="$*"
|
||||||
|
|
||||||
|
# Sanitize channel name (remove any IRC protocol remnants)
|
||||||
|
channelName="${channelName%%[[:space:]]*}"
|
||||||
|
channelName="${channelName//[^a-zA-Z0-9#_-]/}"
|
||||||
|
|
||||||
|
# Only process if we have a valid channel name starting with #
|
||||||
|
if [[ ! "$channelName" =~ ^#[a-zA-Z0-9_-]+$ ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Convert message to lowercase for case-insensitive matching
|
||||||
|
messageLower="${message,,}"
|
||||||
|
|
||||||
|
# Create data directory for this channel if it doesn't exist
|
||||||
|
dataDir="triggers/wordtrack/data/${channelName}"
|
||||||
|
mkdir -p "$dataDir"
|
||||||
|
|
||||||
|
# User data file
|
||||||
|
userDataFile="${dataDir}/${name}.dat"
|
||||||
|
|
||||||
|
# Load existing user data
|
||||||
|
declare -A userCounts
|
||||||
|
if [[ -f "$userDataFile" ]]; then
|
||||||
|
while IFS='=' read -r category count; do
|
||||||
|
userCounts["$category"]="$count"
|
||||||
|
done < "$userDataFile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Track which categories had level-ups
|
||||||
|
declare -a levelUps
|
||||||
|
|
||||||
|
# Process each category
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
for category in "${categories[@]}"; do
|
||||||
|
# Get the word array and levels array for this category
|
||||||
|
levelsArrayName="${category}Levels"
|
||||||
|
|
||||||
|
# Check if message contains any words from this category
|
||||||
|
wordCount=0
|
||||||
|
wordsArrayNameClean="${category}Words"
|
||||||
|
declare -n wordsRef="$wordsArrayNameClean"
|
||||||
|
|
||||||
|
for word in "${wordsRef[@]}"; do
|
||||||
|
# Count all occurrences of this word in the message
|
||||||
|
wordLower="${word,,}"
|
||||||
|
tempMessage="$messageLower"
|
||||||
|
while [[ "$tempMessage" =~ $wordLower ]]; do
|
||||||
|
((wordCount++))
|
||||||
|
# Remove the matched word to find more occurrences
|
||||||
|
tempMessage="${tempMessage/$wordLower/}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
unset -n wordsRef
|
||||||
|
|
||||||
|
# If words were found, update the counter
|
||||||
|
if ((wordCount > 0)); then
|
||||||
|
oldCount="${userCounts[$category]:-0}"
|
||||||
|
newCount=$((oldCount + wordCount))
|
||||||
|
userCounts["$category"]="$newCount"
|
||||||
|
|
||||||
|
# Check for level-up
|
||||||
|
oldLevel=""
|
||||||
|
newLevel=""
|
||||||
|
|
||||||
|
# Get the thresholds for this category using nameref
|
||||||
|
declare -n levelsRef="$levelsArrayName"
|
||||||
|
|
||||||
|
# Get old level
|
||||||
|
for threshold in $(printf '%s\n' "${!levelsRef[@]}" | sort -n); do
|
||||||
|
if ((oldCount >= threshold)); then
|
||||||
|
oldLevel="${levelsRef[$threshold]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get new level
|
||||||
|
for threshold in $(printf '%s\n' "${!levelsRef[@]}" | sort -n); do
|
||||||
|
if ((newCount >= threshold)); then
|
||||||
|
newLevel="${levelsRef[$threshold]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If level changed, record the level-up
|
||||||
|
if [[ -n "$newLevel" && "$newLevel" != "$oldLevel" ]]; then
|
||||||
|
levelUps+=("$category:$newLevel:$newCount")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up nameref
|
||||||
|
unset -n levelsRef
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Save updated user data
|
||||||
|
: > "$userDataFile"
|
||||||
|
for category in "${!userCounts[@]}"; do
|
||||||
|
echo "${category}=${userCounts[$category]}" >> "$userDataFile"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Announce level-ups
|
||||||
|
for levelUp in "${levelUps[@]}"; do
|
||||||
|
IFS=':' read -r category level count <<< "$levelUp"
|
||||||
|
msg "$channelName" "$name just leveled up in ${category}! You are now a ${level} with ${count} words!"
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user