A few updates, cleanup updated weather module.
This commit is contained in:
1 parent
221e14a85a
commit
3669e07a9a
43 files changed
+794
-153
No files matched your search
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
userNick="$1"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
advice=(
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
msg "$2" "$1: $@"
|
||||
+15
-2
@@ -1,12 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("curl" "w3m" "grep" "sed" "iconv")
|
||||
|
||||
set -f
|
||||
quote="$(curl -s http://bash.org/?random)"
|
||||
quote="$(curl -s --connect-timeout 5 --max-time 10 http://bash.org/?random)"
|
||||
if [[ -z "$quote" ]]; then
|
||||
msg "$2" "$1: Sorry, couldn't fetch a bash.org quote right now."
|
||||
set +f
|
||||
exit 1
|
||||
fi
|
||||
quote="$(echo "$quote" | grep -m 1 -A 10 '"Permanent link to this quote."')"
|
||||
quote="${quote#*class=\"qt\">}"
|
||||
quote="${quote//</ <}"
|
||||
quote="${quote//>/> }"
|
||||
quote="${quote%%<p class*}"
|
||||
quote="$(echo "$quote" | w3m -dump -T text/html)"
|
||||
msg "$2" "$(echo "$quote" | iconv -f utf-8 -t ascii)"
|
||||
if [[ ${#quote} -lt 5 ]]; then
|
||||
msg "$2" "$1: Sorry, couldn't parse the bash.org quote."
|
||||
else
|
||||
msg "$2" "$(echo "$quote" | iconv -f utf-8 -t ascii)"
|
||||
fi
|
||||
set +f
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
userNick="$1"
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("calc")
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
calculate() {
|
||||
calc -- "$*" | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
case "${3^^}" in
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
units="$(command -v units)"
|
||||
# Dependencies required by this module
|
||||
dependencies=("units")
|
||||
|
||||
shift
|
||||
chan="$1"
|
||||
shift
|
||||
if [ -z "$units" ]; then
|
||||
msg "$chan" "I do not have access to units."
|
||||
else
|
||||
msg "$chan" "$($units -v ${*#* } | head -n1 | tr -d '[:space:]')"
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$chan" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg "$chan" "$(units -v ${*#* } | head -n1 | tr -d '[:space:]')"
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Add phrases in quotes to the array.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
shift
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
douchebag=(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
user=$1
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("curl" "w3m" "grep" "iconv")
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fml="$(curl -Ls --connect-timeout 5 https://fmylife.com/random | grep -m1 -A1 '<a class="article-link" href="/article/.*>' | tail -1 | w3m -dump -T text/html | iconv -f utf-8 -t ascii | tr '[:space:]' ' ')"
|
||||
|
||||
if [[ ${#fml} -gt 10 ]]; then
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
fortune="$(command -v fortune)"
|
||||
# Dependencies required by this module
|
||||
dependencies=("fortune")
|
||||
|
||||
target="${3#fortune}"
|
||||
|
||||
if [ -z "$fortune" ]; then
|
||||
msg "$2" "I do not have access to fortune."
|
||||
else
|
||||
fortuneText="$($fortune -a -e -s -n 512 $target || echo "No fortunes found.")"
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fortuneText="$(fortune -a -e -s -n 512 $target || echo "No fortunes found.")"
|
||||
fortuneText="$(echo "$fortuneText" | tr '[:space:]' ' ' | sed -e 's/"/\"/g')"
|
||||
msg "$2" "$fortuneText"
|
||||
fi
|
||||
+16
-1
@@ -1,4 +1,19 @@
|
||||
#!/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")"
|
||||
msg "$2" "$(curl -s -H "Accept: text/plain" "https://foaas.com/${type}/$3/$nick")"
|
||||
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,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
output="$1: The modules I have are:"
|
||||
output="$output $(find modules/ -type d | sort -d | tr '[:space:]' ' ' | sed -e 's#modules/##g')"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
cpu="$(shuf -n 1 -e HACKER NUKE SHOTGUN)"
|
||||
player="$3"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[[ -f functions.sh ]] && source functions.sh
|
||||
|
||||
# Find the last line of the script.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
user=$1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
shift
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
pong="${3:-ping}"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
shift
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
userNick="$1"
|
||||
@@ -7,20 +8,56 @@ shift
|
||||
time="$1"
|
||||
shift
|
||||
|
||||
# Validate time argument is provided
|
||||
if [[ -z "$time" ]]; then
|
||||
msg "$chan" "$userNick: Please provide a time (e.g., 30s, 5m, 1h)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Normalize time format
|
||||
if ! [[ "$time" =~ ^[0-9]+[HhMmSs]$ ]]; then
|
||||
time="${time}s"
|
||||
fi
|
||||
|
||||
# Validate time is numeric
|
||||
if ! [[ "${time%[HhMmSs]}" =~ ^[0-9]+$ ]]; then
|
||||
reminderMessage="Times must be numeric (seconds)."
|
||||
msg "$chan" "$userNick: $reminderMessage"
|
||||
else
|
||||
msg "$chan" "ok, $userNick, reminder in $time."
|
||||
reminderMessage="$@"
|
||||
if [[ "$reminderMessage" =~ ^[Tt]ell* ]]; then
|
||||
userNick="$(echo "${reminderMessage#[T|t]ell }" | cut -d ' ' -f1)"
|
||||
reminderMessage="${reminderMessage#[Tt]ell }"
|
||||
reminderMessage="${reminderMessage#* }"
|
||||
fi
|
||||
sleep $time && msg "$chan" "$userNick: $reminderMessage"&
|
||||
msg "$chan" "$userNick: Time must be numeric (e.g., 30s, 5m, 1h)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate time is reasonable (max 24 hours)
|
||||
timeValue="${time%[HhMmSs]}"
|
||||
timeUnit="${time: -1}"
|
||||
case "${timeUnit,,}" in
|
||||
h) maxTime=24; timeInSeconds=$((timeValue * 3600)) ;;
|
||||
m) maxTime=1440; timeInSeconds=$((timeValue * 60)) ;;
|
||||
s) maxTime=86400; timeInSeconds=$timeValue ;;
|
||||
*) maxTime=86400; timeInSeconds=$timeValue ;;
|
||||
esac
|
||||
|
||||
if [[ $timeValue -gt $maxTime ]]; then
|
||||
msg "$chan" "$userNick: Maximum time is 24 hours."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate reminder message is provided
|
||||
if [[ -z "$*" ]]; then
|
||||
msg "$chan" "$userNick: Please provide a reminder message."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg "$chan" "ok, $userNick, reminder in $time."
|
||||
reminderMessage="$@"
|
||||
|
||||
# Handle 'tell' syntax for targeting other users
|
||||
if [[ "$reminderMessage" =~ ^[Tt]ell[[:space:]]+ ]]; then
|
||||
targetNick="$(echo "${reminderMessage#[T|t]ell }" | cut -d ' ' -f1)"
|
||||
# Validate nick doesn't contain invalid characters
|
||||
if [[ "$targetNick" =~ ^[a-zA-Z0-9_\[\]\{\}\\|\`\^\-]+$ ]]; then
|
||||
userNick="$targetNick"
|
||||
reminderMessage="${reminderMessage#[Tt]ell }"
|
||||
reminderMessage="${reminderMessage#* }"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep "$timeInSeconds" && msg "$chan" "$userNick: $reminderMessage" &
|
||||
+29
-4
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
roll_dice() {
|
||||
@@ -30,8 +31,32 @@ roll_dice() {
|
||||
}
|
||||
|
||||
rollString="${3##* }"
|
||||
if ! [[ "$rollString" =~ ^[1-9][0-9]*[dD][1-9][0-9]*$ ]]; then
|
||||
msg "$2" "${1}: Usage is roll #d# where # is greater than 0."
|
||||
else
|
||||
msg "$2" "$(roll_dice ${rollString})"
|
||||
|
||||
# Validate roll string is provided
|
||||
if [[ -z "$rollString" ]]; then
|
||||
msg "$2" "${1}: Usage is roll #d# (e.g., 2d6, 1d20)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate roll string format
|
||||
if ! [[ "$rollString" =~ ^[1-9][0-9]*[dD][1-9][0-9]*$ ]]; then
|
||||
msg "$2" "${1}: Invalid format. Usage: roll #d# where # is greater than 0 (e.g., 2d6, 1d20)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract count and sides for validation
|
||||
count=${rollString%[dD]*}
|
||||
sides=${rollString#*[dD]}
|
||||
|
||||
# Validate reasonable limits to prevent abuse
|
||||
if [[ $count -gt 1000 ]]; then
|
||||
msg "$2" "${1}: Maximum 1000 dice per roll."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $sides -gt 1000 ]]; then
|
||||
msg "$2" "${1}: Maximum 1000 sides per die."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg "$2" "$(roll_dice ${rollString})"
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
cpu="$(shuf -n 1 -e PAPER ROCK SCISSORS)"
|
||||
player="$3"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
shift
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
# Sex adapted to the stormbot.
|
||||
# The C version is available from: http://spatula.net/software/sex/
|
||||
# Please use responsibly, disable where inappropriate
|
||||
|
||||
#set up random parts of the sentence
|
||||
faster="$(shuf -n 1 -e "\"Let the games begin!\"" "\"Sweet Jesus!\"" "\"Not that!\"" "\"At last!\"" "\"Land o' Goshen!\"" "\"Is that all?\"" "\"Cheese it, the cops!\"" "\"I never dreamed it could be\"" "\"If I do, you won't respect me!\"" "\"Now!\"" "\"Open sesame!\"" "\"EMR!\"" "\"Again!\"" "\"Faster!\"" "\"Harder!\"" "\"Help!\"" "\"Fuck me harder!\"" "\"Is it in yet?\"" "\"You aren't my father!\"" "\"Doctor, that's not *my* shou\"" "\"No, no, do the goldfish!\"" "\"Holy Batmobile, Batman!\"" "\"He's dead, he's dead!\"" "\"Take me, Robert!\"" "\"I'm a Republican!\"" "\"Put four fingers in!\"" "\"What a lover!\"" "\"Talk dirty, you pig!\"" "\"The ceiling needs painting,\"" "\"Suck harder!\"" "\"The animals will hear!\"" "\"Not in public!\"")"
|
||||
said="$( shuf -n 1 -e "bellowed" "yelped" "croaked" "growled" "panted" "moaned" "grunted" "laughed" "warbled" "sighed" "ejaculated" "choked" "stammered" "wheezed" "squealed" "whimpered" "salivated" "tongued" "cried" "screamed" "yelled" "said")"
|
||||
fadj="$(shuf -n 1 -e "saucy" "wanton" "unfortunate" "lust-crazed" "nine-year-old" "bull-dyke" "bisexual" "gorgeous" "sweet" "nymphomaniacal" "large-hipped" "freckled" "forty-five year old" "white-haired" "large-boned" "saintly" "blind" "bearded" "blue-eyed" "large tongued" "friendly" "piano playing" "ear licking" "doe eyed" "sock sniffing" "lesbian" "hairy")"
|
||||
female="$(shuf -n 1 -e "baggage" "hussy" "woman" "Duchess" "female impersonator" "nymphomaniac" "virgin" "leather freak" "home-coming queen" "defrocked nun" "bisexual budgie" "cheerleader" "office secretary" "sexual deviate" "DARPA contract monitor" "little matchgirl" "ceremonial penguin" "femme fatale" "bosses' daughter" "construction worker" "sausage abuser" "secretary" "Congressman's page" "grandmother" "penguin" "German shepherd" "stewardess" "waitress" "prostitute" "computer science group" "housewife")"
|
||||
madjec="$(shuf -n 1 -e "thrashing" "slurping" "insatiable" "rabid" "satanic" "corpulent" "nose-grooming" "tripe-fondling" "dribbling" "spread-eagled" "orally fixated" "vile" "awesomely endowed" "handsome" "mush-brained" "tremendously hung" "three-legged" "pile-driving" "cross-dressing" "gerbil buggering" "bung-hole stuffing" "sphincter licking" "hair-pie chewing" "muff-diving" "clam shucking" "egg-sucking" "bicycle seat sniffing")"
|
||||
male="$(shuf -n 1 -e "rakehell" "hunchback" "lecherous lickspittle" "archduke" "midget" "hired hand" "great Dane" "stallion" "donkey" "electric eel" "paraplegic pothead" "dirty old man" "faggot butler" "friar" "black-power advocate" "follicle fetishist" "handsome priest" "chicken flicker" "homosexual flamingo" "ex-celibate" "drug sucker" "ex-woman" "construction worker" "hair dresser" "dentist" "judge" "social worker")"
|
||||
diddled="$(shuf -n 1 -e "diddled" "devoured" "fondled" "mouthed" "tongued" "lashed" "tweaked" "violated" "defiled" "irrigated" "penetrated" "ravished" "hammered" "bit" "tongue slashed" "sucked" "fucked" "rubbed" "grudge fucked" "masturbated with" "slurped")"
|
||||
titadj="$(shuf -n 1 -e "alabaster" "pink-tipped" "creamy" "rosebud" "moist" "throbbing" "juicy" "heaving" "straining" "mammoth" "succulent" "quivering" "rosey" "globular" "varicose" "jiggling" "bloody" "tilted" "dribbling" "oozing" "firm" "pendulous" "muscular" "bovine")"
|
||||
knockers="$(shuf -n 1 -e "globes" "melons" "mounds" "buds" "paps" "chubbies" "protuberances" "treasures" "buns" "bung" "vestibule" "armpits" "tits" "knockers" "elbows" "eyes" "hooters" "jugs" "lungs" "headlights" "disk drives" "bumpers" "knees" "fried eggs" "buttocks" "charlies" "ear lobes" "bazooms" "mammaries")"
|
||||
thrust="$(shuf -n 1 -e "plunged" "thrust" "squeezed" "pounded" "drove" "eased" "slid" "hammered" "squished" "crammed" "slammed" "reamed" "rammed" "dipped" "inserted" "plugged" "augured" "pushed" "ripped" "forced" "wrenched")"
|
||||
dongadj="$(shuf -n 1 -e "bursting" "jutting" "glistening" "Brobdingnagian" "prodigious" "purple" "searing" "swollen" "rigid" "rampaging" "warty" "steaming" "gorged" "trunklike" "foaming" "spouting" "swinish" "prosthetic" "blue veined" "engorged" "horse like" "throbbing" "humongous" "hole splitting" "serpentine" "curved" "steel encased" "glass encrusted" "knobby" "surgically altered" "metal tipped" "open sored" "rapidly dwindling" "swelling" "miniscule" "boney")"
|
||||
dong="$(shuf -n 1 -e "intruder" "prong" "stump" "member" "meat loaf" "majesty" "bowsprit" "earthmover" "jackhammer" "ramrod" "cod" "jabber" "gusher" "poker" "engine" "brownie" "joy stick" "plunger" "piston" "tool" "manhood" "lollipop" "kidney prodder" "candlestick" "John Thomas" "arm" "testicles" "balls" "finger" "foot" "tongue" "dick" "one-eyed wonder worm" "canyon yodeler" "middle leg" "neck wrapper" "stick shift" "dong" "Linda Lovelace choker")"
|
||||
twatadj="$(shuf -n 1 -e "pulsing" "hungry" "hymeneal" "palpitating" "gaping" "slavering" "welcoming" "glutted" "gobbling" "cobwebby" "ravenous" "slurping" "glistening" "dripping" "scabiferous" "porous" "soft-spoken" "pink" "dusty" "tight" "odiferous" "moist" "loose" "scarred" "weapon-less" "banana stuffed" "tire tracked" "mouse nibbled" "tightly tensed" "oft traveled" "grateful" "festering")"
|
||||
twat="$(shuf -n 1 -e "swamp." "honeypot." "jam jar." "butterbox." "furburger." "cherry pie." "cush." "slot." "slit." "cockpit." "damp." "furrow." "sanctum sanctorum." "bearded clam." "continental divide." "paradise valley." "red river valley." "slot machine." "quim." "palace." "ass." "rose bud." "throat." "eye socket." "tenderness." "inner ear." "orifice." "appendix scar." "wound." "navel." "mouth." "nose." "cunt.")"
|
||||
|
||||
msg "$2" "$faster $said the $fadj $female as the $madjec $male $diddled her $titadj $knockers and $thrust his $dongadj $dong into her $twatadj $twat"
|
||||
@@ -1,13 +0,0 @@
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
sext=('( . Y . )'
|
||||
'( . )( . )'
|
||||
'(o)(o)'
|
||||
'( + )( + )'
|
||||
'(*)(*)'
|
||||
'(@)(@)'
|
||||
'(oYo)'
|
||||
'( ^ )( ^ )'
|
||||
'( . )Y( . )'
|
||||
'8========3~~')
|
||||
msg "$2" "$(shuf -n 1 -e '( . Y . )' '( . )( . )' '(o)(o)' '( + )( + )' '(*)(*)' '(@)(@)' '(oYo)' '( ^ )( ^ )' '( . )Y( . )')"
|
||||
@@ -1,8 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("clyrics")
|
||||
|
||||
shift
|
||||
chan="$1"
|
||||
shift
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$chan" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
#get the lyric text into a variable
|
||||
lyricText="$(clyrics $@ | tr '[:space:]' ' ' | tr -s ' ' | fold -s -w 384)"
|
||||
i=$(echo "$lyricText" | wc -l)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
userNick="$1"
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("pgrep" "ps")
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pid=$(pgrep bot.sh | head -1)
|
||||
uptime="$(ps -p $pid -o etime | tail -1)"
|
||||
msg "$2" "$1: I have been up for ${uptime}."
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Alias for weather module
|
||||
|
||||
# Just call the weather module with all arguments
|
||||
./modules/weather/weather.sh "$@"
|
||||
+422
-55
@@ -1,73 +1,440 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
# Dependencies required by this module
|
||||
dependencies=("curl" "jq" "date")
|
||||
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$2" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -f
|
||||
|
||||
name="$1"
|
||||
channelName="$2"
|
||||
shift
|
||||
shift
|
||||
shift 2
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
msg "$channelName" "$name: Please provide a location or postcode."
|
||||
# Database file for user locations and cached geocoding
|
||||
weatherDb="data/weather.db"
|
||||
mkdir -p "$(dirname "$weatherDb")"
|
||||
touch "$weatherDb"
|
||||
|
||||
# Weather code mapping (Open-Meteo codes to descriptions)
|
||||
declare -A weatherCodes=(
|
||||
[0]="Clear sky"
|
||||
[1]="Mainly clear"
|
||||
[2]="Partly cloudy"
|
||||
[3]="Overcast"
|
||||
[45]="Fog"
|
||||
[48]="Rime fog"
|
||||
[51]="Light drizzle"
|
||||
[53]="Moderate drizzle"
|
||||
[55]="Dense drizzle"
|
||||
[56]="Light freezing drizzle"
|
||||
[57]="Dense freezing drizzle"
|
||||
[61]="Slight rain"
|
||||
[63]="Moderate rain"
|
||||
[65]="Heavy rain"
|
||||
[66]="Light freezing rain"
|
||||
[67]="Heavy freezing rain"
|
||||
[71]="Slight snow fall"
|
||||
[73]="Moderate snow fall"
|
||||
[75]="Heavy snow fall"
|
||||
[77]="Snow flurries"
|
||||
[80]="Slight rain showers"
|
||||
[81]="Moderate rain showers"
|
||||
[82]="Heavy rain showers"
|
||||
[85]="Slight snow showers"
|
||||
[86]="Heavy snow showers"
|
||||
[95]="Thunderstorm"
|
||||
[96]="Thunderstorm with slight hail"
|
||||
[99]="Thunderstorm with heavy hail"
|
||||
)
|
||||
|
||||
# Function to get cached geocode result
|
||||
get_cached_location() {
|
||||
local query="$1"
|
||||
local queryLower="${query,,}"
|
||||
grep -i "^CACHE|${queryLower}|" "$weatherDb" 2>/dev/null | head -n1
|
||||
}
|
||||
|
||||
# Function to get user's saved location
|
||||
get_user_location() {
|
||||
local user="$1"
|
||||
grep "^USER|${user}|" "$weatherDb" 2>/dev/null | head -n1
|
||||
}
|
||||
|
||||
# Function to save user location
|
||||
save_user_location() {
|
||||
local user="$1"
|
||||
local location="$2"
|
||||
local lat="$3"
|
||||
local lon="$4"
|
||||
local formatted="$5"
|
||||
|
||||
# Remove old entry if exists
|
||||
if [[ -f "$weatherDb" ]]; then
|
||||
grep -v "^USER|${user}|" "$weatherDb" > "${weatherDb}.tmp"
|
||||
mv "${weatherDb}.tmp" "$weatherDb"
|
||||
fi
|
||||
|
||||
# Add new entry
|
||||
echo "USER|${user}|${location}|${lat}|${lon}|${formatted}" >> "$weatherDb"
|
||||
}
|
||||
|
||||
# Function to delete user location
|
||||
delete_user_location() {
|
||||
local user="$1"
|
||||
|
||||
if [[ -f "$weatherDb" ]]; then
|
||||
grep -v "^USER|${user}|" "$weatherDb" > "${weatherDb}.tmp"
|
||||
mv "${weatherDb}.tmp" "$weatherDb"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to cache geocode result
|
||||
cache_location() {
|
||||
local query="$1"
|
||||
local location="$2"
|
||||
local lat="$3"
|
||||
local lon="$4"
|
||||
local formatted="$5"
|
||||
local queryLower="${query,,}"
|
||||
|
||||
# Check if already cached
|
||||
local cached
|
||||
cached=$(get_cached_location "$query")
|
||||
if [[ -z "$cached" ]]; then
|
||||
echo "CACHE|${queryLower}|${location}|${lat}|${lon}|${formatted}" >> "$weatherDb"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to format location (City, State or City, Country)
|
||||
format_location() {
|
||||
local address="$1"
|
||||
|
||||
# Use jq to parse the address components
|
||||
local locality
|
||||
local state
|
||||
local country
|
||||
local countryCode
|
||||
|
||||
# Try various location types in order of specificity
|
||||
locality=$(echo "$address" | jq -r '.city // .town // .village // .hamlet // .municipality // .suburb // empty' 2>/dev/null)
|
||||
state=$(echo "$address" | jq -r '.state // empty' 2>/dev/null)
|
||||
country=$(echo "$address" | jq -r '.country // empty' 2>/dev/null)
|
||||
countryCode=$(echo "$address" | jq -r '.country_code // empty' 2>/dev/null)
|
||||
|
||||
# For US addresses, always show state if available
|
||||
if [[ "$countryCode" == "us" && -n "$locality" && -n "$state" ]]; then
|
||||
echo "${locality}, ${state}"
|
||||
elif [[ "$countryCode" == "us" && -n "$state" ]]; then
|
||||
# No locality, just show state
|
||||
echo "${state}, United States"
|
||||
elif [[ -n "$locality" && -n "$country" ]]; then
|
||||
# International: show locality and country
|
||||
echo "${locality}, ${country}"
|
||||
elif [[ -n "$country" ]]; then
|
||||
# Just country
|
||||
echo "$country"
|
||||
else
|
||||
# Fallback to display_name if parsing fails
|
||||
echo "$address" | jq -r '.display_name // "Unknown location"' 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to geocode a location
|
||||
geocode_location() {
|
||||
local query="$1"
|
||||
|
||||
# Check cache first
|
||||
local cached
|
||||
local location
|
||||
local lat
|
||||
local lon
|
||||
local formatted
|
||||
cached=$(get_cached_location "$query")
|
||||
if [[ -n "$cached" ]]; then
|
||||
# Format: CACHE|query|location|lat|lon|formatted
|
||||
location=$(echo "$cached" | cut -d'|' -f3)
|
||||
lat=$(echo "$cached" | cut -d'|' -f4)
|
||||
lon=$(echo "$cached" | cut -d'|' -f5)
|
||||
formatted=$(echo "$cached" | cut -d'|' -f6)
|
||||
|
||||
# If no formatted location in cache (old format), use location
|
||||
if [[ -z "$formatted" ]]; then
|
||||
formatted="$location"
|
||||
fi
|
||||
|
||||
echo "${location}|${lat}|${lon}|${formatted}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Query Nominatim API
|
||||
local url="https://nominatim.openstreetmap.org/search"
|
||||
local userAgent="stormbot-weather/1.0"
|
||||
local response
|
||||
|
||||
# URL encode the query (replace spaces with +)
|
||||
local encodedQuery="${query// /+}"
|
||||
|
||||
response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||
-H "User-Agent: ${userAgent}" \
|
||||
"${url}?q=${encodedQuery}&format=json&limit=1&addressdetails=1")
|
||||
|
||||
if [[ -z "$response" || "$response" == "[]" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Parse response
|
||||
local fullAddress
|
||||
local addressDetails
|
||||
local formattedLocation
|
||||
lat=$(echo "$response" | jq -r '.[0].lat // empty' 2>/dev/null)
|
||||
lon=$(echo "$response" | jq -r '.[0].lon // empty' 2>/dev/null)
|
||||
fullAddress=$(echo "$response" | jq -r '.[0].display_name // empty' 2>/dev/null)
|
||||
addressDetails=$(echo "$response" | jq -r '.[0].address // empty' 2>/dev/null)
|
||||
|
||||
if [[ -z "$lat" || -z "$lon" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Format the location nicely
|
||||
formattedLocation=$(format_location "$addressDetails")
|
||||
|
||||
# Cache the result
|
||||
cache_location "$query" "$fullAddress" "$lat" "$lon" "$formattedLocation"
|
||||
|
||||
echo "${fullAddress}|${lat}|${lon}|${formattedLocation}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to get weather data
|
||||
get_weather() {
|
||||
local lat="$1"
|
||||
local lon="$2"
|
||||
|
||||
local url="https://api.open-meteo.com/v1/forecast"
|
||||
local params="latitude=${lat}&longitude=${lon}"
|
||||
params+="¤t=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m"
|
||||
params+="&daily=weather_code,temperature_2m_max,temperature_2m_min"
|
||||
params+="&timezone=auto&forecast_days=3&temperature_unit=fahrenheit&wind_speed_unit=mph"
|
||||
|
||||
local response
|
||||
response=$(curl -s --connect-timeout 5 --max-time 10 "${url}?${params}")
|
||||
|
||||
if [[ -z "$response" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to format weather output
|
||||
format_weather() {
|
||||
local weatherData="$1"
|
||||
local locationName="$2"
|
||||
|
||||
# Parse current weather
|
||||
local temp
|
||||
local humidity
|
||||
local windSpeed
|
||||
local weatherCode
|
||||
temp=$(echo "$weatherData" | jq -r '.current.temperature_2m // "N/A"')
|
||||
humidity=$(echo "$weatherData" | jq -r '.current.relative_humidity_2m // "N/A"')
|
||||
windSpeed=$(echo "$weatherData" | jq -r '.current.wind_speed_10m // "N/A"')
|
||||
weatherCode=$(echo "$weatherData" | jq -r '.current.weather_code // 0')
|
||||
local conditions="${weatherCodes[$weatherCode]:-Unknown}"
|
||||
|
||||
# Build message
|
||||
local message="Weather for ${locationName}: ${temp}°F, ${conditions}"
|
||||
|
||||
if [[ "$humidity" != "N/A" ]]; then
|
||||
message+=", Humidity: ${humidity}%"
|
||||
fi
|
||||
|
||||
if [[ "$windSpeed" != "N/A" ]]; then
|
||||
message+=", Wind: ${windSpeed} mph"
|
||||
fi
|
||||
|
||||
echo "$message"
|
||||
}
|
||||
|
||||
# Function to format forecast output
|
||||
format_forecast() {
|
||||
local weatherData="$1"
|
||||
|
||||
# Parse forecast data
|
||||
local dates
|
||||
dates=$(echo "$weatherData" | jq -r '.daily.time[]' 2>/dev/null)
|
||||
|
||||
if [[ -z "$dates" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local forecastParts=()
|
||||
local i=0
|
||||
|
||||
while IFS= read -r dateStr; do
|
||||
local minTemp
|
||||
local maxTemp
|
||||
local code
|
||||
minTemp=$(echo "$weatherData" | jq -r ".daily.temperature_2m_min[$i] // \"N/A\"")
|
||||
maxTemp=$(echo "$weatherData" | jq -r ".daily.temperature_2m_max[$i] // \"N/A\"")
|
||||
code=$(echo "$weatherData" | jq -r ".daily.weather_code[$i] // 0")
|
||||
|
||||
# Format date to day of week
|
||||
local dayName
|
||||
if date --version &>/dev/null; then
|
||||
# GNU date
|
||||
dayName=$(date -d "$dateStr" '+%A' 2>/dev/null)
|
||||
else
|
||||
# BSD date (macOS)
|
||||
dayName=$(date -j -f '%Y-%m-%d' "$dateStr" '+%A' 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [[ -z "$dayName" ]]; then
|
||||
dayName="$dateStr"
|
||||
fi
|
||||
|
||||
local forecastConditions="${weatherCodes[$code]:-Unknown}"
|
||||
|
||||
if [[ "$minTemp" != "N/A" && "$maxTemp" != "N/A" ]]; then
|
||||
forecastParts+=("${dayName}: ${minTemp}°F to ${maxTemp}°F, ${forecastConditions}")
|
||||
fi
|
||||
|
||||
((i++))
|
||||
|
||||
# Only show 3 days
|
||||
if [[ $i -ge 3 ]]; then
|
||||
break
|
||||
fi
|
||||
done <<< "$dates"
|
||||
|
||||
if [[ ${#forecastParts[@]} -gt 0 ]]; then
|
||||
local IFS=" | "
|
||||
echo "Forecast: ${forecastParts[*]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main command logic
|
||||
subcommand="${1:-}"
|
||||
|
||||
# If subcommand is the module name itself (w or weather), treat as no argument
|
||||
if [[ "$subcommand" == "w" || "$subcommand" == "weather" ]]; then
|
||||
subcommand=""
|
||||
fi
|
||||
|
||||
location="${*}"
|
||||
case "$subcommand" in
|
||||
set)
|
||||
# Set user's location
|
||||
shift
|
||||
if [[ $# -eq 0 ]]; then
|
||||
msg "$channelName" "$name: Usage: weather set <location>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Convert spaces to +.
|
||||
location="${location//[[:space:]]/+}"
|
||||
location="$*"
|
||||
|
||||
# Validate location length
|
||||
if [[ ${#location} -gt 100 ]]; then
|
||||
msg "$channelName" "$name: Location is too long (max 100 characters)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# c Weather condition,
|
||||
# C Weather condition textual name,
|
||||
# h Humidity,
|
||||
# t Temperature (Actual),
|
||||
# f Temperature (Feels Like),
|
||||
# w Wind,
|
||||
# l Location,
|
||||
# m Moonphase ðð,
|
||||
# M Moonday,
|
||||
# p precipitation (mm),
|
||||
# o Probability of Precipitation,
|
||||
# P pressure (hPa),
|
||||
|
||||
# D Dawn*,
|
||||
# S Sunrise*,
|
||||
# z Zenith*,
|
||||
# s Sunset*,
|
||||
# d Dusk*.
|
||||
# Geocode the location
|
||||
geocodeResult=$(geocode_location "$location")
|
||||
if [[ $? -ne 0 || -z "$geocodeResult" ]]; then
|
||||
msg "$channelName" "$name: Could not find that location. Please try a different search term."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
format="%c|%C|%h|%t|%f|%w|%l|%m|%M|%p|%o|%P|%D|%S|%z|%s|%d"
|
||||
argList="${format//%/}"
|
||||
argList="${argList//|/ }"
|
||||
weatherString="$(curl -s https://wttr.in/${location}?format="${format}")"
|
||||
# Parse result: fullAddress|lat|lon|formattedLocation
|
||||
fullAddress=$(echo "$geocodeResult" | cut -d'|' -f1)
|
||||
lat=$(echo "$geocodeResult" | cut -d'|' -f2)
|
||||
lon=$(echo "$geocodeResult" | cut -d'|' -f3)
|
||||
formattedLocation=$(echo "$geocodeResult" | cut -d'|' -f4)
|
||||
|
||||
i=1
|
||||
declare -A weatherInfo
|
||||
for j in $argList ; do
|
||||
weatherInfo[$j]="$(echo "${weatherString}" | cut -d '|' -f $i)"
|
||||
((i++))
|
||||
done
|
||||
# Save user location
|
||||
save_user_location "$name" "$fullAddress" "$lat" "$lon" "$formattedLocation"
|
||||
|
||||
# Format times to 12 hour format.
|
||||
for i in S D z s d ; do
|
||||
weatherInfo[$i]="$(date '+%r' --date="${weatherInfo[$i]}")"
|
||||
done
|
||||
msg "$channelName" "$name: Your location has been set to: ${formattedLocation}"
|
||||
;;
|
||||
|
||||
message="${weatherInfo[l]}: ${weatherInfo[t]} and ${weatherInfo[C]}"
|
||||
if [[ "${weatherInfo[t]}" == "${weatherInfo[f]}" ]]; then
|
||||
message+=". "
|
||||
else
|
||||
message+=" with a real feel of ${weatherInfo[f]}. "
|
||||
fi
|
||||
message+="Wind: ${weatherInfo[w]} "
|
||||
if [[ "${weatherInfo[p]}" != "0.0mm" ]]; then
|
||||
message+=" Precipitation: ${weatherInfo[p]} "
|
||||
fi
|
||||
if [[ -n "${weatherInfo[o]}" ]]; then
|
||||
message+="Chance of precipitation ${weatherInfo[o]} "
|
||||
fi
|
||||
message+="Humidity: ${weatherInfo[h]}. "
|
||||
message+="Sunrise: ${weatherInfo[S]}, Sunset: ${weatherInfo[s]}."
|
||||
del|delete)
|
||||
# Delete user's location
|
||||
delete_user_location "$name"
|
||||
msg "$channelName" "$name: Your location has been deleted."
|
||||
;;
|
||||
|
||||
msg "$channelName" "$name: ${message//+/ }"
|
||||
*)
|
||||
# Show weather (default action)
|
||||
if [[ -n "$subcommand" ]]; then
|
||||
# Weather for specified location
|
||||
location="$*"
|
||||
|
||||
# Validate location length
|
||||
if [[ ${#location} -gt 100 ]]; then
|
||||
msg "$channelName" "$name: Location is too long (max 100 characters)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Geocode the location
|
||||
geocodeResult=$(geocode_location "$location")
|
||||
if [[ $? -ne 0 || -z "$geocodeResult" ]]; then
|
||||
msg "$channelName" "$name: Could not find that location. Please try a different search term."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse result
|
||||
fullAddress=$(echo "$geocodeResult" | cut -d'|' -f1)
|
||||
lat=$(echo "$geocodeResult" | cut -d'|' -f2)
|
||||
lon=$(echo "$geocodeResult" | cut -d'|' -f3)
|
||||
formattedLocation=$(echo "$geocodeResult" | cut -d'|' -f4)
|
||||
|
||||
locationDisplay="$formattedLocation"
|
||||
else
|
||||
# Weather for user's saved location
|
||||
userLocation=$(get_user_location "$name")
|
||||
if [[ -z "$userLocation" ]]; then
|
||||
msg "$channelName" "$name: You have not set a location. Use 'weather set <location>' to save your location, or 'weather <location>' to check weather for a specific location."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse user location: USER|name|location|lat|lon|formatted
|
||||
fullAddress=$(echo "$userLocation" | cut -d'|' -f3)
|
||||
lat=$(echo "$userLocation" | cut -d'|' -f4)
|
||||
lon=$(echo "$userLocation" | cut -d'|' -f5)
|
||||
formattedLocation=$(echo "$userLocation" | cut -d'|' -f6)
|
||||
|
||||
# If no formatted location stored (old format), use full address
|
||||
if [[ -z "$formattedLocation" ]]; then
|
||||
formattedLocation="$fullAddress"
|
||||
fi
|
||||
|
||||
locationDisplay="$formattedLocation"
|
||||
fi
|
||||
|
||||
# Get weather data
|
||||
weatherData=$(get_weather "$lat" "$lon")
|
||||
if [[ $? -ne 0 || -z "$weatherData" ]]; then
|
||||
msg "$channelName" "$name: Could not retrieve weather data. Please try again later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Format and send current weather
|
||||
weatherMessage=$(format_weather "$weatherData" "$locationDisplay")
|
||||
msg "$channelName" "$name: ${weatherMessage}"
|
||||
|
||||
# Format and send forecast
|
||||
forecastMessage=$(format_forecast "$weatherData")
|
||||
if [[ $? -eq 0 && -n "$forecastMessage" ]]; then
|
||||
msg "$channelName" "$name: ${forecastMessage}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -1,5 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -f functions.sh ] && source functions.sh
|
||||
|
||||
joke="$(curl -s https://api.yomomma.info | sed -e 's/{"joke":"//' -e 's/"}$//')"
|
||||
joke="${joke//[[:space:]]/ }"
|
||||
msg "$2" "$joke"
|
||||
# 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
|
||||
Reference in new issue
Block a user