beatsaber-ntfy/beatsaber-ntfy.sh
2024-12-13 13:59:58 +01:00

122 lines
3.8 KiB
Bash

#!/bin/bash
# shellcheck disable=SC2154,SC2034
# beatsaber-ntfy, a bash script (with jq, bc, and curl) to push notifications to a ntfy.sh server on beatsaber leaderboard statistics updates
# Global configuration
INTERVAL=3600
# Set to empty string to disable
SCORESABER_DIR="./scoresaber-players/"
BEATLEADER_DIR="./beatleader-players/"
# Variables taken from SS/BL API
PLAYER_STATS_VARS="name country pp rank countryRank banned inactive"
# Settings stored per player
SETTINGS_VARS="NTFY_URL COUNTRY_THRESHOLD RANK_THRESHOLD PP_THRESHOLD"
stats_routine() {
( if [[ -n "$SCORESABER_DIR" ]]; then
cd "$SCORESABER_DIR" || exit 1
for PLAYER in *; do
update_player_stats "$PLAYER" "ScoreSaber" "https://scoresaber.com/api/player/$PLAYER/basic" "https://scoresaber.com/u/$PLAYER"
done
fi )
( if [[ -n "$BEATLEADER_DIR" ]]; then
cd "$BEATLEADER_DIR" || exit 1
for PLAYER in *; do
update_player_stats "$PLAYER" "BeatLeader" "https://api.beatleader.xyz/player/$PLAYER" "https://beatleader.xyz/u/$PLAYER"
done
fi )
}
update_player_stats() {
# Name arguments
PLAYER=$1
TITLE=$2
API_URL=$3
PROFILE_URL=$4
# If the API fails, don't continue
echo "Fetching stats for $PLAYER on $TITLE"
if ! UPDATED_STATS="$(curl -s --fail-with-body "$API_URL")"; then
echo "Failed to gather stats for $PLAYER on $TITLE due to:"
echo "$UPDATED_STATS"
return
fi
# Get the old playerdata
# shellcheck disable=SC1090
source "$PLAYER"
# Set the new playerdata
for VAR in $PLAYER_STATS_VARS; do
declare "UPD_${VAR}=$(echo "$UPDATED_STATS" | jq -r ".$VAR")"
done
# If there are no known stats, update them without sending a notification
if [[ -z "$rank" ]]; then
INIT_STATS=true
else
INIT_STATS=false
fi
# Calculate stat differences
RANK_DIFF=$(( rank - UPD_rank ))
COUNTRYRANK_DIFF=$(( countryRank - UPD_countryRank ))
PP_DIFF=$(bc <<< "$UPD_pp - $pp")
# Check if criteria for notification are met
SEND_NOTIF=false
if [[ ${RANK_DIFF#-} -gt ${RANK_THRESHOLD} ]]; then SEND_NOTIF=true; fi
if [[ ${COUNTRYRANK_DIFF#-} -gt ${COUNTRYRANK_THRESHOLD} ]]; then SEND_NOTIF=true; fi
if [[ 1 -eq "$(bc <<< "${PP_DIFF#-} > ${PP_THRESHOLD}")" ]]; then SEND_NOTIF=true; fi
if [[ $inactive != "$UPD_inactive" ]]; then SEND_NOTIF=true; fi
if [[ $banned != "$UPD_banned" ]]; then SEND_NOTIF=true; fi
if ! $SEND_NOTIF; then
return
fi
# Add "+" to stats that increased
if [[ ${RANK_DIFF} -gt 0 ]]; then RANK_DIFF="+$RANK_DIFF"; fi
if [[ ${COUNTRYRANK_DIFF} -gt 0 ]]; then COUNTRYRANK_DIFF="+$COUNTRYRANK_DIFF"; fi
if [[ 1 -eq "$(bc <<< "${PP_DIFF} > 0")" ]]; then PP_DIFF="+$PP_DIFF"; fi
# Create the notification text
NOTIF="Global: $rank > $UPD_rank ($RANK_DIFF)
Country ($UPD_country): $countryRank > $UPD_countryRank ($COUNTRYRANK_DIFF)
PP: $pp > $UPD_pp ($PP_DIFF)"
if [[ $inactive != "$UPD_inactive" ]]; then
NOTIF="$NOTIF
Inactive status has changed: $inactive > $UPD_inactive"
fi
if [[ $banned != "$UPD_banned" ]]; then
NOTIF="$NOTIF
Banned status has changed: $banned > $UPD_banned"
fi
# Send the notification
if ! $INIT_STATS; then
echo "${UPD_name}'s $TITLE stats have changed, sending notification"
if ! NOTIF_RESPONSE=$(curl -s --fail-with-body -X POST -H "Title: $UPD_name's $TITLE Stats" -H "Click: $PROFILE_URL" -d "$NOTIF" "$NTFY_URL"); then
echo "Failed to send notification:"
echo "$NOTIF_RESPONSE"
# If we can't notify the user, don't update the stats file.
# Ensures notifications are accurate after ntfy server is fixed.
return
fi
fi
# Recreate the player file
NEW_PLAYER=""
for VAR in $SETTINGS_VARS; do
NEW_PLAYER="$NEW_PLAYER
$VAR=$(eval "echo \$$VAR")"
done
for VAR in $PLAYER_STATS_VARS; do
NEW_PLAYER="$NEW_PLAYER
$VAR=\"$(eval "echo \"\$UPD_$VAR\"")\""
done
echo "${NEW_PLAYER:1}" > "$PLAYER"
}
while true; do
stats_routine
sleep "$INTERVAL"
done