#!/bin/bash ################################################################################ # Authors: # [@cel](@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519) # [@Fred](@9BbJwPDjcyIqrOUPNn0nJZBduWdIrpMk3Cjz5MP361s=.ed25519) # [@Boris](@l5nYExWYIgDLV6BYHOJPoI97jIUyTdSm8CTLpQ0XeOg=.ed25519) # Version: 1.0 # License: AGPL-3.0 (https://choosealicense.com/licenses/agpl-3.0/) ########################################################################################### # PREVENT DOUBLE PAYEMENT # ADD Ğ1 Layer 10 LOVE to message writer you like ! ############################################################################################ # Let's get Ğ1 public and private keys g1pub=$(cat ~/.ssb/secret.dunikey | grep "pub" | cut -d ' ' -f 2) g1priv=$(cat ~/.ssb/secret.dunikey | grep "sec" | cut -d ' ' -f 2) # SSB pubkey ssbpub=$(cat ~/.ssb/secret | grep public\" | cut -d ' ' -f 4 | cut -d '.' -f 1 | sed s/\"//g) amountPerLikeInUD="0.05" bold=$(tput bold) normal=$(tput sgr0) ssbMaxSize=8192 ssbMsgHeadersSize=5810 # Here is a wild guess! ############################################################################################ #### CHECK LIKE AND SEND LOVE # Let's get Ğ1 account balance echo "" echo -e "${bold}Welcome${normal} to the Ğ1/SSB-like microdonation system!\n" sleep 1 echo "MMMMMMMMMMMMMNk;'cdxxd:,c0WMMMMMMMMMMMMM MMMMMMMMMMMMMNx,. .;kWMMMMMMMMMMMMM MMMMMMMMMMMMMMMNOdlccld0NMMMMMMMMMMMMMMM MMMMMMMMMMMWXko:,'....',:okXWMMMMMMMMMMM MMMMMMMMMNk:. .cOWMMMMMMMMM MMMMMMMW0: .c0MMMMMMMM" sleep 1 echo "MMMMMMWk. 'lxkOOkdc' .cOWMMMMMMM MMMMMMO' 'kNMMMMMMMMNxcoOXWMMMMMMMMM MMMMMNl '0MMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMX; cNMMMMMMMNOkkkkkkkkkkONMMMMM MMMMMNc ;XMMMMMMMNd' .OMMMMM MMMMMWx. cKMMMMMMMWKc. .OMMMMM MMMMMMNo. .lkKXNNXKkc. .OMMMMM" sleep 1 echo "MMMMMMMNd. ...... .OMMMMM MMMMMMMMWKl. 'c:. .OMMMMM MMMMMMMMMMWXkc,.. ..,lkXWWO:;OMMMMM MMMMMMMMMMMMMMWX0OxddxO0XWMMMMMMWXNMMMMM MMMMMMMMMMMMMMMMNx;'',dNMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMK, '0MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMNd. .oNMMMMMMMMMMMMMMMM " sleep 1 printf "You know your SSB pubkey:\n%s\n\n" $ssbpub sleep 2 printf "...but did you know it is also a valid Ğ1 wallet?\n%s\n\n" $g1pub sleep 2 printf "Let's check the current balance of your wallet!\n\n" sleep 1 printf "I am interrogating the Ğ1 blockchain to check if anyone has already sent you Ğ1...\n\n" sleep 2 printf "A moment please...\n\n" sleep 1 silkajRelativeAmountPattern='Total\sRelative\s+=\s+(.*)\s+UD' duniter_servers[0]="duniter-g1.p2p.legal:443" duniter_servers[1]="g1.duniter.org:443" duniter_servers[2]="g1.presles.fr:443" duniter_servers[3]="balboa.altsysnet.com:10900" duniter_servers[4]="remuniter.cgeek.fr:16120" duniter_servers[5]="duniter.moul.re:443" duniter_servers[6]="77.152.31.154:20901" duniter_servers[7]="duniter.g1.1000i100.fr:443" silkajExitCode=1 i=0 while [ $silkajExitCode -ne 0 ] && [ $i -lt ${#duniter_servers[@]} ] do echo "Testing server ${duniter_servers[$i]}..." echo "" silkajOutput=$(silkaj -p "${duniter_servers[$i]}" balance $g1pub 2>/dev/null) silkajExitCode=$? ((i++)) done if [ $silkajExitCode -eq 1 ] then echo "The server did not respond well. Please try again." exit 1 fi if [[ $silkajOutput =~ $silkajRelativeAmountPattern ]] then balance="${BASH_REMATCH[1]}" else echo "Account balance wasn't found." exit 1 fi printf "You have ${bold}%s UDĞ1${normal} on your Duniter Ğ1 wallet.\n\n" "$balance" sleep 2 printf "Want to show your appreciation of your fellow butts' posts while helping spreading awareness about libre currencies?\n\n" sleep 2 # BEGIN timestamp computation self=$(sbotc whoami | jq -r .id) || exit 1 ssb_dir=~/.${ssb_appname:-ssb} id_part=$(echo "$self" | sed 's/\//_/g' | tail -c +2 | head -c 9) state_file=$ssb_dir/likes-g1-$id_part.ts current_ts=$(date -u +%s%N | cut -b1-13) if [ -s "$state_file" ] then last_ts=$(cat "$state_file") || exit 1 else last_ts=$((current_ts - 3600000)) # timestamp from 1h ago #else last_ts=null fi days_from_last_tx=$(( (current_ts - last_ts) / (24*60*60*1000) )) # END timestamp computation printf "First, let's see how much ❤ you gave lately...\n\n" sleep 1 declare -A likesNbPerAuthor declare -A likedPosts declare -A likesNbPerPost declare -A postsTimestamps declare -A excerpts totalLikesGiven=0 process_msg() { msg=$1 target_id=$(printf %s "$msg" | jq -r '.value?.content?.vote?.link') || return 1 target_msg=$(sbotc -e get "$target_id") || return 1 target_author=$(printf %s "$target_msg" | jq -r .author) || return 1 msg_content=$(printf %s "$target_msg" | jq -r .content?.text) || return 1 # beware of markdown ! msg_excerpt=${msg_content:0:10} #root_id=$(printf %s "$target_msg" | jq -r .content?.root) || return 1 #[[ $root_id = "null" ]] && root_id=$target_id } process_author() { author_id=$1 g1_author=$(echo $author_id | cut -d '.' -f 1 | cut -d '@' -f2 | base64 -d | base58) author_name=$(sbotc query.read '{"query":[{"$filter":{"value":{"author": "'"$author_id"'", "content":{"type":"about", "about": "'"$author_id"'"}}}}]}' | jq .value?.content?.name | grep -v null | tail -n 1) } authorsNb=0 i=0 messages=$(sbotc query.read '{"query":[{"$filter":{"value":{"author":"'"$self"'","content":{"type":"vote", "vote":{"expression":"Like"}},"timestamp":{"$gt":'"$last_ts"'}}}}]}') while read -r msg do priv=$(printf %s "$msg" | jq .value.content.private) if [[ $priv = true ]] then printf "Private message $priv, continue to next one\n" >&2 continue fi if ! process_msg "$msg" then msg_id=$(printf %s "$msg" | jq -r .key) printf '\nUnable to process message %s\n' "$msg_id" >&2 exit 1 fi if [[ $g1_author = $g1pub ]]; then echo "I LIKE MY MESSAGE $target_id" else ((totalLikesGiven++)) if [[ ${likesNbPerAuthor[$target_author]} -eq 0 ]] then likesNbPerAuthor[$target_author]=1 likedPosts[$target_author]="" else likesNbPerAuthor[$target_author]=$((${likesNbPerAuthor[$target_author]} + 1)) fi if [[ ${likesNbPerPost[$target_id]} -eq 0 ]] then likesNbPerPost[$target_id]=1 likedPosts[$target_author]+=$target_id likedPosts[$target_author]+="\n" else ((likesNbPerPost[$target_id]++)) fi excerpts[$target_id]=$msg_excerpt if ! postsTimestamps[$target_id]=$(printf %s "$msg" | jq -r .value.timestamp) then printf 'Unable to get message timestamp\n' >&2 exit 1 fi ((i++)) fi done < <(printf '%s\n' "$messages") if [[ $totalLikesGiven -eq 0 ]] then printf "You did not give any like during the past %s days or they have already been processed.\n\n" "$days_from_last_tx" printf "Try again in a few days.\n\n" fi printf "You gave ${bold}%s❤${normal} during the past %s days.\n\n" "$totalLikesGiven" "$days_from_last_tx" sleep 2 printf "How many UDĞ1 do you want to send per each like you gave? (default is ${bold}%s UDĞ1${normal}) " "$amountPerLikeInUD" read a echo "" tx_are_possible=0 while [[ $tx_are_possible -eq 0 ]] do amountPerLikeInUD=$a amountGiven=$(echo "$totalLikesGiven * $amountPerLikeInUD" | bc -l) tx_are_possible=$(( $(echo "$amountGiven <= $balance" | bc -l) )) if [[ $tx_are_possible -ne 0 ]] ; then newBalance=$(echo "$balance - $amountGiven" | bc -l) printf "${bold}%s UDĞ1${normal} will be given.\n\n" "$amountGiven" sleep 1 printf "After sending transactions, your new balance will be ${bold}%s UDĞ1${normal}\n\n" "$newBalance" sleep 1 printf "Press ENTER to continue: " && read printf "\n" else printf "You don't have enough UDĞ1 to send all transactions.\n\n" sleep 1 printf "${bold}%s UDĞ1${normal} are needed.\n\n" "$amountGiven" sleep 1 printf "Try again with a different amount per like.\n\n" maxAmountPerLike=$(awk -vp=$balance -vq=$totalLikesGiven 'BEGIN{printf "%.2f" ,p / q}') sleep 1 printf "Maximum amount per like possible: ${bold}%s UDĞ1${normal}\n\n" "$maxAmountPerLike" sleep 1 printf "How many UDĞ1 do you want to send per each like you gave? " read a echo "" fi done # Let's construct thank you message and send transactions! n=0 outputs[$n]="" outputs[$n]+=$(printf "Huge thanks to the ScuttleButt community for all the fascinating posts you allowed me to read in the past %s days." "$days_from_last_tx") outputs[$n]+="\n\nAs a means to thank you further, I have just sent you #Ğ1 libre money.\n\n" outputs[$n]+="These messages, though they might feel spammy (sorry) are also a way for the Ğ1 community to spread awareness about [libre currencies](https://libre-currency.org/) so we can build #resilience at every level.\n\n" outputs[$n]+="You can learn how to spend your freshly earned money at [https://git.p2p.legal/Axiom-Team/ssb-g1like](https://git.p2p.legal/Axiom-Team/ssb-g1like)\n\n" outputs[$n]+="Below is the list of SSB users whose content I liked recently, and the amount each one was given:\n\n" tableHeaders='| thanks to | for their posts | given |\n' tableHeaders+='| --- | --- | ---- |\n' outputs[$n]+=$tableHeaders for author_id in ${!likesNbPerAuthor[@]} do process_author $author_id # (Legacy) saving authors we have already mentionned in a message likedAuthorsFile=$ssb_dir/db/g1likes if [ ! -f $likedAuthorsFile ]; then touch $likedAuthorsFile fi if ! grep -Fxq $author_id $likedAuthorsFile; then echo $author_id >> $likedAuthorsFile fi author_amount=$(bc <<< "${likesNbPerAuthor[$author_id]} * $amountPerLikeInUD") newLine='' newLine+=$(printf "| [@%s](%s) " "${author_name:1:-1}" "$author_id") newLine+="| " posts=${likedPosts[$author_id]} thisAuthorLikedPosts=( ${posts//\\n/ } ) firstPost=1 for post_id in ${thisAuthorLikedPosts[@]} do if [[ $firstPost ]] then firstPost=0 else newLine+=", " fi newLine+=$(printf " %s❤" "${likesNbPerPost[$post_id]}") newLine+=$(printf "[%s](%s)" "${post_id:0:9}" "$post_id") newLine+=$(printf "[\`%s\`](%s)" "${excerpts[$post_id]}" "$post_id") done newLine+=$(printf "| %s UDĞ1 " $author_amount) newLine+="|\n" messageSize=$(printf "%s%s" "${outputs[$n]}" "$newLine" | wc -c) totalSize=$((messageSize + ssbMsgHeadersSize)) if [[ $totalSize -gt $ssbMaxSize ]] then outputs[$n]+="For message size reasons, the rest of the list had to be displayed below, in the following answer:" ((n++)) outputs[$n]+=$tableHeaders fi outputs[$n]+=$newLine #printf '%s\n' "silkaj -af --file ~/.ssb/secret.dunikey tx --outputs[$n] $g1_author --amountUD $author_amount --comment "Thx for your cool posts on ScuttleButt" #silkaj -p "$duniter_server" -af --file ~/.ssb/secret.dunikey tx --outputs[$n] $g1_author --amountUD $author_amount --comment "Thx for your cool posts on ScuttleButt" -y 2>/dev/null printf "\n${bold}%s UDĞ1${normal} sent to %s!\n\n" "$author_amount" "${author_name:1:-1}" # Let's save the timestamp of the last processed message if ! echo "${postsTimestamps[$target_id]}" > "$state_file"~ then printf 'Unable to write to backup state file.\n' >&2 exit 1 fi #if ! mv "$state_file"~ "$state_file" #then # msg_id=$(printf %s "$msg" | jq -r .key) # printf 'Unable to write to state file. Update state file manually to prevent %s from being processed twice.\n' "$msg_id" >&2 # exit 1 #fi #sleep 20 # DO NOT OVER CHARGE DUNITER done printf "\n%s UDĞ1 sent to %s butts!\n\n" "$amountGiven" "${#likesNbPerAuthor[@]}" # Let's publicly thank everyone! #echo -e "${outputs[$n]}" # the following produces error: # "sbotc: unexpected end of parent stream" # must be a non-escaped quote problem... #thank_you_msg=$(printf "%q" "${outputs[$n]}") #sbotc publish '{"type":"post","text":"'"$thank_you_msg"'"}' 2>&1>/dev/null printf "What now ?\n\n" sleep 1 date=$(date -u +%Y-week-%W) if [[ ${#outputs[@]} -eq 1 ]] then msg_filename=thank-your-butts-$date echo -e ${outputs[$n]} > ~/$msg_filename else for i in ${!outputs[@]} do part=$((i + 1)) msg_filename=thank-your-butts-$date echo -e ${outputs[$i]} > ~/$msg_filename-part-$part.md done fi printf "A surprise is awaiting in your home dir (~).\n\n" sleep 2 if [[ ${#outputs[@]} -eq 1 ]] then printf "It's a file.\n\n" sleep 2 printf "It's called $msg_filename.md\n\n" else printf "It's %s files.\n\n" "${#outputs[@]}" sleep 2 printf "The first one is called $msg_filename-part-1.md.\n\n" fi sleep 2 printf "Customize it to your needs to thank you fellow butts publicly and help spread awareness about libre currencies :-)\n\n" sleep 3 printf "Then delete it.\n\n" sleep 2 printf "...because it won't self-destruct, haha :D \n\n"