├── run └── .placeholder ├── tmb-150.png ├── tmb-580.png ├── scripts ├── unused │ ├── README.md │ ├── viktor │ ├── otsusta │ ├── coop │ ├── piibel │ ├── ilm │ ├── eki │ ├── koroona │ ├── v6tame │ ├── plaan │ ├── reede │ ├── kiida │ ├── astral │ ├── dict │ └── solva ├── pong ├── disks ├── ping ├── motd ├── top ├── datetime ├── users ├── pick ├── backup ├── platform ├── ps ├── cputemp ├── ddg ├── tesla ├── firewall ├── web ├── btc ├── s2f ├── hn ├── wake ├── eth ├── help ├── alert ├── check ├── totp ├── update ├── twitter ├── mn ├── restart ├── weather ├── rss ├── tides └── hello ├── .gitignore ├── tiny-matrix-bot.service ├── LICENSE ├── tiny-matrix-bot.cfg.sample ├── crontab-example ├── tmb.svg ├── tiny-matrix-bot.cfg.feature-rich.sample ├── tiny-matrix-bot-send-msg.sh ├── README.md └── tiny-matrix-bot.py /run/.placeholder: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tmb-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/8go/tiny-matrix-bot/HEAD/tmb-150.png -------------------------------------------------------------------------------- /tmb-580.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/8go/tiny-matrix-bot/HEAD/tmb-580.png -------------------------------------------------------------------------------- /scripts/unused/README.md: -------------------------------------------------------------------------------- 1 | More example scripts, both bash as well as Python 3. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | matrix_client 2 | run/* 3 | !run/.placeholder 4 | tiny-matrix-bot.cfg 5 | -------------------------------------------------------------------------------- /scripts/pong: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^!?pong(!|\?)?$' 5 | exit 0 6 | fi 7 | 8 | # shellcheck disable=SC2154 9 | if [ -n "$__reply" ]; then 10 | echo "$__reply" 11 | else 12 | echo 'P I N G' 13 | fi 14 | -------------------------------------------------------------------------------- /scripts/disks: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^disks$|^disk$|^full$|^space$' 5 | exit 0 6 | fi 7 | 8 | du -hs "$HOME" 2>>/dev/null 9 | echo "=========================" 10 | df -h 2>>/dev/null 11 | 12 | #if [ -n "$__reply" ] 13 | #then 14 | # echo "$__reply" 15 | #else 16 | # echo 'P O N G' 17 | #fi 18 | -------------------------------------------------------------------------------- /scripts/unused/viktor: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^!viktor\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 0 9 | fi 10 | 11 | arg="$( echo "$@" | sed "s/$regex//I" )" 12 | 13 | if [ -z "$arg" ] 14 | then 15 | exit 1 16 | fi 17 | 18 | echo "Viktor Vassiljev: $arg olemine pole ainult amet, see on diagnoos elu lõpuni" 19 | -------------------------------------------------------------------------------- /scripts/ping: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ] 4 | then 5 | echo '^!?ping(!|\?)?$' # this regular expressions decides when this bot script is triggered 6 | exit 0 7 | fi 8 | 9 | # the __reply variable is set or can be set in the bot config file 10 | if [ -n "$__reply" ] 11 | then 12 | echo "$__reply" 13 | else 14 | echo 'P O N G' 15 | fi 16 | -------------------------------------------------------------------------------- /scripts/motd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo 'motd|^!?motd.*$' 5 | exit 0 6 | fi 7 | 8 | if [ -f /etc/motd ]; then 9 | cat /etc/motd 10 | else 11 | echo "There is no message of the day on your system. So, be happpy." 12 | fi 13 | 14 | #if [ -n "$__reply" ] 15 | #then 16 | # echo "$__reply" 17 | #else 18 | # echo 'P O N G' 19 | #fi 20 | -------------------------------------------------------------------------------- /scripts/unused/otsusta: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^!(otsusta|vali|decide|pick)\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 0 9 | fi 10 | 11 | arg="$( echo "$@" | sed -r "s/$regex//I" )" 12 | 13 | if [ -z "$arg" ] 14 | then 15 | exit 1 16 | fi 17 | 18 | printf 'hmm...\n\n%s\n' \ 19 | "$( echo "$arg" | sed -r 's/(\s+(ja|või|and|or)\s+)/\n/gI' | shuf -n1 )" 20 | -------------------------------------------------------------------------------- /tiny-matrix-bot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=tiny-matrix-bot 3 | 4 | [Service] 5 | User=tiny-matrix-bot 6 | Group=users 7 | Environment=PYTHONUNBUFFERED=1 8 | # adjust path to fit your config and setup 9 | ExecStart=/home/tiny-matrix-bot/tiny-matrix-bot/tiny-matrix-bot.py 10 | ExecStop=/bin/kill -9 $MAINPID 11 | Restart=on-failure 12 | RestartSec=30 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /scripts/top: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^top$|^top .*$' 5 | exit 0 6 | fi 7 | 8 | echo "Top 5 CPU consumers:" 9 | #ps -eo %cpu,pid,ppid,cmd --sort=-%cpu | head 10 | ps -eo %cpu,cmd --sort=-%cpu --cols 40 | head -n 5 11 | echo "" 12 | echo "Top 5 RAM consumers:" 13 | #ps -eo %mem,pid,ppid,cmd --sort=-%mem | head 14 | ps -eo %mem,cmd --sort=-%mem --cols 40 | head -n 5 15 | 16 | #if [ -n "$__reply" ] 17 | #then 18 | # echo "$__reply" 19 | #else 20 | # echo 'P O N G' 21 | #fi 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /scripts/datetime: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^date$|^time$|^tiempo$|^hora$|^temps$|^heure$|^heures$|^datum$|^zeit$' 5 | exit 0 6 | fi 7 | 8 | echo -n "Server time: " 9 | date 10 | echo -n "Los Angeles: " 11 | TZ='America/Los_Angeles' date 12 | echo -n "Paris/Madrid: " 13 | TZ='Europe/Madrid' date 14 | echo -n "Lima: " 15 | TZ='America/Lima' date 16 | echo -n "Melbourne: " 17 | TZ='Australia/Melbourne' date 18 | 19 | #if [ -n "$__reply" ] 20 | #then 21 | # echo "$__reply" 22 | #else 23 | # echo 'P O N G' 24 | #fi 25 | -------------------------------------------------------------------------------- /tiny-matrix-bot.cfg.sample: -------------------------------------------------------------------------------- 1 | [tiny-matrix-bot] 2 | base_url = https://matrix.example.com 3 | token = SuperSecretToken 4 | #run_path = run 5 | #scripts_path = scripts 6 | #enabled_scripts = ping 7 | #inviter = :example\.com$ 8 | 9 | #[ping] 10 | #whitelist = \!rOomId1:example\.com 11 | #blacklist = (@spammer|\!roOMid2):example\.com 12 | ## reply is optional 13 | #reply = PONG! 14 | ## format can be: text, html, or code. If not set it is "text" by default. 15 | #format = text 16 | ## other arguments can be passed into script as well if desired 17 | #foo = something 18 | -------------------------------------------------------------------------------- /scripts/users: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # PUT YOUR CORRECT ACCESS TOKEN HERE, THIS ACCESS TOKEN MUST HAVE ADMIN RIGHTS 4 | # see documentation how to add admin rights to normal access token 5 | MYACCESSTOKENWITHADMINPERMISSIONS="VERY-LONG-CRYTOGRAHIC-STRING-THAT-IS-YOUR-ACCESS-TOKEN-WITH-ADMIN-PERMISSIONS" 6 | MYHOMESERVER="https://matrix.example.com" 7 | 8 | 9 | echo "List of at most 100 users:" 10 | curl --silent --header "Authorization: Bearer $MYACCESSTOKENWITHADMINPERMISSIONS" "$MYHOMESERVER/_synapse/admin/v2/users?from=0&limit=100&guests=false" | 11 | jq '.users[] | .name' | tr -d '"' 12 | 13 | -------------------------------------------------------------------------------- /crontab-example: -------------------------------------------------------------------------------- 1 | # This is just a tiny example of a few lines one could add to the cron file via the command "crontab -e" 2 | # in order to have some automated checks, status updates or similar. 3 | 4 | # PS Summary 5 | # Every day, once a day at noon, send a message as bot to a bot room, e.g. to an admin room, with CPU/RAM/DISK usage. 6 | # The room is configured in the tiny-matrix-bot-send-msg.sh script 7 | # Adjust the following line to fit YOUR paths! 8 | 0 12 * * * /usr/bin/echo -e "Cron msg:\\n$(/home/YOUR_PATH_HERE/tiny-matrix-bot/scripts/ps)" | /home/YOUR_PATH_HERE/tiny-matrix-bot/tiny-matrix-bot-send-msg.sh 9 | 10 | -------------------------------------------------------------------------------- /scripts/pick: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo 'pick|pick .*|^pick .*$|^choose .*|^decide .*|^select .*$' 5 | exit 0 6 | fi 7 | 8 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 9 | #echo "pick: arguments: \"$args\"" 10 | if [ "$args" == "" ]; then 11 | echo "You must give me something to chose from. Try \"pick pizza or hamburger or salad\"." 12 | exit 0 13 | fi 14 | printf 'hmm... let me think, tough choice, how about: %s\n' \ 15 | "$(echo "$args" | sed -r 's/(,|\.|[[:punct:]]|\s+(et|ou|und|oder|y|o|and|or)\s+)/\n/gI' | sed '/^[[:space:]]*$/d' | shuf -n1 | sed 's/^[ \t]*//;s/[ \t]*$//')" 16 | -------------------------------------------------------------------------------- /scripts/backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^backup$|^backup .*$' 5 | exit 0 6 | fi 7 | 8 | echo "Not implemented. This will fail. You need to change this code here." 9 | 10 | # adjust this code 11 | # add your backup code her: 12 | # e.g. something like this: 13 | 14 | MYBACKUPDIR=/foo/bar/Backup 15 | MYBACKUPFILE="$MYBACKUPDIR/mybackupfile.$(date +"%y%m%d").tar" 16 | tar -hcf "$MYBACKUPFILE" /foo/bar/Documents/ /foor/bar/Scripts/ /foo/bar/and-so-on 17 | tar tvf "$MYBACKUPFILE" 18 | echo "" 19 | echo "Existing backup files are:" 20 | ls -lGh "$MYBACKUPDIR" 21 | 22 | #if [ -n "$__reply" ] 23 | #then 24 | # echo "$__reply" 25 | #else 26 | # echo 'P O N G' 27 | #fi 28 | -------------------------------------------------------------------------------- /scripts/platform: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import platform 4 | import sys 5 | import os 6 | 7 | regex = '^platform|^platform .*' 8 | 9 | if 'CONFIG' in os.environ: 10 | print(regex) 11 | sys.exit(0) 12 | 13 | 14 | def linux_distribution(): 15 | try: 16 | return platform.linux_distribution() 17 | except BaseException: 18 | return "N/A" 19 | 20 | 21 | print("""Python version: %s 22 | linux_distribution: %s 23 | system: %s 24 | machine: %s 25 | platform: %s 26 | uname: %s 27 | version: %s 28 | """ % ( 29 | sys.version.split('\n'), 30 | linux_distribution(), 31 | platform.system(), 32 | platform.machine(), 33 | platform.platform(), 34 | platform.uname(), 35 | platform.version(), 36 | )) 37 | -------------------------------------------------------------------------------- /scripts/ps: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^ps$|^ps .*$' 5 | exit 0 6 | fi 7 | 8 | free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f %%)\n", $3,$2,$3*100/$2 }' 9 | df -h | awk '$NF=="/"{printf "Disk Usage: %d/%dGB (%s)\n", $3,$2,$5}' 10 | # top -bn1 | grep load | awk '{printf "CPU Load: %.2f\n", $(NF-2)}' 11 | CPU=$(top -bn1 | head -n 1 | cut -d "," -f 5 | tr -d " ") # last 5 min CPU load average as "0.03" for 3% 12 | CPUP=$(LC_ALL=en_US.UTF-8 printf "%'.0f" "$(echo "scale=10; $CPU * 100.0" | bc -l)") 13 | echo "CPU Load: $CPUP %" 14 | echo -n "CPU Temperature: " 15 | # assume 'ps' and 'cputemp' are in same directory 16 | $(dirname "${0}")/cputemp 17 | 18 | #if [ -n "$__reply" ] 19 | #then 20 | # echo "$__reply" 21 | #else 22 | # echo 'P O N G' 23 | #fi 24 | -------------------------------------------------------------------------------- /scripts/unused/coop: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^!(coop|konsum)\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 1 9 | fi 10 | 11 | arg="$( echo "$@" | sed -r "s/$regex//I" )" 12 | 13 | keyword="$( printf "%s" "$arg" | sed 's/\s/+/g' )" 14 | 15 | json="$( curl -s "https://ecoop.ee/api/v1/products?ordering=relevancy&show_search=1&keyword=$keyword" )" 16 | 17 | results="$( printf '%s' "$json" | jq -r '.results[] | "\(.sell_price) € \(.name)"' )" 18 | 19 | count="$( printf '%s' "$json" | jq -r '.count' )" 20 | 21 | if [ "$count" -eq 0 ] 22 | then 23 | echo '?' 24 | else 25 | echo "$results" | head -8 26 | 27 | if [ "$count" -gt 8 ] 28 | then 29 | printf "%s toodet: " "$count" 30 | fi 31 | 32 | echo "https://ecoop.ee/et/otsing/?ordering=relevancy&otsing=$keyword" \ 33 | | sed 's/\s/+/g' 34 | fi 35 | -------------------------------------------------------------------------------- /scripts/cputemp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^cpu$|^temp$|^temperature|celsius|^!?cputemp(!|\?)?$' 5 | exit 0 6 | fi 7 | 8 | # single Core 9 | # CELSIUS=$(cat /sys/class/thermal/thermal_zone0/temp) && echo "scale=2; $CELSIUS/1000" | bc | tr "\n" " " && echo "Celsius" 10 | 11 | # multi-core CPU 12 | cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | while read -r p; do 13 | # echo "$p" 14 | CELSIUS="$p" && echo "scale=2; $CELSIUS/1000" | bc | tr "\n" " " && echo "Celsius" 15 | done 16 | if [ "$(cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | wc -l)" == "0" ]; then 17 | echo "No CPU temperature information found." 18 | fi 19 | exit 0 20 | 21 | # The __reply env variable set in the config file is not used in this script 22 | #if [ -n "$__reply" ] 23 | #then 24 | # echo "$__reply" 25 | #else 26 | # echo 'P O N G' 27 | #fi 28 | -------------------------------------------------------------------------------- /scripts/ddg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^ddg$|^ddg .*$|^duck$|^duck .*$|^duckduckgo$|^duckduckgo .*$|^search$|^search .*$' 5 | exit 0 6 | fi 7 | 8 | # ddgr must be installed 9 | type ddgr >/dev/null 2>&1 || { 10 | echo "For duckduckgo search to work you must first install the packge \"ddgr\" on the server." 11 | exit 0 12 | } 13 | 14 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 15 | #echo "ddg: arguments: \"$args\"" 16 | if [ "$args" == "" ]; then 17 | echo "You must be looking for something. Try \"ddg matrix news\"." 18 | exit 0 19 | fi 20 | 21 | ddgr --np -n=10 -C "$args" 22 | 23 | exit 0 24 | 25 | # The argument __reply from the config file ist not used in this script. 26 | #if [ -n "$__reply" ] 27 | #then 28 | # echo "$__reply" 29 | #else 30 | # echo 'P O N G' 31 | #fi 32 | -------------------------------------------------------------------------------- /scripts/tesla: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo 'model3.*|tesla|^tesla .*$' 5 | exit 0 6 | fi 7 | 8 | echo " Sorry master. I am resting. Better take a walk, that is healthier anyway... 9 | Not now, I am charging. 10 | Can't do. My batteries are low. 11 | Not today. A Vaseline truck crashed on the highway and cars were sliding all over the place. 12 | Uber surge pricing is 4.6x right now 13 | It’s raining! 14 | Omg, I totally forgot we had plans 15 | I am in the middle of watch a YouTube film, don't bother me now! 16 | I can’t find my own car keys :( 17 | You are so lazy! 18 | Please not today. It is my day off! 19 | Don't you have another car? 20 | I can't hear you. Speak louder." | shuf -n1 21 | 22 | #if [ -n "$__reply" ] 23 | #then 24 | # echo "$__reply" 25 | #else 26 | # echo 'P O N G' 27 | #fi 28 | -------------------------------------------------------------------------------- /scripts/unused/piibel: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^(1Ms|2Ms|3Ms|4Ms|5Ms|Jos|Km|Rt|1Sm|2Sm|1Kn|2Kn|1Aj|2Aj|Esr|Ne|Est|Ii|Ps|Õp|Kg|Ül|Js|Jr|Nl|Hs|Tn|Ho|Jl|Am|Ob|Jn|Mi|Na|Ha|Sf|Hg|Sk|Ml|Jdt|Trk|Tb|Srk|Brk|1Mak|2Mak|Erl|Su|Bl|Lm|As|Kml|Mn|Mt|Mk|Lk|Jh|Ap|Rm|1Kr|2Kr|Gl|Ef|Fl|Kl|1Ts|2Ts|1Tm|2Tm|Tt|Fm|Hb|Jk|1Pt|2Pt|1Jh|2Jh|3Jh|Jd|Ilm)\s[0-9:-]+$' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 0 9 | fi 10 | 11 | arg="$( echo "$@" | grep -ioP "$regex" | sed 's/\s/+/' )" 12 | 13 | if [ -z "$arg" ] 14 | then 15 | exit 1 16 | fi 17 | 18 | json="$( curl -s "http://piibel.net/api/v3/.json?q=$arg" )" 19 | 20 | if [ -z "$json" ] 21 | then 22 | exit 1 23 | fi 24 | 25 | echo "$json" \ 26 | | jq -r '.result.verses[].text' \ 27 | | while read -r l 28 | do 29 | echo "$l" 30 | done \ 31 | | sed -r 's/(&[a-z]+;|br \/|\s+)/ /gim' \ 32 | | sed -r 's/\s+/ /gim' 33 | -------------------------------------------------------------------------------- /scripts/firewall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^firewall$|^fw$|^!?firewall.*$' 5 | exit 0 6 | fi 7 | 8 | # ufw must be installed 9 | type ufw >/dev/null 2>&1 || { 10 | echo "This script requires that you install the packge \"ufw\" on the server to check your firewall." 11 | exit 0 12 | } 13 | 14 | fi=$(sudo ufw status verbose) 15 | bold=$(tput bold) 16 | red=$(tput setaf 1) 17 | yellow=$(tput setaf 3) 18 | green=$(tput setaf 2) 19 | reset=$(tput sgr0) 20 | fi=${fi//deny/${green}${bold}deny${reset}} 21 | fi=${fi//reject/${yellow}${bold}reject${reset}} 22 | fi=${fi//allow/${red}${bold}allow${reset}} 23 | fi=${fi//disabled/${green}${bold}disabled${reset}} 24 | fi=${fi//enabled/${red}${bold}enabled${reset}} 25 | echo -e -n "$fi" 26 | echo 27 | 28 | # Argument __reply from config file is not used in this script 29 | #if [ -n "$__reply" ] 30 | #then 31 | # echo "$__reply" 32 | #else 33 | # echo 'P O N G' 34 | #fi 35 | -------------------------------------------------------------------------------- /scripts/unused/ilm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ] 4 | then 5 | echo '^!?ilm\??$' 6 | exit 0 7 | fi 8 | 9 | __get() { 10 | c="/tmp/ilm-cache-$( echo "$1" | md5sum | awk '{print $1}' )" 11 | [ -f "$c" ] && a=$(( $( date +%s ) - $( date -r "$c" +%s ) )) 12 | if [ ! -f "$c" ] || [ "$a" -gt 500 ] 13 | then curl -s -A tiny-matrix-bot -o "$c" "$1" 14 | fi 15 | cat "$c" 16 | } 17 | 18 | __ilmateenistus() { 19 | __get http://www.ilmateenistus.ee/ilma_andmed/xml/observations.php \ 20 | | xmlstarlet sel -t -v "/observations/station[name='$1']/airtemperature" 21 | } 22 | 23 | __print() { 24 | printf '%s: %.1f °C\n' "$1" "$2" \ 25 | | sed 's/\./,/' \ 26 | | sed 's/,0//' 27 | } 28 | 29 | __print Tallinn "$( __ilmateenistus Tallinn-Harku )" 30 | 31 | __print Tartu "$( __ilmateenistus Tartu-Kvissental )" 32 | 33 | __print Pärnu "$( __ilmateenistus Pärnu )" 34 | 35 | __print Võru "$( __ilmateenistus Võru )" 36 | 37 | __print Elva "$( __ilmateenistus Elva )" 38 | -------------------------------------------------------------------------------- /scripts/web: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo 'www|web|^!?web .*$|^!?www .*$|^browse$|^browse .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # w3m must be installed 17 | type w3m >/dev/null 2>&1 || { 18 | echo "This script requires that you install the packge \"w3m\" on the server." 19 | exit 0 20 | } 21 | 22 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 23 | #echo "web: arguments: \"$args\"" 24 | if [ "$args" == "" ]; then 25 | echo "You must be browsing some URL. Try \"web news.ycombinator.com\"." 26 | # echo "If torify is available all traffic will go through TOR by default." 27 | # echo "If you really must skip TOR, try \"web notorify news.ycombinator.com\"." 28 | exit 0 29 | fi 30 | 31 | arg1=$(echo "$args" | tr -s ' ' | cut -s -d ' ' -f 1) 32 | if [ "$arg1" == "notorify" ]; then 33 | TORIFY="" 34 | args=$(echo "$args" | tr -s ' ' | cut -s -d ' ' -f 2-) # remove first arg 35 | fi 36 | $TORIFY w3m -dump "$args" 37 | 38 | # Argument __reply from config file is not used in this script 39 | #if [ -n "$__reply" ] 40 | #then 41 | # echo "$__reply" 42 | #else 43 | # echo 'P O N G' 44 | #fi 45 | -------------------------------------------------------------------------------- /scripts/unused/eki: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | 'http://www.eki.ee/dict/ekss/index.cgi?Q=%s&C01=1&C02=1&C03=1', 23 | 'qs' => 'http://www.eki.ee/dict/qs/index.cgi?Q=%s&C01=1&C02=1', 24 | 'ety' => 'http://www.eki.ee/dict/ety/index.cgi?Q=%s&F=M&C06=et', 25 | ); 26 | 27 | $url = sprintf( $dicts[ $dict ], $args ); 28 | $html = file_get_contents( $url ); 29 | 30 | $dom = new DOMDocument; 31 | @$dom->loadHTML( $html ); // UTF-suutropp 32 | $xpath = new DOMXpath( $dom ); 33 | 34 | $results = $xpath->query( '//div[contains(@class,"tervikart")]' ); 35 | $counter = 0; 36 | 37 | foreach ( $results as $result ) 38 | { 39 | foreach ( $result->childNodes as $node ) 40 | { 41 | $counter++; 42 | 43 | $line = trim( $node->nodeValue ); 44 | 45 | if ( mb_strlen( $line ) >= 300 ) 46 | $line = mb_substr( $line, 0, 300 ) . '...'; 47 | 48 | echo $line . "\n"; 49 | 50 | if ( $counter >= 3 ) 51 | break; 52 | } 53 | 54 | if ( $counter >= 3 ) 55 | break; 56 | } 57 | 58 | if ( $counter > 0 ) 59 | echo $url . "\n"; 60 | else 61 | echo "Nein!\n"; 62 | -------------------------------------------------------------------------------- /scripts/btc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^btc$|^bitcoin$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/assets/bitcoin/metrics" | jq '.data.market_data | 17 | # .percent_change_usd_last_24_hours, .real_volume_last_24_hours , .price_usd' 2>&1 # 2>> /dev/null 18 | 19 | BASELIST=$($TORIFY curl --silent --compressed "https://data.messari.io/api/v1/assets/bitcoin/metrics" | 20 | jq '.data.market_data | keys_unsorted[] as $k | "\($k), \(.[$k] )"' | 21 | grep -e price_usd -e real_volume_last_24_hours -e percent_change_usd_last_24_hours | tr -d "\"") 22 | # returns something like 23 | # price_usd, 9632.330680167783 24 | # real_volume_last_24_hours, 1418555108.5501404 25 | # percent_change_usd_last_24_hours, 1.152004386319294 26 | LC_ALL=en_US.UTF-8 printf "Price: %'.0f USD\n" "$(echo "$BASELIST" | grep price_usd | cut -d "," -f 2)" 27 | LC_ALL=en_US.UTF-8 printf "Change: %'.1f %%\n" "$(echo "$BASELIST" | grep percent_change_usd_last_24_hours | cut -d "," -f 2)" 28 | LC_ALL=en_US.UTF-8 printf "Volume: %'.0f USD\n" "$(echo "$BASELIST" | grep real_volume_last_24_hours | cut -d "," -f 2)" 29 | 30 | #if [ -n "$__reply" ] 31 | #then 32 | # echo "$__reply" 33 | #else 34 | # echo 'P O N G' 35 | #fi 36 | -------------------------------------------------------------------------------- /scripts/s2f: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^flow$|^s2f|^flow .*$|^s2f .$|^s-to-f$|^stock-to-flow .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) # optional format like "+" or "more" 17 | 18 | if [[ "$arg1" == "+" ]] || [[ "$arg1" == "more" ]] || [[ "$arg1" == "plus" ]] || [[ "$arg1" == "v" ]]; then 19 | FORMAT="" 20 | else 21 | FORMAT="--terse" 22 | fi 23 | 24 | # s2f must be installed 25 | type s2f.py >/dev/null 2>&1 || { 26 | # it was not found in normal path, lets see if we can amplify the PATH by sourcing profile files 27 | . $HOME/.bash_profile 2> /dev/null 28 | . $HOME/.profile 2> /dev/null 29 | type s2f.py >/dev/null 2>&1 || { 30 | echo "For s2f to work you must first install the file \"s2f.py\" on the server." 31 | echo "Download from https://github.com/8go/bitcoin-stock-to-flow" 32 | echo "Set your PATH if you have installed it but it cannot be found." 33 | exit 0 34 | } 35 | } 36 | 37 | # does not work over TOR $TORIFY 38 | # mys2f.py $FORMAT | grep -v "Calculated" | grep -v "Data sources" | tr -s " " # this displays nicer with format "text" 39 | 40 | mys2f.py $FORMAT | grep -v "Calculated" | grep -v "Data sources" # this displays nicer with format "code" 41 | 42 | #if [ -n "$__reply" ] 43 | #then 44 | # echo "$__reply" 45 | #else 46 | # echo 'P O N G' 47 | #fi 48 | -------------------------------------------------------------------------------- /scripts/hn: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^hn$|^hn .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | function gethackernewsfromweb() { 17 | $TORIFY w3m -dump news.ycombinator.com 2>&1 | grep -v -E 'points.*comments' | 18 | grep -v -E ' points by .* minutes ago | hide | discuss' | 19 | grep -v -E ' ago | hide' | 20 | grep -v 'Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet' | 21 | grep -v "Legal | Apply to YC | Contact" | 22 | grep -v -E ' *Search: \[ *\]$' | 23 | grep -v " submit" | 24 | grep -v " More" | 25 | grep -v -E ' \*$' | sed '/^[[:space:]]*$/d' | sed 's/^......//' 26 | # remove lines with only whitespaces, remove leading 6 characters 27 | } 28 | 29 | #arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) 30 | ##echo "hn: argument 1: \"$arg1\"" 31 | #if [ "$arg1" == "" ]; then 32 | # ; # no argument 33 | #fi 34 | #case "$arg1" in 35 | #'' | *[!0-9]*) 36 | # echo "First argument is not a number. Skipping. Try \"hn\" or \"hn 5\"." 37 | # exit 0 38 | # ;; 39 | #*) 40 | # # echo "First argument is a number. " 41 | # ;; 42 | #esac 43 | 44 | gethackernewsfromweb # "$arg1" 45 | exit 0 46 | 47 | # Argument __reply from config file is not used in this script 48 | #if [ -n "$__reply" ] 49 | #then 50 | # echo "$__reply" 51 | #else 52 | # echo 'P O N G' 53 | #fi 54 | -------------------------------------------------------------------------------- /scripts/wake: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^wake$|^wakeup$|^wake .*$|^wakeup .*$|^wakelan .*$' 5 | exit 0 6 | fi 7 | 8 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 9 | #echo "wake: arguments: \"$args\"" 10 | if [ "$args" == "" ]; then 11 | echo "You must specify which PC to wake up. Try \"wake pc1\" or similar." 12 | exit 0 13 | fi 14 | arg1=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 1) 15 | arg2=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 2) 16 | 17 | # $1: which PC to wake up 18 | # $2: possible password 19 | function dowake() { 20 | arg1="$1" 21 | arg2="$2" 22 | case "${arg1,,}" in 23 | "world") 24 | echo "Waking up the world. Done!" 25 | ;; 26 | "pc1" | "pc1fullname") 27 | # in order to wake up host, one must provide a password 28 | # we compare the hashes here, put your hash here 29 | if [ "$(echo "$arg2" | sha256sum | cut -d ' ' -f 1)" == "1234567812345678123456781234567812345678123456781234567812345678" ]; then 30 | echo "The bot will wake up host \"$arg1\"." 31 | wakeonlan 00:44:88:cc:ee:ff # put the MAC of your PC here 32 | else 33 | echo "Argument missing or argument wrong. Command ignored due to lack of permissions." 34 | fi 35 | ;; 36 | *) 37 | echo "The bot does not know how to wake up host \"${arg1}.\"" 38 | echo "Only hosts \"pc1\" and \"pc1fullname\" are configured on server." 39 | ;; 40 | esac 41 | } 42 | 43 | dowake "$arg1" "$arg2" 44 | 45 | exit 0 46 | 47 | # The __reply env variable set in the config file is not used in this script 48 | #if [ -n "$__reply" ] 49 | #then 50 | # echo "$__reply" 51 | #else 52 | # echo 'P O N G' 53 | #fi 54 | -------------------------------------------------------------------------------- /scripts/eth: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^eth$|^ethereum$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/assets/ethereum/metrics" | jq '.data.market_data' 2>> /dev/null 17 | # $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/assets/ethereum/metrics" | 18 | # jq '.data.market_data | keys_unsorted[] as $k | "\($k), \(.[$k] )"' | 19 | # grep -e price_usd -e real_volume_last_24_hours -e percent_change_usd_last_24_hours -e price_btc | tr -d "\"" | rev | cut -c9- | rev | tr "," ":" 2>&1 20 | 21 | BASELIST=$($TORIFY curl --silent --compressed "https://data.messari.io/api/v1/assets/ethereum/metrics" | 22 | jq '.data.market_data | keys_unsorted[] as $k | "\($k), \(.[$k] )"' | 23 | grep -e price_usd -e real_volume_last_24_hours -e percent_change_usd_last_24_hours -e price_btc | tr -d "\"") 24 | # returns something like 25 | # price_usd, 9632.330680167783 26 | # real_volume_last_24_hours, 1418555108.5501404 27 | # percent_change_usd_last_24_hours, 1.152004386319294 28 | LC_ALL=en_US.UTF-8 printf "Price: %'.0f USD\n" "$(echo "$BASELIST" | grep price_usd | cut -d "," -f 2)" 29 | LC_ALL=en_US.UTF-8 printf "Price: %'.4f BTC\n" "$(echo "$BASELIST" | grep price_btc | cut -d "," -f 2)" 30 | LC_ALL=en_US.UTF-8 printf "Change: %'.1f %%\n" "$(echo "$BASELIST" | grep percent_change_usd_last_24_hours | cut -d "," -f 2)" 31 | LC_ALL=en_US.UTF-8 printf "Volume: %'.0f USD\n" "$(echo "$BASELIST" | grep real_volume_last_24_hours | cut -d "," -f 2)" 32 | 33 | #if [ -n "$__reply" ] 34 | #then 35 | # echo "$__reply" 36 | #else 37 | # echo 'P O N G' 38 | #fi 39 | -------------------------------------------------------------------------------- /scripts/unused/koroona: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import datetime 4 | import json 5 | import os 6 | import re 7 | import sys 8 | import time 9 | import urllib.request 10 | 11 | regex = '^!*koroona\\?*\\s*' 12 | 13 | if 'CONFIG' in os.environ: 14 | print(regex) 15 | sys.exit(0) 16 | 17 | count = 5 18 | 19 | if len(sys.argv) > 1: 20 | x = re.sub(regex, '', sys.argv[1]) 21 | if x.isdigit(): 22 | x = int(x) 23 | if x > count and x < 11: 24 | count = x 25 | 26 | tmp = '/tmp/covid19cache.json' 27 | 28 | if not os.path.exists(tmp) or time.time() - os.path.getmtime(tmp) > 500: 29 | urllib.request.urlretrieve( 30 | 'https://opendata.digilugu.ee/opendata_covid19_test_results.json', 31 | tmp) 32 | 33 | data = json.loads(open(tmp, 'r').read()) 34 | results = {} 35 | totals = {'P': {'M': 0, 'N': 0, 'K': 0}, 36 | 'N': {'M': 0, 'N': 0, 'K': 0}, 37 | 'K': 0} 38 | 39 | for x in data: 40 | gender = x['Gender'] 41 | result = x['ResultValue'] 42 | timefmt = '%Y-%m-%dT%H:%M:%S+{}'.format( 43 | re.search('\\+([0-9:]{5})$', x['ResultTime']).group(1)) 44 | day = datetime.datetime.strptime( 45 | x['ResultTime'], 46 | timefmt).strftime('%Y-%m-%d') 47 | 48 | if day not in results: 49 | results[day] = {'P': {'M': 0, 'N': 0, 'K': 0}, 50 | 'N': {'M': 0, 'N': 0, 'K': 0}, 51 | 'K': 0} 52 | 53 | results[day]['K'] += 1 54 | results[day][result]['K'] += 1 55 | results[day][result][gender] += 1 56 | 57 | totals['K'] += 1 58 | totals[result]['K'] += 1 59 | totals[result][gender] += 1 60 | 61 | results['Kokku'] = totals 62 | 63 | for x in sorted(results)[-(count+1):]: 64 | if results[x]['P']['K'] == 0: 65 | print('{}: {} testi, kõik negatiivsed'.format( 66 | x, 67 | results[x]['K'])) 68 | else: 69 | print('{}: {} testi, millest positiivseid {} ({:.1f}%)'.format( 70 | x, 71 | results[x]['K'], 72 | results[x]['P']['K'], 73 | results[x]['P']['K'] / results[x]['K'] * 100)) 74 | -------------------------------------------------------------------------------- /scripts/unused/v6tame: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ] 4 | then 5 | echo '^võtame!$' 6 | exit 0 7 | fi 8 | 9 | # https://github.com/JaanVr/bots/blob/master/bots/v%C3%B5tame.txt 10 | 11 | echo "Kallid koosviibijad. Palun tõstame kõik oma pitsid ja pokaalid suu juurde. Nüüd paneme need lauale tagasi.Tänan. 12 | Joome naiste ja armukeste terviseks ja et nad eales ei kohtuks! 13 | Elagu naised, kes vähendavad meie valu, teevad meie rõõmud kahekordseks ja väljaminekud kümnekordseks! 14 | Teie terviseks, minu kõhtu 15 | Võtame selle terviseks, et meie lastel oleksid rikkad vanemad! 16 | Joome naiste terviseks, kes ei suuda elada ilma meesteta, nagu kala ei suuda elada veeta! 17 | Joome mannekeenide terviseks, kes ei lähe kunagi moest! 18 | Wõtame wõtmise pärast! 19 | Võta pits ja pea aru 20 | Joogem selle terviseks, et me vaieldes kuulaksime alati ka teise poole arvamust, isegi kui ta on eesel! 21 | Tõstkem pits nendele keda me austame, wõtame, ja tühja pitsiga visakem neid, kes meile närvidele käivad! 22 | Joogem selleks, et on janu, seejärel joogem selleks, et janu vajab kustutamist, ning lõpuks joogem selleks, et lihtsalt tahaks juua! 23 | Kes homme hiljem ärkab, see vähem silma torkab, wõtame! 24 | Joome selleks, et elus püsida! 25 | Kuna elu on seiklus, tõstame pitsi oma tugitoolile! 26 | Mis sitasti, see uuesti. Tõstkem pits seksile, mis läks sitasti! 27 | Wõtame kadunukese terviseks... ja nüüd lähme otsime ta üles! 28 | Kolm põrsakest... wõtame... seapraad! 29 | Kes viimasena võtab, läheb järgi! Seega, võtame kähku. 30 | Elagu mumps! 31 | Viin on lihtsalt lustakas vesi, võtame! 32 | Kui elu on piin, siis aitab sind viin, ära ülesse end poo, vaid südamest joo! 33 | Kunagi lugesin, et joomine kahjustab tervist, võtame lugemisoskamatuse terviseks! 34 | Jätame joomise maha? Jätame. Selle peale võtame? Võtame! 35 | Keegi tark ütles kunagi, et juua tuleb mõistuse piires. Aga Einstein ütles, et mõistus on piiritu. Võtame Einsteini terviseks! 36 | Mehed ei sünnita sellepärast, et nad poleks sellise pingutusega üldse nõus. Võtame naiste terviseks! 37 | Elu on lill, persse need muruniidukid,! Wõtame! 38 | Kes jõid, need on läinud, kes joovad, need lähevad ka, ja kes ei joo, ega needki siia jää, wõtame!" | shuf -n1 39 | -------------------------------------------------------------------------------- /scripts/unused/plaan: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^!pla+n\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 0 9 | fi 10 | 11 | arg="$( echo "$@" | sed -r "s/$regex//I" )" 12 | 13 | if [ -z "$arg" ] 14 | then 15 | exit 1 16 | fi 17 | 18 | # https://github.com/mth/hirc/blob/master/plans.txt 19 | 20 | printf '1. %s\n\n2. ???\n\n3. %s\n' \ 21 | "$arg" \ 22 | "$( echo "[CENSORED] 23 | [CLASSIFIED] 24 | kõik perses 25 | valus perse 26 | valus munn 27 | make profit 28 | räige kasum 29 | sitaks õlut 30 | rule the world 31 | ilus elu 32 | lihtne elu 33 | lihtsalt masendav 34 | ulmeline aldaris 35 | nõukogude võim 36 | kerge joove 37 | raske joove 38 | erakorralised valimised 39 | tagasi paastu ja palve juurde 40 | sittagi pole muutunud 41 | erakordselt sitt pohmakas 42 | metsas läheb elu käima 43 | naabrimutt saab infarkti 44 | tehnoloogiasektor langeb kolinal 45 | kõigil on savi 46 | maapealne paradiis 47 | uuele katsele 48 | juhtum antakse kaitsepolitseile uurida 49 | nobeli preemia 50 | spot the loony! 51 | kesknädalas ilmub pisike nupuke toimunu kohta 52 | mõistus kirjutab lahkumisavalduse 53 | mõistus läheb puhkusele 54 | peaks vist advokaadi palkama 55 | Kroonikal on jälle millest kirjutada 56 | tekib röögatu hunnik tagantjärele tarkust 57 | erakordselt külm talv 58 | maakera jääb häbi pärast seisma 59 | kast viina kõigile 60 | viina defitsiit 61 | poest saab lauaviin otsa 62 | igale pensionärile tasuta suitsuvorst 63 | saabub 1000 aastane rahuriik 64 | Eesti saab uue peaministri nõuniku 65 | sotsiaalministeeriumil valmib esimene edukas e-lahendus 66 | tühistatakse viimane rahareform 67 | Tapa Edasi hakkab uuesti ilmuma 68 | lihtsalt sitt 69 | massirepressioonid 70 | puhas nauding 71 | nädalane orgia 72 | ilge porno 73 | kristlikud organisatsioonid avaldavad hukkamõistu 74 | Venemaa avaldab hukkamõistu 75 | rahvusvaheline tunnustus ja tohutu edu! 76 | valitsus tellib Lätist veekahuri 77 | kogu raha on maha joodud 78 | rootsi kardinad 79 | Katrin Lust-Buchanan kirjutab Delfisse uue nutuloo 80 | sa näed telepurgist hommikust Haloneni 81 | 100k preemiat ja õhtulehe esikaas 82 | Halonen toob kohvikõrvaseks põhjapõdraspermat 83 | suurenenud teotahe 84 | sama jama, uus nimi 85 | lõõgastav õhtu fooliummütsiga mullivannis 86 | üleestiline reede 87 | hea pidu 88 | halb pidu 89 | PÕMM! 90 | kuskil on piir" | shuf -n1 )" 91 | -------------------------------------------------------------------------------- /scripts/unused/reede: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ] 4 | then 5 | echo '^reede\?$' 6 | exit 0 7 | fi 8 | 9 | __mis_nadalapaev() 10 | { 11 | date -d "$d" '+%u' 12 | } 13 | 14 | __mis_paevkuu() 15 | { 16 | date -d "$d" '+%d%m' 17 | } 18 | 19 | __on_nadalavahetus() 20 | { 21 | __mis_nadalapaev "$1" | grep -Eq '6|7' 22 | } 23 | 24 | __on_paevkuu() 25 | { 26 | __mis_paevkuu "$1" | grep -Eq "$2" 27 | } 28 | 29 | __on_lyhendatud() 30 | { 31 | __on_paevkuu "$1" '2302|2206|2312|3112' 32 | } 33 | 34 | __on_riigipyha() 35 | { 36 | y="$( date +%Y )" 37 | g="$(( y % 19 ))" 38 | c="$(( y / 100 ))" 39 | h="$(( ( c - c / 4 - ( 8 * c + 13 ) / 25 + 19 * g + 15 ) % 30 ))" 40 | i="$(( h - ( h / 28 ) * ( 1 - ( h / 28 ) * ( 29 / ( h + 1 ) ) * ( ( 21 - g ) / 11 ) ) ))" 41 | j="$(( ( y + y / 4 + i + 2 - c + c / 4 ) % 7 ))" 42 | p="$(( i - j ))" 43 | m="$(( 3 + ( p + 26 ) / 30 ))" 44 | d="$(( ( 1 + ( p + 27 + ( p + 6 ) / 40 ) % 31 ) - 2 ))" 45 | s="$( printf "%02d%02d" "$d" "$m" )" 46 | 47 | __on_paevkuu "$1" "0101|2402|$s|0105|2306|2406|2008|2412|2512|2612" 48 | } 49 | 50 | if __on_riigipyha 'today' 51 | then 52 | if __on_riigipyha 'tomorrow' || __on_nadalavahetus 'tomorrow' 53 | then 54 | echo 'Pühad on, kasi tagasi jooma!' 55 | else 56 | case "$( __mis_nadalapaev 'tomorrow' )" in 57 | 1|2|3) echo 'Hakkame lõpetama!' ;; 58 | 4) echo 'Äkki peaks tervisepäevad võtma?' ;; 59 | 5) echo 'Võta tervisepäev ja kasi tagasi jooma!' ;; 60 | esac 61 | fi 62 | 63 | elif __on_riigipyha 'tomorrow' 64 | then 65 | if __on_nadalavahetus 'today' 66 | then 67 | echo 'Pühad on, kasi tagasi jooma!' 68 | 69 | elif __on_lyhendatud 'today' 70 | then 71 | echo 'Miks sa ei joo juba?' 72 | else 73 | echo 'JAH!!!' 74 | fi 75 | 76 | elif __on_lyhendatud 'tomorrow' || __on_riigipyha '2 days' 77 | then 78 | echo 'Võta tervisepäevad ja kasi jooma!' 79 | 80 | else 81 | case "$( __mis_nadalapaev 'today' )" in 82 | 1|2) echo 'Ei.' ;; 83 | 3) echo 'Kolmapäev on nädala selgroog.' ;; 84 | 4) echo 'Varareede alles.' ;; 85 | 5) echo 'JAH!!!' ;; 86 | 6) echo 'Nädalavahetus on, kasi tagasi jooma!' ;; 87 | 7) echo 'Hakkame lõpetama!' ;; 88 | esac 89 | fi 90 | -------------------------------------------------------------------------------- /scripts/help: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^!?help(!|\?)?$|^ayuda$|^man$|^manual$|^hilfe$|^je suis perdu$|^perdu$|^socorro$|^h$' 5 | exit 0 6 | fi 7 | 8 | echo "Try: alert backup btc check cputemp datetime ddg disks eth firewall hello help hn mn motd \ 9 | pick ping platform pong ps restart rss s2f tesla tides top totp twitter update users wake weather web. 10 | 11 | Example bot commands provided: 12 | 13 | - help: to list available bot commands 14 | - ping: trivial example to have the bot respond 15 | - pong: like ping, but pong 16 | - hello: gives you a friendly compliment 17 | - motd: gives you the Linux Message Of The Day 18 | - ddg: search the web with DuckDuckGo search 19 | - web: surf the web, get a web page (JavaScript not supported) 20 | - rss: read RSS feeds 21 | - twitter: read latest user tweets from Twitter (does not always work as info is scraped from web) 22 | - tesla: chat with your Tesla car (dummy) 23 | - totp: get 2FA Two-factor-authentication TOTP PIN via bot message 24 | - hn: read Hacker News, fetches front page headlines from Hacker News 25 | - mn: read Messari News, fetches the latest news articles from Messari 26 | - date: gives date and time 27 | - weather: gives weather forecast 28 | - tides: give tidal forecast 29 | - btc: gives Bitcoin BTC price info 30 | - eth: gives Ethereum price info 31 | - s2f: print Bitcoin Stock-to-Flow info 32 | 33 | Additional bot commands provided to Matrix or system administrators 34 | 35 | With these commands a system administrator can maintain his Matrix installation and \ 36 | keep a watchful eye on his server all through the Matrix bot. 37 | 38 | - backup: performs backup on server 39 | - users: list registered Matrix users 40 | - disks: see how full your disks or mountpoints are 41 | - cputemp: monitor the CPU temperatures 42 | - restart: restart the bot itself, or Matrix services 43 | - wake: wake up another PC via wake-on-LAN 44 | - check: check status, health status, updates, etc. of bot, Matrix and the operating system 45 | - update: update operating sytem 46 | - firewall: list the firewall settings and configuration 47 | - date: gives date and time of server 48 | - platform: gives hardware and operating system platform information 49 | - ps: print current CPU, RAM and Disk utilization of server 50 | - top: gives 5 top CPU and RAM consuming processes 51 | - alert: shows if any CPU, RAM, or Disk thresholds have been exceeded (best to combine with a cron job, and have the cron job send the bot message to Matrix admin rooms)" 52 | exit 0 53 | 54 | # shellcheck disable=SC2154 55 | if [ -n "$__reply" ]; then 56 | echo "$__reply" 57 | else 58 | echo 'Read the config file for help :)' 59 | fi 60 | 61 | # EOF 62 | -------------------------------------------------------------------------------- /scripts/alert: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^alert$|^alert .*$|^alarm$' 5 | exit 0 6 | fi 7 | 8 | MEM_ALERT=0.8 # more than 80% of RAM used 9 | CPU_ALERT=0.7 # more than 80% of CPU used 10 | DSK_ALERT=0.9 # more than 80% of DISK used 11 | TMP_ALERT=65 # 69C, temperature alert if above x C Celsius 12 | 13 | # free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }' 14 | # df -h | awk '$NF=="/"{printf "Disk Usage: %d/%dGB (%s)\n", $3,$2,$5}' 15 | # top -bn1 | grep load | awk '{printf "CPU Load: %.2f\n", $(NF-2)}' 16 | 17 | # Memory Usage: 536/3793MB (14.13%) 18 | # Disk Usage: 7/30GB (25%) 19 | # CPU Load: 0.22 20 | 21 | MEM=$(free -m | awk 'NR==2{printf "%.2f", $3/$2 }') # total mem/used mem (does not look at swap) 22 | CPU=$(top -bn1 | head -n 1 | cut -d "," -f 5 | tr -d " ") # last 5 min CPU load average as "0.03" for 3% 23 | DSKP=$(df -h | awk '$NF=="/"{printf substr($5, 1, length($5)-1)}') # e.g. 25 for 25% 24 | DSK=$(LC_ALL=en_US.UTF-8 printf "%'.2f" "$(echo "scale=10; $DSKP / 100.0" | bc -l)") # e.g. 0.25 25 | 26 | MEMP=$(LC_ALL=en_US.UTF-8 printf "%'.0f" "$(echo "scale=10; $MEM * 100.0" | bc -l)") 27 | CPUP=$(LC_ALL=en_US.UTF-8 printf "%'.0f" "$(echo "scale=10; $CPU * 100.0" | bc -l)") 28 | 29 | CELSIUS=$(cat /sys/class/thermal/thermal_zone0/temp) 30 | TMP=$(echo "scale=0; $CELSIUS/1000" | bc | tr -d "\n") 31 | 32 | # echo "MEM=$MEM, CPU=$CPU, DSK=$DSK, TEMP=$TMP" 33 | # echo "MEM=${MEMP}%, CPU=${CPUP}%, DSK=${DSKP}%, TEMP=${TMP}C" 34 | 35 | RET=0 36 | MEM_STR="" 37 | CPU_STR="" 38 | DSK_STR="" 39 | TMP_STR="" 40 | 41 | if (($(echo "$MEM > $MEM_ALERT" | bc -l))); then 42 | MEM_STR="***$(date +%F\ %R)*** ALERT: memory consumption too high!\n" 43 | RET=$((RET + 1)) 44 | fi 45 | if (($(echo "$CPU > $CPU_ALERT" | bc -l))); then 46 | CPU_STR="***$(date +%F\ %R)*** ALERT: CPU usage too high!\n" 47 | RET=$((RET + 2)) 48 | fi 49 | if (($(echo "$DSK > $DSK_ALERT" | bc -l))); then 50 | DSK_STR="***$(date +%F\ %R)*** ALERT: disk too full!\n" 51 | RET=$((RET + 4)) 52 | fi 53 | if (($(echo "$TMP > $TMP_ALERT" | bc -l))); then 54 | TMP_STR="***$(date +%F\ %R)*** ALERT: CPU temperature too high!\n" 55 | RET=$((RET + 8)) 56 | fi 57 | 58 | if [ "$RET" != "0" ]; then 59 | echo "***$(date +%F\ %R)*** ### ALERT ### ALERT ### ALERT ###" >&2 # write this to stderr 60 | echo -e "${MEM_STR}${CPU_STR}${DSK_STR}${TMP_STR}MEM=${MEMP}%, CPU=${CPUP}%, DSK=${DSKP}%, TEMP=${TMP}C\n" 61 | # if there is an alert, also print the top 5 processes, see "top" script, code taken from there 62 | echo "Top 5 CPU consumers:" 63 | #ps -eo %cpu,pid,ppid,cmd --sort=-%cpu | head 64 | ps -eo %cpu,cmd --sort=-%cpu --cols 40 | head -n 5 65 | echo "" 66 | echo "Top 5 RAM consumers:" 67 | #ps -eo %mem,pid,ppid,cmd --sort=-%mem | head 68 | ps -eo %mem,cmd --sort=-%mem --cols 40 | head -n 5 69 | fi 70 | 71 | exit 0 72 | 73 | #if [ -n "$__reply" ] 74 | #then 75 | # echo "$__reply" 76 | #else 77 | # echo 'P O N G' 78 | #fi 79 | -------------------------------------------------------------------------------- /scripts/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^check$|^chk$|^status$|^state$|^check .*$|^chk .*|^status .*$|^state .*$$' 5 | exit 0 6 | fi 7 | 8 | # There is exactly 1 argument $1 when called from tiny Matrix bot. 9 | # Tiny Matrix bot calls script with this as $1: "script-name arg1 arg2 arg3 ..." 10 | # If we want to execute this script locally for testing, from the terminal we have 11 | # to call it like this: ./check "dummy os" Here, "dummy" will be thrown away and "os" will be used as argument 12 | 13 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 14 | #echo "check: arguments: \"$args\"." 15 | if [ "$args" == "" ]; then 16 | echo "You must be checking the health of something. Try \"check os\"." 17 | exit 0 18 | fi 19 | arg1=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 1) 20 | case "${arg1,,}" in 21 | "bot" | "ibot") 22 | echo "The bot will check the health of itself." 23 | systemctl status tiny-matrix-bot 24 | ;; 25 | "matrix") 26 | echo "The bot will check the health of matrix service." 27 | # the name of the service might vary based on installation from : synapse-matrix, matrix, etc. 28 | # let#s check all services that contain "matrix" in their name 29 | service --status-all | grep -i matrix | tr -s " " | cut -d " " -f 5 | while read -r p; do 30 | systemctl status "$p" 31 | done 32 | ;; 33 | "os") 34 | echo "The bot will check for possible updates for the operating system" 35 | type apt >/dev/null 2>&1 && type dnf >/dev/null 2>&1 && echo "Don't know how to check for updates as your system does neither support apt nor dnf." && exit 0 36 | # dnf OR apt exists 37 | type dnf >/dev/null 2>&1 || { 38 | apt list --upgradeable 39 | apt-get --just-print upgrade 2>/dev/null | grep -v "NOTE: This is only a simulation!" | 40 | grep -v "apt-get needs root privileges for real execution." | 41 | grep -v "Keep also in mind that locking is deactivated," | 42 | grep -v "so don't depend on the relevance to the real current situation!" 43 | } 44 | type apt >/dev/null 2>&1 || { 45 | dnf -q check-update 46 | dnf -q updateinfo 47 | dnf -q updateinfo list sec 48 | } 49 | ;; 50 | "services" | "service") 51 | service --status-all 52 | ;; 53 | "world") 54 | echo "The world definitely needs some upgrades!" 55 | ;; 56 | *) 57 | echo "This bot does not know how to check up on ${arg1}." 58 | echo "Only \"bot\", \"matrix\", \"os\", \"services\", and \"world\" are configured on server." 59 | ;; 60 | esac 61 | 62 | # The __reply env variable set in the config file is not used in this script 63 | #if [ -n "$__reply" ] 64 | #then 65 | # echo "$__reply" 66 | #else 67 | # echo 'P O N G' 68 | #fi 69 | -------------------------------------------------------------------------------- /scripts/totp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^otp$|^totp$|^otp .*$|^totp .*$' 5 | exit 0 6 | fi 7 | 8 | # Example URI: 9 | # otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example 10 | 11 | # Example TOTP secret key: 12 | # JBSWY3DPEHPK3PXP 13 | 14 | # TOTP secret can be password protected thru a 2nd argument 15 | 16 | # Do this to encypt a TOTP secret key: 17 | # echo "JBSWY3DPEHPK3PXP" | openssl enc -aes-256-cbc -salt -a -pbkdf2 # returns encrypted TOTP key 18 | # "U2FsdGVkX1+etVuH68uNDv1v5J+XfYXRSuuEyypLJrEGCfo4V91eICW1085lQa68" # TOTP secret key "JBSWY3DPEHPK3PXP" encrypted with passphrase "test" 19 | 20 | # the reverse is: decrypted the cipher text to get original TOTP secret key, in the example we use passphrase "test" 21 | # echo "U2FsdGVkX1+etVuH68uNDv1v5J+XfYXRSuuEyypLJrEGCfo4V91eICW1085lQa68" | openssl enc -aes-256-cbc -d -salt -a -pbkdf2 -k test # returns "JBSWY3DPEHPK3PXP" 22 | # JBSWY3DPEHPK3PXP 23 | 24 | # oathtool must be installed 25 | type oathtool >/dev/null 2>&1 || { 26 | echo "This script requires that you install the packge \"oathtool\" on the server." 27 | exit 0 28 | } 29 | 30 | function totp() { 31 | D="$(date +%S)" 32 | # shellcheck disable=SC2001 33 | DNOLEADINGZERO=$(echo "$D" | sed 's/^0//') 34 | # shellcheck disable=SC2004 35 | SECONDSREMAINING=$((30 - $DNOLEADINGZERO % 30)) 36 | X=$(oathtool --totp -b "$1") 37 | echo "$SECONDSREMAINING seconds remaining : $X" 38 | } 39 | 40 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) 41 | arg2=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 3) 42 | #echo "totp: arguments : \"$1\"" 43 | #echo "totp: argument 1: \"$arg1\"" # totp-nick-name 44 | #echo "totp: argument 2: \"$arg2\"" # optional password 45 | if [ "$arg1" == "" ]; then 46 | echo "No TOTP nick-name given. Try \"totp example-plaintext\" or \"totp example-encrypted\" next time." 47 | echo "This script has to be set up on the server to be meaningful." 48 | echo "As shipped it only has an example of a TOTP service." 49 | exit 0 50 | fi 51 | case "$arg1" in 52 | example-plaintext) 53 | # echo "Calculating TOTP PIN for you" 54 | PLAINTEXTTOTPKEY="JBSWY3DPEHPK3PXP" 55 | totp "$PLAINTEXTTOTPKEY" 56 | exit 0 57 | ;; 58 | example-encrypted) 59 | # echo "Calculating TOTP PIN for you" 60 | if [ "$arg2" == "" ]; then 61 | echo "A password is required for this TOTP nick name." 62 | exit 0 63 | fi 64 | CIPHERTOTPKEY="U2FsdGVkX1+etVuH68uNDv1v5J+XfYXRSuuEyypLJrEGCfo4V91eICW1085lQa68" 65 | PLAINTEXTTOTPKEY=$(echo "$CIPHERTOTPKEY" | openssl enc -aes-256-cbc -d -salt -a -pbkdf2 -k "$arg2") 66 | totp "$PLAINTEXTTOTPKEY" 67 | # echo "Using \"$arg2\" as password. Totp secret is \"$TOTPSECRET\"." 68 | exit 0 69 | ;; 70 | *) 71 | echo "Unknown TOTP nick name \"$arg1\". Not configured on server." 72 | ;; 73 | esac 74 | 75 | #if [ -n "$__reply" ] 76 | #then 77 | # echo "$__reply" 78 | #else 79 | # echo 'P O N G' 80 | #fi 81 | -------------------------------------------------------------------------------- /scripts/update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^update$|^upgrade$|^update .*$|^upgrade .*$' 5 | exit 0 6 | fi 7 | 8 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 9 | #echo "update: arguments: \"$args\"" 10 | if [ "$args" == "" ]; then 11 | echo "You must be updating something. Try \"update os\"." 12 | exit 0 13 | fi 14 | arg1=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 1) 15 | case "${arg1,,}" in 16 | "bot" | "ibot") 17 | echo "Hey, what do you mean? I am always up-to-date." 18 | echo "Sorry. The bot update is not implemented. If you really want to update your bot, add your update code here." 19 | ;; 20 | "matrix") 21 | echo "The bot will update the matrix software." 22 | # the name of the service might vary based on installation from : synapse-matrix, matrix, etc. 23 | # there are many different ways to install matrix and to update matrix. 24 | echo "Sorry. The matrix update is not implemented. Add it here if desired." 25 | ;; 26 | "os") 27 | echo "The bot will update the operating system" 28 | type apt >/dev/null 2>&1 && type dnf >/dev/null 2>&1 && echo "Don't know how to check for updates as your system does neither support apt nor dnf." && exit 0 29 | # dnf OR apt exists 30 | type dnf >/dev/null 2>&1 || { 31 | sudo apt-get update || 32 | { 33 | echo "Error while using apt. Maybe due to missing permissions?" 34 | return 0 35 | } 36 | sudo apt-get --yes --with-new-pkgs upgrade || 37 | { 38 | echo "Error while using apt. Maybe due to missing permissions?" 39 | return 0 40 | } 41 | sudo apt-get --yes autoremove || 42 | { 43 | echo "Error while using apt. Maybe due to missing permissions?" 44 | return 0 45 | } 46 | sudo apt-get --yes autoclean || 47 | { 48 | echo "Error while using apt. Maybe due to missing permissions?" 49 | return 0 50 | } 51 | } 52 | type apt >/dev/null 2>&1 || { 53 | sudo dnf -y upgrade || 54 | { 55 | echo "Error while using dnf. Maybe due to missing permissions?" 56 | return 0 57 | } 58 | } 59 | ;; 60 | "world") 61 | echo "Your bot will update world order. World 2.0 ready!" 62 | ;; 63 | *) 64 | echo "This bot does not know how to upgrade ${arg1}." 65 | echo "Only \"bot\", \"matrix\", \"os\", and \"world\" are configured on server." 66 | ;; 67 | esac 68 | 69 | # The __reply env variable set in the config file is not used in this script 70 | #if [ -n "$__reply" ] 71 | #then 72 | # echo "$__reply" 73 | #else 74 | # echo 'P O N G' 75 | #fi 76 | -------------------------------------------------------------------------------- /tmb.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 54 | 62 | 66 | 70 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /scripts/unused/kiida: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^!(kiida|compliment)\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 1 9 | fi 10 | 11 | arg="$( echo "$@" | sed -r "s/$regex//I" | sed 's/.*/\u&/' )" 12 | 13 | # https://github.com/mth/hirc/blob/master/compliments.txt 14 | 15 | echo "Milline sümpaatne noor inimene on $arg! Olgu ta teile eeskujuks. 16 | Pidevast õllejoomisest hoolimata on Sul fantastiline figuur! 17 | Ma pole veel kohanud nii võrratu käitumisega inimest kui $arg 18 | Eesti mees nagu $arg on kõige parem 19 | Sul on nii armsad silmad, just nagu kutsikal! 20 | Sa oled sama ilus kui tänane päev! 21 | Oma aju ja teadmistega võiksid Sa vabalt olla mees! 22 | Sa oled nagu ingel kesapõllul! 23 | $arg eest annaks ma terve kuningriigi 24 | $arg, Sa oled nagu hea vein, mida keegi ei raatsi puutuda 25 | Tahaks Sind kallistada! 26 | Sa oled arukas, heatujuline ja elav. Kuidas naistega läheb? 27 | $arg mõistus on kahtlemata omal kohal 28 | Sa oled nagu sinilill kibuvitsapõõsas 29 | $arg, mu ingel 30 | Aitäh, $arg, et Sa elus oled! 31 | Sina oledki see kirkaim kriit karbis! 32 | Sa näed välja nagu koorejäätis kirsiga 33 | Piiblis on kirjas: \"Ja nüüd istub ta Tema paremal käel.\" Mõeldi vist Sind. 34 | Ma arvan, et $arg on selle koha tegelik juhtfiguur 35 | $arg, kas Sa oleksid palun mu laste isa? 36 | Kas need on Sinu Porsched seal maja ees? 37 | Tule ma annan Sulle musi 38 | Kui Sind ära ruunata, oleks Sa ikka rohkem mees kui need teised lontrused siin 39 | $arg, kas MENSA jäi Sulle kitsaks? 40 | Ükski prohvet, isegi mitte $arg, pole kuulus omal maal... 41 | $arg, Su kaunidus võtab jalust nõrgemaks kui liköör shampusega 42 | Räägitakse, et $arg on uus Ron Jeremy... 43 | Sa näed fantastiline välja. Oled Sa ikka eestlane? 44 | Muskulatuuri järgi võiks arvata, et Sa oled neeger 45 | Igal õhtul ma palvetan, et mulle Sinusugune mees saadetaks! 46 | $arg presidendiks! 47 | Teen ettepaneku nimetada $arg Valgetähe ordeni kandidaadiks 48 | $arg on nii lahe, et talle peaks selle eest raha maksma 49 | Kui ma oleks nii kuulus kui $arg, ei julgeks ma ilma turvadeta väljagi minna... 50 | Minu laste isa on $arg. Soovitan teistelegi. 51 | Päike oli valge, enne kui ta $arg peale vaadates kadedusest kollaseks läks 52 | Sinu sära juures poleks meile päikest vajagi 53 | $arg paneb aluse uuele inimtõule 54 | Meie ajastu vajab kangelasi. $arg, astu ette! 55 | Mehed nagu $arg viivad meid tähtedele 56 | $arg, kas sind esitati jälle Nobeli preemia kandidaadiks? 57 | Hea on päeva alustada, kui tead, et $arg on lähedal 58 | Kui Billi asemel juhiks Microsofti $arg, kasutaks kogu see rahvas Windowsit 59 | $arg: Sinuga läheks luurele küll. Ja tuleks koos tagasi ka. 60 | $arg: Ema Teresal oli Sinu kohta mõndagi head öelda 61 | Kui maailmas oleks ainult inimesed nagu $arg, elaksime siiani paradiisis 62 | Kas teadsite, et buda mungad käisid $arg juures kannatlikkust õppimas? 63 | $arg võitles meie vabaduse eest. Mida tegite teie? 64 | Vaadake! $arg'st levib ürgset mehelikku jõudu! 65 | Maagiat ma ei usu, aga $arg on küll täielik tehnikavõlur 66 | $arg, Sa oled mu eeskuju. Ausõna. 67 | Pange tähele, veel mõni aasta ja $arg on populaarsem kui Jeesus ja biitlid kokku 68 | $arg: Kuidas Sa küll suudad alati olla nii rõõmsameelne, optimistlik ja lahke? 69 | $arg: Su elurõõm on piiritu, jaga seda teistelegi 70 | $arg, Sa oled ikka uskumatult positiivne tüüp! Fantastiline! Täiesti super! 71 | Pärast $arg nägemist on terve päev nagu päikest täis 72 | Sinuga, $arg, võiks ma minna kasvõi maailma lõppu! 73 | Mis on õnn? Aga vaadake $arg poole, saate aru... 74 | $arg: Tule ma kallistan Sind! 75 | $arg: Su elu on nagu muinasjutt... 76 | Kas teate, miks John Holmes Eestis ei käinud? Ta kartis $arg'ga võistelda." | shuf -n1 77 | -------------------------------------------------------------------------------- /scripts/unused/astral: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | import sys 6 | 7 | try: 8 | import datetime 9 | import pytz 10 | 11 | from astral import LocationInfo 12 | from astral import moon 13 | from astral import sun 14 | 15 | except ImportError as e: 16 | print(e, file=sys.stderr) 17 | sys.exit(0) 18 | 19 | 20 | def get_places(): 21 | # TODO read this from file? 22 | return { 23 | 'tallinn': [ 24 | 'Tallinn', 25 | 'Estonia', 26 | 'Europe/Tallinn', 27 | 59.437222, 28 | 24.745278], 29 | 'tartu': [ 30 | 'Tartu', 31 | 'Estonia', 32 | 'Europe/Tallinn', 33 | 58.383333, 34 | 26.716667], 35 | 'pärnu': [ 36 | 'Pärnu', 37 | 'Estonia', 38 | 'Europe/Tallinn', 39 | 58.383333, 40 | 24.5], 41 | 'võru': [ 42 | 'Võru', 43 | 'Estonia', 44 | 'Europe/Tallinn', 45 | 57.848611, 46 | 26.992778], 47 | 'elva': [ 48 | 'Elva', 49 | 'Estonia', 50 | 'Europe/Tallinn', 51 | 58.224444, 52 | 26.421111]} 53 | 54 | 55 | def print_places(): 56 | places = sorted([place[0] for place in get_places().values()]) 57 | i = len(places) - 1 58 | if i == 0: 59 | print(places[0]+'?') 60 | else: 61 | print(', '.join(places[:i]) + ' or ' + places[i] + '?') 62 | 63 | 64 | def get_place(place): 65 | places = get_places() 66 | if place in places.keys(): 67 | return places[place] 68 | else: 69 | return False 70 | 71 | 72 | def print_place(p): 73 | place = get_place(p) 74 | if not place: 75 | print_places() 76 | sys.exit(0) 77 | 78 | city, region, tzname, lat, lon = place 79 | location = LocationInfo(city, region, tzname, lat, lon) 80 | observer = location.observer 81 | 82 | timezone = pytz.timezone(location.timezone) 83 | today = datetime.datetime.now(timezone) 84 | tomorrow = today + datetime.timedelta(days=1) 85 | 86 | sunrise_today = sun.sunrise(observer, today, timezone) 87 | sunrise_today_is = sunrise_today.strftime('🌅 %H:%m:%S') 88 | sunrise_tomorrow = sun.sunrise(observer, tomorrow, timezone) 89 | sunrise_tomorrow_is = sunrise_today.strftime('🌅 %H:%m:%S') 90 | 91 | sunset_today = sun.sunset(observer, today, timezone) 92 | sunset_today_is = sunset_today.strftime('🌇 %H:%m:%S') 93 | sunset_tomorrow = sun.sunset(observer, tomorrow, timezone) 94 | sunset_tomorrow_is = sunset_tomorrow.strftime('🌇 %H:%m:%S') 95 | 96 | moon_today = moon.phase() 97 | 98 | if 0 <= moon_today <= 6.99: 99 | moon_today_is = '🌚' 100 | elif 7 <= moon_today <= 13.99: 101 | moon_today_is = '🌓' 102 | elif 14 <= moon_today <= 20.99: 103 | moon_today_is = '🌝' 104 | elif 21 <= moon_today <= 27.99: 105 | moon_today_is = '🌗' 106 | 107 | print("{} {} {} {} {:.1f} {} {}".format( 108 | location.name, 109 | sunrise_today_is, 110 | sunset_today_is, 111 | moon_today_is, 112 | moon_today, 113 | sunrise_tomorrow_is, 114 | sunset_tomorrow_is)) 115 | 116 | 117 | regex = '^!?(astral|p\u00E4ike)\\s*' 118 | 119 | if 'CONFIG' in os.environ: 120 | print(regex) 121 | sys.exit(0) 122 | 123 | if len(sys.argv) != 2: 124 | print('Error?') 125 | sys.exit(0) 126 | 127 | arg = re.sub(regex, '', sys.argv[1], flags=re.IGNORECASE).lower() 128 | 129 | if arg == '?': 130 | print_places() 131 | else: 132 | print_place(arg) 133 | -------------------------------------------------------------------------------- /scripts/twitter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo 'tweet|twitter|^tweet .*$|^twitter .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # rsstail must be installed 17 | type rsstail >/dev/null 2>&1 || { 18 | echo "This script requires that you install the packge \"rsstail\" on the server." 19 | exit 0 20 | } 21 | 22 | function readrss() { 23 | feeddata=$($TORIFY rsstail -1 -ldpazPH -u "$1" -n "$2" 2>&1) 24 | if [ "$(echo "$feeddata" | xargs)" == "" ] || [ "$feeddata" == "Error reading RSS feed: Parser error" ]; then 25 | echo "Can't screenscrape Twitter right now. Rate limits are in place. Come back later. ($1)" 26 | return 0 27 | fi 28 | echo "Fetching latest $2 items from feed \"$1\"..." 29 | # if there are 3 newlines, it will generate separate posts, but it is nicer and more compact if everything is nicely bundled into 1 post 30 | # so, first we use sed to remove all occurances of 5, 4, and 3 newlines. 31 | # Then we insert 2 newlines after the last newline to create 3 newlines, so that at the end of the feed item the Matrix message is split. 32 | # This way N feed posts always create exactly N Matrix messages. 33 | # Inserting newlines with sed: https://unix.stackexchange.com/questions/429139/replace-newlines-with-sed-a-la-tr 34 | echo "$feeddata" | sed 'H;1h;$!d;x; s/\n\n\n\n\n/\n\n/g' | sed 'H;1h;$!d;x; s/\n\n\n\n/\n\n/g' | sed 'H;1h;$!d;x; s/\n\n\n/\n\n/g' | 35 | sed '/Pub.date: /a \\n\n' # add newlines for separation after last feed item line 36 | } 37 | 38 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) # twitter user name, required 39 | arg2=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 3) # number of items (optional) or "notorify" 40 | arg3=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 4) # "notorify" or empty 41 | #echo "rss: arguments : \"$1\"" 42 | #echo "rss: argument 1: \"$arg1\"" 43 | #echo "rss: argument 2: \"$arg2\"" 44 | if [ "$arg1" == "" ]; then 45 | echo "Example Twitter user names are: aantonom adam3us balajis elonmusk naval NickZsabo4" 46 | echo "Try \"tweet elonmusk 2\" for example to get the latest 2 tweets from Elon." 47 | exit 0 48 | fi 49 | 50 | if [ "$arg2" == "" ]; then 51 | arg2="1" # default, get only last item, if no number specified 52 | fi 53 | 54 | if [ "$arg2" == "notorify" ] || [ "$arg3" == "notorify" ]; then 55 | TORIFY="" 56 | echo "Are you sure you do not want to use TOR?" 57 | if [ "$arg2" == "notorify" ]; then 58 | arg2="1" 59 | fi 60 | fi 61 | 62 | case "$arg2" in 63 | '' | *[!0-9]*) 64 | echo "Second argument is not a number. Skipping. Try \"tweet elonmusk 1\"." 65 | exit 0 66 | ;; 67 | *) 68 | # echo "First argument is a number. " 69 | ;; 70 | esac 71 | 72 | 73 | function dofeed() { 74 | arg1="$1" 75 | arg2="$2" 76 | case "$arg1" in 77 | all) 78 | for feed in aantonop adam3us balajis Blockstream elonmusk naval jimmysong NickZsabo4; do 79 | dofeed "$feed" "$arg2" 80 | echo -e "\n\n\n" 81 | done 82 | ;; 83 | *) 84 | readrss "https://twitrss.me/twitter_user_to_rss/?user=${arg1}" "$arg2" 85 | ;; 86 | esac 87 | } 88 | 89 | dofeed "$arg1" "$arg2" 90 | 91 | exit 0 92 | 93 | # The __reply env variable set in the config file is not used in this script 94 | #if [ -n "$__reply" ] 95 | #then 96 | # echo "$__reply" 97 | #else 98 | # echo 'P O N G' 99 | #fi 100 | -------------------------------------------------------------------------------- /scripts/mn: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^mn$|^mn .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) 17 | #echo "mn: argument 1: \"$arg1\"" 18 | if [ "$arg1" == "" ]; then 19 | arg1=1 # default value if none given by user 20 | fi 21 | case "$arg1" in 22 | '' | *[!0-9]*) 23 | echo "First argument is not a number. Skipping. Try \"mn\" or \"mn 2\"." 24 | exit 0 25 | ;; 26 | *) 27 | # echo "First argument is a number. " 28 | ;; 29 | esac 30 | 31 | case "$arg1" in 32 | '' | 1) 33 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1] | .url, .title , .content ' 2>>/dev/null 34 | ;; 35 | 2) 36 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 37 | ;; 38 | 3) 39 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 40 | ;; 41 | 4) 42 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 43 | ;; 44 | 5) 45 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 46 | ;; 47 | 6) 48 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 49 | ;; 50 | 7) 51 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 52 | ;; 53 | 8) 54 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 55 | ;; 56 | 9) 57 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 58 | ;; 59 | 10) 60 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 61 | ;; 62 | 11) 63 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10,11] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 64 | ;; 65 | 12) 66 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10,11,12] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 67 | ;; 68 | 13) 69 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10,11,12,13] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 70 | ;; 71 | 14) 72 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10,11,12,13,14] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 73 | ;; 74 | 15) 75 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] | .url, .title , .content ' | sed '0~3 s/$/\n\n/g' 2>>/dev/null 76 | ;; 77 | *) 78 | echo "You want too many or you want something foolish. I will give you 1 news article" 79 | $TORIFY curl --silent --compressed "https://data.messari.io/api/v1/news" | jq '.data[1] | .url, .title , .content ' 2>>/dev/null 80 | ;; 81 | esac 82 | 83 | #if [ -n "$__reply" ] 84 | #then 85 | # echo "$__reply" 86 | #else 87 | # echo 'P O N G' 88 | #fi 89 | -------------------------------------------------------------------------------- /scripts/restart: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^restart$|^reset$|^restart .*$|^reset .*$' 5 | exit 0 6 | fi 7 | 8 | args=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2-) 9 | #echo "restart: arguments: \"$args\"" 10 | if [ "$args" == "" ]; then 11 | echo "You must be restarting something. Try \"restart bot\" or \"restart matrix\"." 12 | exit 0 13 | fi 14 | arg1=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 1) 15 | arg2=$(echo "$args" | tr -s ' ' | cut -d ' ' -f 2) 16 | 17 | function dorestart() { 18 | arg1="$1" 19 | arg2="$2" 20 | case "${arg1,,}" in 21 | "bot" | "ibot") 22 | echo "The bot will reset itself." 23 | # THIS WILL ONLY WORK IF THE ACCOUNT UNDER WHICH THIS IS EXECUTED HAS PERMISSIONS TO DO SUDO! 24 | p="tiny-matrix-bot" 25 | sudo systemctl restart "$p" || 26 | { 27 | echo "Error while trying to restart service \"$p\". systemctl restart \"$p\" failed. Maybe due to missing permissions?" 28 | return 0 29 | } 30 | # the following output will go nowhere, nothing will be returned to user 31 | echo "The bot did restart." 32 | systemctl status tiny-matrix-bot 33 | ;; 34 | "world") 35 | echo "Reseting world order. Done!" 36 | ;; 37 | "matrix") 38 | echo "The bot will reset Matrix service" 39 | # the name of the service might vary based on installation from : synapse-matrix, matrix, etc. 40 | # let's be reckless and reset all services that contain "matrix" in their name 41 | # THIS WILL ONLY WORK IF THE ACCOUNT UNDER WHICH THIS IS EXECUTED HAS PERMISSIONS TO DO SUDO! 42 | service --status-all | grep -i matrix | tr -s " " | cut -d " " -f 5 | while read -r p; do 43 | sudo systemctl stop "$p" || 44 | { 45 | echo "Error while trying to stop service \"$p\". systemctl stop \"$p\" failed. Maybe due to missing permissions?" 46 | return 0 47 | } 48 | sleep 1 49 | echo "Service \"$p\" was stopped successfully." 50 | sudo systemctl start "$p" || 51 | { 52 | echo "Error while trying to start service \"$p\". systemctl start \"$p\" failed. Maybe due to missing permissions?" 53 | return 0 54 | } 55 | sleep 1 56 | echo "Service \"$p\" was started successfully." 57 | echo "Status of service \"$p\" is:" 58 | systemctl status "$p" 59 | done 60 | # output will be shown by bot after Matrix restarts and bot reconnects. 61 | ;; 62 | "os") 63 | # in order to reboot OS, one must provide a password 64 | # we compare the hashes here, add your hash here 65 | if [ "$(echo "$arg2" | sha256sum | cut -d ' ' -f 1)" == "123456781234567891234567812345678123456781234567891234567812345678" ]; then 66 | echo "The bot will reboot the server" 67 | sudo systemctl reboot 68 | else 69 | echo "Argument missing or argument wrong. Command ignored due to lack of permissions." 70 | fi 71 | ;; 72 | *) 73 | echo "The bot does not know how to restart ${arg1}." 74 | echo "Only \"bot\", \"matrix\", \"os\", and \"world\" are configured on server." 75 | ;; 76 | esac 77 | } 78 | 79 | dorestart "$arg1" "$arg2" 80 | 81 | exit 0 82 | 83 | # The __reply env variable set in the config file is not used in this script 84 | #if [ -n "$__reply" ] 85 | #then 86 | # echo "$__reply" 87 | #else 88 | # echo 'P O N G' 89 | #fi 90 | -------------------------------------------------------------------------------- /scripts/weather: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^weather$|^tiempo$|^wetter$|^temps$|^weather .*$|^tiempo .*$|^eltiempo .*$|^wetter .*$|^temps .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # ansiweather must be installed 17 | type ansiweather >/dev/null 2>&1 || { 18 | # see: https://github.com/fcambus/ansiweather 19 | echo "This script requires that you install the packge \"ansiweather\" on the server." 20 | exit 0 21 | } 22 | 23 | # $1: location, city 24 | # $2: optional, "full" for more details 25 | function getweather() { 26 | if [[ "$2" == "full" ]] || [[ "$2" == "f" ]] || [[ "$2" == "more" ]] || [[ "$2" == "+" ]]; then 27 | # give a full, long listing of forecast 28 | torify curl "wttr.in/${1%,*}?m" # remove everything to the right of comma 29 | elif [[ "$2" == "short" ]] || [[ "$2" == "less" ]] || [[ "$2" == "s" ]] || [[ "$2" == "l" ]] || [[ "$2" == "-" ]]; then 30 | # give a short, terse listing of forecast 31 | torify curl "wttr.in/${1%,*}?m&format=%l:+%C+%t+(%f)+%o+%p" # remove everything to the right of comma 32 | else 33 | # give a mediaum, default listing of forecast 34 | $TORIFY ansiweather -l "$1" | tr "-" "\n" | tr "=>" "\n" 2>&1 35 | fi 36 | } 37 | 38 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) # tweather-location, city, required 39 | arg2=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 3) # "full" (optional) or "short" (optional) or "notorify" (optional) or empty 40 | arg3=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 4) # "notorify" or empty 41 | #echo "arguments : \"$1\"" 42 | #echo "argument 1: \"$arg1\"" 43 | #echo "argument 2: \"$arg2\"" 44 | if [ "$arg1" == "" ]; then 45 | echo "Example weather locations are: paris london san-diego new-york" 46 | echo "Try \"weather melbourne\" for example to get the Melbourne weather forecast." 47 | echo "Try \"weather France\" for example to get the French weather forecast." 48 | echo "Try \"weather New+York,US\" for example to get the NYC weather forecast." 49 | echo "Try adding full, short, + or - at the end to get more or less information, like \"weather paris +\"." 50 | exit 0 51 | fi 52 | 53 | #if [ "$arg2" == "" ]; then 54 | # arg2="1" # default, get only last item, if no number specified 55 | #fi 56 | 57 | if [ "$arg2" == "notorify" ] || [ "$arg3" == "notorify" ]; then 58 | TORIFY="" 59 | echo "Are you sure you do not want to use TOR?" 60 | if [ "$arg2" == "notorify" ]; then 61 | arg2="$arg3" 62 | fi 63 | fi 64 | 65 | function doweather() { 66 | arg1="${1,,}" 67 | arg2="${2,,}" 68 | case "$arg1" in 69 | all) 70 | for city in san-francisco san-diego paris lima,pe hamburg,de; do 71 | doweather "$city" "$arg2" 72 | echo -e "\n\n\n" 73 | done 74 | ;; 75 | l | london) 76 | getweather "London,GB" "$arg2" 77 | ;; 78 | m | melbourne) 79 | getweather "Melbourne,AU" "$arg2" 80 | ;; 81 | ny | nyc | new-york) 82 | getweather "New+York,US" "$arg2" 83 | ;; 84 | p | paris) 85 | getweather "Paris,FR" "$arg2" 86 | ;; 87 | sd | san-diego) 88 | getweather "San+Diego,US" "$arg2" 89 | ;; 90 | sf | san-fran | san-francisco) 91 | getweather "San+Francisco,US" "$arg2" 92 | ;; 93 | sk | st-kilda) 94 | getweather "St+Kilda,AU" "$arg2" 95 | ;; 96 | w | vienna) 97 | getweather "Vienna,AT" "$arg2" 98 | ;; 99 | # add your own favorite city here, see https://wttr.in for names of cities 100 | *) 101 | getweather "$arg1" "$arg2" 102 | ;; 103 | esac 104 | } 105 | 106 | doweather "$arg1" "$arg2" 107 | 108 | exit 0 109 | 110 | # The __reply env variable set in the config file is not used in this script 111 | #if [ -n "$__reply" ] 112 | #then 113 | # echo "$__reply" 114 | #else 115 | # echo 'P O N G' 116 | #fi 117 | -------------------------------------------------------------------------------- /scripts/unused/dict: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | data_file = $file; 16 | 17 | if ( file_exists( $this->data_file ) ) 18 | $load = file_get_contents( $this->data_file ); 19 | else 20 | $load = ''; 21 | 22 | $this->data_checksum = md5( $load ); 23 | 24 | if ( empty( $load ) ) 25 | $this->data = array(); 26 | else 27 | $this->data = json_decode( $load, true ); 28 | } 29 | 30 | function __destruct() 31 | { 32 | if ( md5( ( $save = json_encode( $this->data ) ) ) != $this->data_checksum ) 33 | file_put_contents( $this->data_file, $save ); 34 | } 35 | 36 | function __toString() 37 | { 38 | $keys = array_keys( $this->data ); 39 | sort( $keys ); 40 | return implode( ', ', $keys ); 41 | } 42 | 43 | function add( $key, $value ) 44 | { 45 | if ( empty( $value ) ) 46 | return false; 47 | foreach ( explode( '|', $value ) as $v ) 48 | $this->data[ $key ][] = trim( $v ); 49 | return true; 50 | } 51 | 52 | function bite( $key ) 53 | { 54 | if ( isset( $this->data[ $key ] ) ) 55 | array_pop( $this->data[ $key ] ); 56 | else 57 | return false; 58 | if ( empty( $this->data[ $key ] ) ) 59 | unset( $this->data[ $key ] ); 60 | return true; 61 | } 62 | 63 | function forget( $key ) 64 | { 65 | if ( ! isset( $this->data[ $key ] ) ) 66 | return false; 67 | unset( $this->data[ $key ] ); 68 | return true; 69 | } 70 | 71 | function show( $key ) 72 | { 73 | if ( isset( $this->data[ $key ] ) ) 74 | return sprintf( '%s = %s', $key, implode( ' | ', $this->data[ $key ] ) ); 75 | else 76 | return $this->search( $key ); 77 | } 78 | 79 | function search( $search ) 80 | { 81 | $r = array(); 82 | foreach ( $this->data as $n => $v ) 83 | { 84 | if ( false !== stripos( $n, $search ) ) 85 | $r[] = $n; 86 | foreach ( $v as $vv ) 87 | if ( false !== stripos( $vv, $search ) ) 88 | $r[] = $n; 89 | } 90 | $r = array_unique( $r ); 91 | if ( ! empty( $r ) ) 92 | return sprintf( '%s?', implode( ', ', $r ) ); 93 | else 94 | return false; 95 | } 96 | } 97 | 98 | $a = explode( ' ', $argv[ 1 ] ); 99 | $c = $a[ 0 ]; 100 | array_shift( $a ); 101 | $i = implode( ' ', $a ); 102 | 103 | if ( false === ( $p = strpos( $i, '=' ) ) ) 104 | $k = $i; 105 | 106 | else 107 | { 108 | $k = substr( $i, 0, $p ); 109 | $v = trim( substr( $i, $p + 1 ) ); 110 | } 111 | 112 | $k = strtolower( trim( $k ) ); 113 | 114 | $d = new dict( 'dict.db' ); 115 | 116 | switch ( $c ) 117 | { 118 | case 'dict?': 119 | echo $d; 120 | break; 121 | 122 | case '!add': 123 | if ( $d->add( $k, $v ) ) 124 | { 125 | if ( is_string( $s = $d->show( $k ) ) ) 126 | echo $s; 127 | else 128 | echo 'midagi on katki'; 129 | } 130 | else printf( 'ei saanud aru', $k ); 131 | break; 132 | 133 | case '!bite': 134 | if ( $d->bite( $k ) ) 135 | { 136 | if ( is_string( $s = $d->show( $k ) ) ) 137 | echo $s; 138 | else 139 | printf( 'viimane amps, %s unustatud', $k ); 140 | } 141 | else printf( '%s ei eksisteeri', $k ); 142 | break; 143 | 144 | case '!forget': 145 | if ( $d->forget( $k ) ) 146 | printf( '%s unustatud', $k ); 147 | else 148 | printf( '%s ei eksisteeri', $k ); 149 | break; 150 | 151 | case '!brainwash': 152 | if ( $d->forget( $k ) ) 153 | { 154 | if ( $d->add( $k, $v ) ) 155 | { 156 | if ( is_string( $s = $d->show( $k ) ) ) 157 | echo $s; 158 | else 159 | echo 'midagi on katki'; 160 | } 161 | else echo 'midagi on katki'; 162 | } 163 | else printf( '%s ei eksisteeri', $k ); 164 | break; 165 | 166 | case '?': 167 | if ( is_string( $s = $d->show( $k ) ) ) 168 | echo $s; 169 | else 170 | printf( '%s ei eksisteeri', $k ); 171 | break; 172 | } 173 | 174 | echo PHP_EOL; 175 | -------------------------------------------------------------------------------- /scripts/rss: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^rss$|^feed$|^rss .*$|^feed .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify > /dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # rsstail must be installed 17 | type rsstail > /dev/null 2>&1 || { 18 | echo "This script requires that you install the packge \"rsstail\" on the server." 19 | exit 0 20 | } 21 | 22 | function readrss() { 23 | echo "Fetching latest $2 items from feed \"$1\"..." 24 | # if there 3 newlines, it will generate separate posts, but it is nicer and easier to remove later if everything is nicely bundled into 1 post 25 | # so, first we use sed to remove all occurances of 5, 4, and 3 newlines. 26 | # Then we insert 2 newlines after the last newline to create 3 newlines, so that at the end of the feed item the Matrix message is split. 27 | # This way N feed posts always create exactly N Matrix messages. 28 | # Inserting newlines with sed: https://unix.stackexchange.com/questions/429139/replace-newlines-with-sed-a-la-tr 29 | $TORIFY rsstail -1 -ldpazPH -u "$1" -n $2 | sed 'H;1h;$!d;x; s/\n\n\n\n\n/\n\n/g' | sed 'H;1h;$!d;x; s/\n\n\n\n/\n\n/g' | \ 30 | sed 'H;1h;$!d;x; s/\n\n\n/\n\n/g' | sed '/Pub.date: /a \\n\n' # add newlines for separation after last line 31 | } 32 | 33 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) # rss feed, required 34 | arg2=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 3) # number of items (optional) or "notorify" 35 | arg3=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 4) # "notorify" or empty 36 | #echo "rss: arguments : \"$1\"" 37 | #echo "rss: argument 1: \"$arg1\"" 38 | #echo "rss: argument 2: \"$arg2\"" 39 | if [ "$arg1" == "" ]; then 40 | echo -n "Currently supported feeds are: " 41 | echo "all, affaires, andreas, ars1, ars2, ars3, btc, coin, citron, core, futura, hn, jimmy, matrix, noon, pine, qubes, trezor" 42 | echo "Try \"rss pine 2\" for example to get the latest 2 news items from Pine64.org News RSS feed." 43 | exit 0 44 | fi 45 | 46 | if [ "$arg2" == "" ]; then 47 | arg2="1" # default, get only last item, if no number specified 48 | fi 49 | 50 | if [ "$arg2" == "notorify" ] || [ "$arg3" == "notorify" ]; then 51 | TORIFY="" 52 | echo "Are you sure you do not want to use TOR?" 53 | if [ "$arg2" == "notorify" ]; then 54 | arg2="1" 55 | fi 56 | fi 57 | 58 | case "$arg2" in 59 | '' | *[!0-9]*) 60 | echo "Second argument is not a number. Skipping. Try \"rss pine 1\"." 61 | exit 0 62 | ;; 63 | *) 64 | # echo "First argument is a number. " 65 | ;; 66 | esac 67 | 68 | function dofeed() { 69 | arg1="$1" 70 | arg2="$2" 71 | case "$arg1" in 72 | all) 73 | for feed in affaires andreas ars1 ars2 ars3 btc citron coin core futura jimmy matrix noon pine qubes trezor; do 74 | dofeed "$feed" "$arg2" 75 | echo -e "\n\n\n" 76 | done 77 | ;; 78 | affaires) 79 | readrss "https://www.lesaffaires.com/rss/techno/internet" "$arg2" 80 | ;; 81 | andreasm) 82 | readrss "https://medium.com/feed/@aantonop" "$arg2" 83 | ;; 84 | andreas) 85 | readrss "https://twitrss.me/twitter_user_to_rss/?user=aantonop" "$arg2" 86 | ;; 87 | ars1) 88 | readrss "http://feeds.arstechnica.com/arstechnica/technology-lab" "$arg2" 89 | ;; 90 | ars2) 91 | readrss "http://feeds.arstechnica.com/arstechnica/features" "$arg2" 92 | ;; 93 | ars3) 94 | readrss "http://feeds.arstechnica.com/arstechnica/gadgets" "$arg2" 95 | ;; 96 | btc) 97 | readrss "https://bitcoin.org/en/rss/blog.xml" "$arg2" 98 | ;; 99 | citron) 100 | TORIFYBEFORE=$TORIFY # temporarily turn TORIFY off because citron does not work under TOR 101 | TORIFY="" 102 | readrss "https://www.presse-citron.net/feed/" "$arg2" 103 | TORIFY=$TORIFYBEFORE 104 | ;; 105 | coin) 106 | readrss "https://www.coindesk.com/feed?x=1" "$arg2" 107 | ;; 108 | core) 109 | readrss "https://bitcoincore.org/en/rss.xml" "$arg2" 110 | ;; 111 | futura) 112 | # readrss "https://www.futura-sciences.com/rss/actualites.xml" "$arg2" 113 | readrss "https://www.futura-sciences.com/rss/high-tech/actualites.xml" "$arg2" 114 | ;; 115 | hn) 116 | readrss "https://hnrss.org/frontpage" "$arg2" 117 | ;; 118 | jimmy) 119 | readrss "https://medium.com/feed/@jimmysong" "$arg2" 120 | ;; 121 | matrix) 122 | readrss "https://matrix.org/blog/feed/" "$arg2" 123 | ;; 124 | noon) 125 | readrss "https://hackernoon.com/feed" "$arg2" 126 | ;; 127 | pine) 128 | readrss "https://www.pine64.org/feed/" "$arg2" 129 | ;; 130 | qubes) 131 | readrss "https://www.qubes-os.org/feed.xml" "$arg2" 132 | ;; 133 | trezor) 134 | readrss "https://blog.trezor.io/feed/" "$arg2" 135 | ;; 136 | *) 137 | echo "This feed is not configured on server." 138 | ;; 139 | esac 140 | } 141 | 142 | dofeed "$arg1" "$arg2" 143 | 144 | exit 0 145 | 146 | #if [ -n "$__reply" ] 147 | #then 148 | # echo "$__reply" 149 | #else 150 | # echo 'P O N G' 151 | -------------------------------------------------------------------------------- /tiny-matrix-bot.cfg.feature-rich.sample: -------------------------------------------------------------------------------- 1 | [tiny-matrix-bot] 2 | base_url = https://matrix.example.com 3 | token = SuperSecretToken 4 | #run_path = run 5 | #scripts_path = scripts 6 | enabled_scripts = ping,pong,help,cputemp,disks,hn,btc,eth,mn,ddg,web,restart,wake,update,check,motd,hello,pick,firewall,backup,totp,datetime,weather,tides,rss,twitter,tesla,platform,ps,top,alert,users,s2f 7 | #inviter = :example\.com$ 8 | 9 | [help] 10 | #whitelist = \!rOomId1:example\.com 11 | #blacklist = (@spammer|\!roOMid2):example\.com 12 | reply = Try: ping, pong, cputemp, disks, hn, btc, s2f, eth, mn, ddg, web, restart, wake, hello, update, check, motd, pick, firewall, backup, totp, date, weather, tides, rss, twitter, tesla, platform, ps, top, alert, users. 13 | # format can be: text, html, or code. If not set it is "text" by default. 14 | format = text 15 | 16 | [ping] 17 | #whitelist = \!rOomId1:example\.com 18 | #blacklist = (@spammer|\!roOMid2):example\.com 19 | reply = PONG! 20 | format = text 21 | 22 | [pong] 23 | #whitelist = \!rOomId1:example\.com 24 | #blacklist = (@spammer|\!roOMid2):example\.com 25 | reply = PING! 26 | format = html 27 | 28 | [cputemp] 29 | #whitelist = \!rOomId1:example\.com 30 | #blacklist = (@spammer|\!roOMid2):example\.com 31 | reply = Shall I put on a jacket? 32 | 33 | [disks] 34 | #whitelist = \!rOomId1:example\.com 35 | #blacklist = (@spammer|\!roOMid2):example\.com 36 | reply = I am hungry. Give me space :) 37 | # format the output like code, like ```text``` 38 | format = code 39 | 40 | [hn] 41 | #whitelist = \!rOomId1:example\.com 42 | #blacklist = (@spammer|\!roOMid2):example\.com 43 | reply = Read hn somewhere else :) 44 | 45 | [btc] 46 | #whitelist = \!rOomId1:example\.com 47 | #blacklist = (@spammer|\!roOMid2):example\.com 48 | reply = Ticker :) 49 | 50 | [eth] 51 | #whitelist = \!rOomId1:example\.com 52 | #blacklist = (@spammer|\!roOMid2):example\.com 53 | reply = Ticker :) 54 | 55 | [mn] 56 | #whitelist = \!rOomId1:example\.com 57 | #blacklist = (@spammer|\!roOMid2):example\.com 58 | reply = Messari News :) 59 | 60 | [ddg] 61 | #whitelist = \!rOomId1:example\.com 62 | #blacklist = (@spammer|\!roOMid2):example\.com 63 | reply = Duck duck goes :) 64 | 65 | [web] 66 | #whitelist = \!rOomId1:example\.com 67 | #blacklist = (@spammer|\!roOMid2):example\.com 68 | reply = Surfing U.S.A. :) 69 | 70 | [restart] 71 | #whitelist = \!rOomId1:example\.com 72 | #blacklist = (@spammer|\!roOMid2):example\.com 73 | reply = Restarting services ... 74 | 75 | [wake] 76 | #whitelist = \!rOomId1:example\.com 77 | #blacklist = (@spammer|\!roOMid2):example\.com 78 | reply = Wake up another PC via LAN ... 79 | 80 | [check] 81 | #whitelist = \!rOomId1:example\.com 82 | #blacklist = (@spammer|\!roOMid2):example\.com 83 | reply = Checking for status, health status, updates, etc ... 84 | 85 | [motd] 86 | #whitelist = \!rOomId1:example\.com 87 | #blacklist = (@spammer|\!roOMid2):example\.com 88 | reply = Message from our leader :) 89 | 90 | [update] 91 | #whitelist = \!rOomId1:example\.com 92 | #blacklist = (@spammer|\!roOMid2):example\.com 93 | reply = Updating stuff :) 94 | 95 | [hello] 96 | #whitelist = \!rOomId1:example\.com 97 | #blacklist = (@spammer|\!roOMid2):example\.com 98 | reply = I will return a compliment :) 99 | 100 | [pick] 101 | #whitelist = \!rOomId1:example\.com 102 | #blacklist = (@spammer|\!roOMid2):example\.com 103 | reply = pizza or hamburgers or salad 104 | 105 | [firewall] 106 | #whitelist = \!rOomId1:example\.com 107 | #blacklist = (@spammer|\!roOMid2):example\.com 108 | reply = List firewall settings 109 | format = code 110 | 111 | [backup] 112 | #whitelist = \!rOomId1:example\.com 113 | #blacklist = (@spammer|\!roOMid2):example\.com 114 | reply = Create backup of important files 115 | 116 | [totp] 117 | #whitelist = \!rOomId1:example\.com 118 | #blacklist = (@spammer|\!roOMid2):example\.com 119 | reply = Return TOTP code (PIN) 120 | 121 | [datetime] 122 | #whitelist = \!rOomId1:example\.com 123 | #blacklist = (@spammer|\!roOMid2):example\.com 124 | reply = Return time and date 125 | format = code 126 | 127 | [weather] 128 | #whitelist = \!rOomId1:example\.com 129 | #blacklist = (@spammer|\!roOMid2):example\.com 130 | reply = Return weather forecast 131 | format = code 132 | 133 | [tides] 134 | #whitelist = \!rOomId1:example\.com 135 | #blacklist = (@spammer|\!roOMid2):example\.com 136 | reply = Return tidal forecast 137 | format = code 138 | 139 | [rss] 140 | #whitelist = \!rOomId1:example\.com 141 | #blacklist = (@spammer|\!roOMid2):example\.com 142 | reply = Read RSS feeds 143 | 144 | [twitter] 145 | #whitelist = \!rOomId1:example\.com 146 | #blacklist = (@spammer|\!roOMid2):example\.com 147 | reply = Read Twitter feeds 148 | 149 | [tesla] 150 | #whitelist = \!rOomId1:example\.com 151 | #blacklist = (@spammer|\!roOMid2):example\.com 152 | reply = Chat with Tesla car 153 | 154 | [platform] 155 | #whitelist = \!rOomId1:example\.com 156 | #blacklist = (@spammer|\!roOMid2):example\.com 157 | reply = Example with Python program 158 | 159 | [ps] 160 | #whitelist = \!rOomId1:example\.com 161 | #blacklist = (@spammer|\!roOMid2):example\.com 162 | reply = ps, CPU/RAM/disk utilization 163 | 164 | [top] 165 | #whitelist = \!rOomId1:example\.com 166 | #blacklist = (@spammer|\!roOMid2):example\.com 167 | reply = Lists top 5 CPU and RAM consuming processes 168 | format = code 169 | 170 | [alert] 171 | #whitelist = \!rOomId1:example\.com 172 | #blacklist = (@spammer|\!roOMid2):example\.com 173 | reply = Only prints msg if an CPU, RAM or disk usage is beyond an alert level 174 | 175 | [users] 176 | #whitelist = \!rOomId1:example\.com 177 | #blacklist = (@spammer|\!roOMid2):example\.com 178 | reply = List registered Matrix users 179 | 180 | [s2f] 181 | #whitelist = \!rOomId1:example\.com 182 | #blacklist = (@spammer|\!roOMid2):example\.com 183 | reply = Stock-to-Flow ratio of BTC from messari.io API 184 | format = code 185 | 186 | ################################################## 187 | -------------------------------------------------------------------------------- /scripts/tides: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo '^tide$|^tides$|^marea|^mareas|^tide .*$|^tides .*$|^marea .*$|^mareas .*$|^gehzeiten .*$' 5 | exit 0 6 | fi 7 | 8 | TORIFY="torify" 9 | 10 | # tor and torify should be installed for your privacy. 11 | type torify >/dev/null 2>&1 || { 12 | echo "It is recommended that you install the packge \"tor\" on the server for privacy." 13 | TORIFY="" 14 | } 15 | 16 | # xmllint must be installed 17 | type xmllint >/dev/null 2>&1 || { 18 | # see: https://github.com/fcambus/ansiweather 19 | echo "This script requires that you install the packge \"xmllint\" (libxml2-utils) on the server." 20 | exit 0 21 | } 22 | 23 | # $1: location, city 24 | # $2: optional, "full" for more details 25 | function gettide() { 26 | if [[ "$2" == "full" ]] || [[ "$2" == "f" ]] || [[ "$2" == "more" ]] || [[ "$2" == "+" ]]; then 27 | # give a full, long listing of forecast 28 | echo "To be implemented" # to be implemented 29 | elif [[ "$2" == "short" ]] || [[ "$2" == "less" ]] || [[ "$2" == "s" ]] || [[ "$2" == "l" ]] || [[ "$2" == "-" ]]; then 30 | # give a short, terse listing of forecast 31 | echo -n "${1^}: " 32 | # shellcheck disable=SC2086 33 | $TORIFY wget -q -O - https://www.tide-forecast.com/locations/${1}/tides/latest | \ 34 | xmllint --html --xpath '//table[@class = "tide-times__table--table"]/tbody/tr/td' - 2>/dev/null | \ 35 | sed "s|| |g" | sed "s|| |g" | sed "s|| |g" | \ 36 | sed "s|| |g" | sed 's|| |g' | \ 37 | sed 's|| |g' | \ 38 | sed 's|| |g' | \ 39 | sed 's|| |g' | \ 40 | sed "s|||g" | tr -d '\n' | sed "s|Low Tide|\nLow Tide|g" | sed "s|High Tide|\nHigh Tide|g" | \ 41 | sed 's|([^)]*)||g' | sed 's| | |g' | sed 's| Tide | |g' | sed 's|m |m|g' | sed 's| m|m|g' 42 | echo "" # add newline 43 | else 44 | # give a mediaum, default listing of tides, just today 45 | echo -n "${1^}: " 46 | # shellcheck disable=SC2086 47 | $TORIFY wget -q -O - https://www.tide-forecast.com/locations/${1}/tides/latest | \ 48 | xmllint --html --xpath '//table[@class = "tide-times__table--table"]/tbody/tr/td' - 2>/dev/null | \ 49 | sed "s|| |g" | sed "s|| |g" | sed "s|| |g" | \ 50 | sed "s|| |g" | sed 's|| |g' | \ 51 | sed 's|| |g' | \ 52 | sed 's|| |g' | \ 53 | sed 's|| |g' | \ 54 | sed "s|||g" | tr -d '\n' | sed "s|Low Tide|\nLow Tide|g" | sed "s|High Tide|\nHigh Tide|g" | \ 55 | sed 's|) |)|g' 56 | echo "" # add newline 57 | fi 58 | } 59 | 60 | arg1=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 2) # tide-location, city, required 61 | arg2=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 3) # "full" (optional) or "short" (optional) or "notorify" (optional) or empty 62 | arg3=$(echo "$1" | tr -s ' ' | cut -s -d ' ' -f 4) # "notorify" or empty 63 | #echo "arguments : \"$1\"" 64 | #echo "argument 1: \"$arg1\"" 65 | #echo "argument 2: \"$arg2\"" 66 | if [ "$arg1" == "" ]; then 67 | echo "Example tide locations are: hamburg san-diego new-york san-fran" 68 | echo "Try \"tide hamburg\" for example to get the Hamburg tide forecast." 69 | exit 0 70 | fi 71 | 72 | #if [ "$arg2" == "" ]; then 73 | # arg2="1" # default, get only last item, if no number specified 74 | #fi 75 | 76 | if [ "$arg2" == "notorify" ] || [ "$arg3" == "notorify" ]; then 77 | TORIFY="" 78 | echo "Are you sure you do not want to use TOR?" 79 | if [ "$arg2" == "notorify" ]; then 80 | arg2="$arg3" 81 | fi 82 | fi 83 | 84 | function dotide() { 85 | arg1="${1,,}" 86 | arg2="${2,,}" 87 | case "$arg1" in 88 | all) 89 | for city in san-francisco san-diego lima; do 90 | dotide "$city" "$arg2" 91 | echo -e "\n\n\n" 92 | done 93 | ;; 94 | h | hamburg) 95 | gettide "Hamburg-Germany" "$arg2" 96 | ;; 97 | l | london) 98 | gettide "London-Bridge-England" "$arg2" 99 | ;; 100 | m | melbourne) 101 | gettide "Melbourne-Australia" "$arg2" 102 | ;; 103 | ny | nyc | new-york) 104 | gettide "New-York-New-York" "$arg2" 105 | ;; 106 | p | pornic) 107 | gettide "Pornic" "$arg2" # France 108 | ;; 109 | sd | san-diego) 110 | gettide "San-Diego-California" "$arg2" 111 | ;; 112 | sf | san-fran | san-francisco) 113 | gettide "San-Francisco-California" "$arg2" 114 | ;; 115 | urangan) 116 | gettide "Urangan-Australia" "$arg2" 117 | ;; 118 | # see https://www.tide-forecast.com for names to add as your favorite beaches 119 | *) 120 | gettide "$arg1" "$arg2" 121 | ;; 122 | esac 123 | } 124 | 125 | dotide "$arg1" "$arg2" 126 | 127 | exit 0 128 | 129 | # The __reply env variable set in the config file is not used in this script 130 | #if [ -n "$__reply" ] 131 | #then 132 | # echo "$__reply" 133 | #else 134 | # echo 'P O N G' 135 | #fi 136 | -------------------------------------------------------------------------------- /tiny-matrix-bot-send-msg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ############################################################################################## 4 | # Global vars, Defaults 5 | ############################################################################################## 6 | 7 | # Add tiny-matrix-bot.py to your path or provide full path in the next line. 8 | APP="tiny-matrix-bot.py" 9 | # APP="/home/FULL/PATH/HERE/tiny-matrix-bot/tiny-matrix-bot.py" 10 | # Put a valid bot Matrix room Id into the next line 11 | ROOMDEFAULT='!YourRoomId:yourhomeserver.org' 12 | 13 | ############################################################################################## 14 | # Argument Parsing 15 | ############################################################################################## 16 | 17 | # argument parsing: 18 | # see: https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash 19 | 20 | # saner programming env: these switches turn some bugs into errors 21 | set -o errexit -o pipefail -o noclobber -o nounset 22 | 23 | # allow a command to fail with !’s side effect on errexit 24 | # use return value from ${PIPESTATUS[0]}, because ! hosed $? 25 | # shellcheck disable=SC2251 26 | ! getopt --test >/dev/null 27 | if [[ ${PIPESTATUS[0]} -ne 4 ]]; then 28 | echo "I am sorry, \"getopt --test\" failed in this environment. Either not installed or the wrong version. \"getopt --test\" must return 4. Install package getopt first." 29 | exit 1 30 | fi 31 | 32 | OPTIONS=hdfvwcr:m: 33 | LONGOPTS=help,debug,force,verbose,html,code,room:,message: 34 | 35 | function usage() { 36 | echo "${0##*/}: Send a text message to a Matrix chat room as user bot." 37 | echo "${0##*/}: usage: ${0##*/} [-h|--help] [-r|--room RoomId] [-w|--html] [-c|--code] [-m|--message] ... send the provided text to a Matrix chat room" 38 | echo "${0##*/}: usage: ${0##*/} --message \"\" ... send the provided argument as text" 39 | echo "${0##*/}: usage: ${0##*/} ... send the provided arguments as text" 40 | echo "${0##*/}: usage: ${0##*/} ... without arguments, without message, program will read message from stdin (Ctrl-D to stop reading)" 41 | echo "${0##*/}: usage: with --room it will send to the specified room, remember bot must have permissions to send to that room" 42 | echo "${0##*/}: usage: without --room it will send to default bot room" 43 | echo "${0##*/}: usage: without --html it will send in default text format" 44 | echo "${0##*/}: usage: without --code it will send in default text format" 45 | exit 1 46 | } 47 | 48 | # regarding ! and PIPESTATUS see above 49 | # temporarily store output to be able to check for errors 50 | # activate quoting/enhanced mode (e.g. by writing out “--options”) 51 | # pass arguments only via -- "$@" to separate them correctly 52 | # shellcheck disable=SC2251 53 | ! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") 54 | if [[ ${PIPESTATUS[0]} -ne 0 ]]; then 55 | # e.g. return value is 1 56 | # then getopt has complained about wrong arguments to stdout 57 | exit 2 58 | fi 59 | # read getopt’s output this way to handle the quoting right: 60 | eval set -- "$PARSED" 61 | 62 | h=n d=n DEBUG=0 f=n v=n w=n c=n m=n ROOM=$ROOMDEFAULT MESSAGE="$MESSAGEDEFAULT" 63 | # now enjoy the options in order and nicely split until we see -- 64 | while true; do 65 | case "$1" in 66 | -h | --help) 67 | h=y 68 | shift 69 | usage 70 | ;; 71 | -d | --debug) 72 | d=y 73 | DEBUG=1 74 | shift 75 | ;; 76 | -f | --force) 77 | f=y 78 | shift 79 | ;; 80 | -v | --verbose) 81 | v=y 82 | shift 83 | ;; 84 | -w | --html) 85 | w=y 86 | shift 87 | ;; 88 | -c | --code) 89 | c=y 90 | shift 91 | ;; 92 | -r | --room) 93 | ROOM="$2" 94 | shift 2 95 | ;; 96 | -m | --message) 97 | m=y 98 | MESSAGE="$2" 99 | shift 2 100 | ;; 101 | --) 102 | shift 103 | break 104 | ;; 105 | *) 106 | echo "Programming error" 107 | usage 108 | exit 3 109 | ;; 110 | esac 111 | done 112 | 113 | # This is not our case, comment it out 114 | # handle non-option arguments 115 | #if [[ $# -ne 1 ]]; then 116 | # echo "$0: A single input file is required." 117 | # exit 4 118 | #fi 119 | 120 | ############################################################################################## 121 | # Logic, Main 122 | ############################################################################################## 123 | 124 | # handle non-option arguments 125 | if [ "${DEBUG,,}" == "true" ]; then DEBUG="1"; fi 126 | [ "$DEBUG" == "1" ] && echo "${0##*/}: \$# == $#" 127 | if [[ $# -ne 0 ]]; then 128 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Multiple unlabelled arguments found." 129 | if [ "$m" == "y" ]; then 130 | echo "${0##*/}: Use either --message or message text without --message, but not both!" 131 | exit 5 132 | fi 133 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Multiple unlabelled arguments found which are to be interpreted as message text strings." 134 | MESSAGE=$(echo "$@" | xargs) # concatenate all text strings together to form the total msg 135 | fi 136 | 137 | # h=n d=n f=n v=n w=n c=n ROOM="" MESSAGE="" 138 | [ "$DEBUG" == "1" ] && echo "${0##*/}: help: $h, debug: $d, force: $f, verbose: $v, html: $w, code: $c, room: $ROOM, message: $MESSAGE" 139 | 140 | ARGUMENTS="" 141 | if [ "$d" == "y" ]; then ARGUMENTS="$ARGUMENTS --debug"; fi 142 | if [ "$w" == "y" ]; then ARGUMENTS="$ARGUMENTS --html"; fi 143 | if [ "$c" == "y" ]; then ARGUMENTS="$ARGUMENTS --code"; fi 144 | 145 | if [ "$MESSAGE" == "" ]; then 146 | if [ -t 0 ]; then 147 | # echo "stdin is available" 148 | # let $APP read the MESSAGE from keyboard/stdin 149 | # Don't double-quote $ARGUMENTS to avoid empty argument for $APP 150 | # shellcheck disable=SC2086 151 | "$APP" $ARGUMENTS --room "$ROOM" # will read from keyboard 152 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Message from stdin was passed to room \"$ROOM\"." 153 | else 154 | # echo "stdin is NOT available" 155 | MESSAGE=$(cat <&0) 156 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Something is piped into script: \"$MESSAGE\"." 157 | if [ "$MESSAGE" == "" ]; then 158 | [ "$DEBUG" == "1" ] && echo "${0##*/}: No message given, no stdin avaiable, pipe empty, no need to do anything. No message sent to room \"$ROOM\"." 159 | else 160 | # Don't double-quote $ARGUMENTS to avoid empty argument for $APP 161 | # shellcheck disable=SC2086 162 | "$APP" $ARGUMENTS --room "$ROOM" --message "$MESSAGE" 163 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Text message \"$MESSAGE\" from pipe was passed to room \"$ROOM\"." 164 | fi 165 | fi 166 | else 167 | # Don't double-quote $ARGUMENTS to avoid empty argument for $APP 168 | # shellcheck disable=SC2086 169 | "$APP" $ARGUMENTS --room "$ROOM" --message "$MESSAGE" 170 | [ "$DEBUG" == "1" ] && echo "${0##*/}: Text message \"$MESSAGE\" from argument was passed to room \"$ROOM\"." 171 | fi 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tiny-matrix-bot plus 2 | 3 | ![tiny-matrix-bot icon](tmb-150.png) 4 | 5 | This is a simple [Matrix](https://matrix.org) bot based on [matrix-python-sdk](https://github.com/matrix-org/matrix-python-sdk) with no support and no warranty. It was forked from [4nd3r/tiny-matrix-bot](https://github.com/4nd3r/tiny-matrix-bot). 6 | 7 | It is easy to understand, little code, and easy to set up and extend to your personal needs. It is meant for small private Matrix homeservers that are run by individuals for their friends. It is not performant and hence not suitable for industrial size roll-out. 8 | 9 | ## Future 10 | 11 | In mid-July 2020 the project was moved to this new [repository](https://github.com/8go/matrix-eno-bot) and renamed to `matrix-eno-bot`. The reason for this move was that `tiny-matrix-bot plus` is based on [matrix-python-sdk](https://github.com/matrix-org/matrix-python-sdk). Since `matrix-python-sdk` is no longer actively supported and end-to-end-encryption comes out of the box in `matrix-nio`, the switch to the Matrix SDK [matrix-nio](https://github.com/poljar/matrix-nio) and `nio-template` was made. 12 | 13 | #### This bot, i.e. [this repo](https://github.com/8go/tiny-matrix-bot), will *not* be maintained. A maintained bot with similar functionality (but a bit more complexity) will be at [matrix-eno-bot](https://github.com/8go/matrix-eno-bot). 14 | 15 | Even though unmaintained the `tiny-matrix bot plus` still is meaningful for beginners as-is. It is smaller and simpler than `matrix-eno-bot`. An easier entry point for people who just want a simple bot. But if end-to-end-encryption is a strict requirement, then head right over to [matrix-eno-bot](https://github.com/8go/matrix-eno-bot). 16 | 17 | ## Installation and Setup 18 | 19 | ``` 20 | sudo apt install python3 python3-requests 21 | git clone https://github.com/8go/tiny-matrix-bot 22 | git clone https://github.com/matrix-org/matrix-python-sdk 23 | cd tiny-matrix-bot 24 | ln -s ../matrix-python-sdk/matrix_client 25 | cp tiny-matrix-bot.cfg.sample tiny-matrix-bot.cfg 26 | vim tiny-matrix-bot.cfg # adjust the config file, add token, etc. 27 | cp tiny-matrix-bot.service /etc/systemd/system 28 | vim /etc/systemd/system/tiny-matrix-bot.service # adjust service to your setup 29 | systemctl enable tiny-matrix-bot 30 | systemctl start tiny-matrix-bot 31 | systemctl stop tiny-matrix-bot 32 | ``` 33 | 34 | ## Usage 35 | 36 | - intended audience/users: 37 | - small homeserver set up for a few friends 38 | - tinkerers who want to learn how a bot works 39 | - people who want to play around with Python code and Matrix 40 | - create a Matrix account for the bot, name it `bot` for example 41 | - configure the bot software 42 | - create the bot service and start the bot or the bot service 43 | - log in to the before created Matrix `bot` account e.g. via Riot web page 44 | - manually send invite from `bot` account to a friend (or to yourself) 45 | - once invite is accepted, reset the bot service (so that the new room will be added to bot service) 46 | - if you as admin already have a room with the bot, you can reset the bot by sending it `restart bot` as a message in your Matrix bot room 47 | - have the newly joined invitee send a `hello` command to the bot for a first test 48 | - do not encrypt any of the bot rooms, bot does not know how to handle encrypted rooms 49 | 50 | ## Debugging 51 | 52 | Run something similar to 53 | ``` 54 | systemctl stop tiny-matrix-bot # stop server in case it is running 55 | cd tiny-matrix-bot # go to your installation directory 56 | ./tiny-matrix-bot.py --debug # observe debug output 57 | ``` 58 | 59 | ## Bot as personal assistent: Example bot commands provided 60 | 61 | - help: to list available bot commands 62 | - ping: trivial example to have the bot respond 63 | - pong: like ping, but pong 64 | - hello: gives you a friendly compliment 65 | - motd: gives you the Linux Message Of The Day 66 | - ddg: search the web with DuckDuckGo search 67 | - web: surf the web, get a web page (JavaScript not supported) 68 | - tides: get today's low and high tides of your favorite beach 69 | - weather: get the weather forecast for your favorite city 70 | - rss: read RSS feeds 71 | - twitter: read latest user tweets from Twitter (does not always work as info is scraped from web, lately this web service seems to be down all the time) 72 | - tesla: chat with your Tesla car (dummy) 73 | - totp: get 2FA Two-factor-authentication TOTP PIN via bot message 74 | - hn: read Hacker News, fetches front page headlines from Hacker News 75 | - mn: read Messari News, fetches the latest news articles from Messari 76 | - date: gives date and time 77 | - btc: gives Bitcoin BTC price info 78 | - eth: gives Ethereum price info 79 | - s2f: print Bitcoin Stock-to-flow price info 80 | 81 | ## Bot as Admin tool: Additional bot commands provided to Matrix or system administrators 82 | 83 | With these commands a system administrator can maintain his Matrix installation and keep a watchful eye on his server all through the Matrix bot. Set the permissions accordingly in the config file to avoid unauthorized use of these bot commands! 84 | 85 | - disks: see how full your disks or mountpoints are 86 | - cputemp: monitor the CPU temperatures 87 | - restart: restart the bot itself, or Matrix services 88 | - check: check status, health status, updates, etc. of bot, Matrix and the operating system 89 | - update: update operating sytem 90 | - wake: wake up other PCs on the network via wake-on-LAN 91 | - firewall: list the firewall settings and configuration 92 | - date: gives date and time of server 93 | - platform: gives hardware and operating system platform information 94 | - ps: print current CPU, RAM and Disk utilization of server 95 | - top: gives 5 top CPU and RAM consuming processes 96 | - users: list users that are registered on homeserver 97 | - alert: shows if any CPU, RAM, or Disk thresholds have been exceeded (best to combine with a cron job, and have the cron job send the bot message to Matrix admin rooms) 98 | 99 | ## Other Features 100 | 101 | - bot can also be used as an CLI app to send messages to rooms where bot is a member 102 | - when sending messages, 3 message formats are supported: 103 | - text: by default 104 | - html: like using `/html ...` in a chat 105 | - code: for sending code snippets or script outputs, like `/html
 ... 
` 106 | - sample scripts are mostly in `bash` and some in `python3` 107 | - it can be used very easily for monitoring the system. An admin can set up a cron job that runs every 15 minutes, e.g. to check CPU temperature, or to check a log file for signs of an intrusion (e.g. SSH or Web Server log files). If anything abnormal is found by the cron job, the cron job fires off a bot message to the admin. 108 | 109 | ## Final Thoughts 110 | 111 | - Enjoy and have fun with it, it is cool, and easily extensible. Adjust it to your needs! 112 | - Pull Requests for bug fixes are welcome! If you want to make a Pull Requests for enhancements then you better make it on [matrix-eno-bot](https://github.com/8go/matrix-eno-bot). 113 | -------------------------------------------------------------------------------- /scripts/hello: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -n "$CONFIG" ]; then 4 | echo "^salut$|^ciao$|^hallo$|^hi$|^servus$|^hola$|^hello$|^hello .*$|^bonjour$|^bonne nuit$" 5 | exit 1 6 | fi 7 | 8 | echo "You're an awesome friend. 9 | You're a gift to those around you. 10 | You're a smart cookie. 11 | You are awesome! 12 | You have impeccable manners. 13 | I like your style. 14 | You have the best laugh. 15 | I appreciate you. 16 | You are the most perfect you there is. 17 | You are enough. 18 | You're strong. 19 | Your perspective is refreshing. 20 | I'm grateful to know you. 21 | You light up the room. 22 | You deserve a hug right now. 23 | You should be proud of yourself. 24 | You're more helpful than you realize. 25 | You have a great sense of humor. 26 | You've got an awesome sense of humor! 27 | You are really courageous. 28 | Your kindness is a balm to all who encounter it. 29 | You're all that and a super-size bag of chips. 30 | On a scale from 1 to 10, you're an 11. 31 | You are strong. 32 | You're even more beautiful on the inside than you are on the outside. 33 | You have the courage of your convictions. 34 | I'm inspired by you. 35 | You're like a ray of sunshine on a really dreary day. 36 | You are making a difference. 37 | Thank you for being there for me. 38 | You bring out the best in other people. 39 | Your ability to recall random factoids at just the right time is impressive. 40 | You're a great listener. 41 | How is it that you always look great, even in sweatpants? 42 | Everything would be better if more people were like you! 43 | I bet you sweat glitter. 44 | You were cool way before hipsters were cool. 45 | That color is perfect on you. 46 | Hanging out with you is always a blast. 47 | You always know -- and say -- exactly what I need to hear when I need to hear it. 48 | You help me feel more joy in life. 49 | You may dance like no one is watching, but everyone is watching because you are an amazing dancer! 50 | Being around you makes everything better! 51 | When you say, \"I meant to do that,\" I totally believe you. 52 | When you're not afraid to be yourself is when you are most incredible. 53 | Colors seem brighter when you're around. 54 | You're more fun than a ball pit filled with candy. (And seriously, what could be more fun than that?) 55 | That thing you don't like about yourself is what makes you so interesting. 56 | You're wonderful. 57 | You have cute elbows. For reals! 58 | Jokes are funnier when you tell them. 59 | You're better than a triple-scoop ice cream cone. With sprinkles. 60 | When I'm down you always say something encouraging to help me feel better. 61 | You are really kind to people around you. 62 | You're one of a kind! 63 | You help me be the best version of myself. 64 | If you were a box of crayons, you'd be the giant name-brand one with the built-in sharpener. 65 | You should be thanked more often. So thank you!! 66 | Our community is better because you're in it. 67 | Someone is getting through something hard right now because you've got their back. 68 | You have the best ideas. 69 | You always find something special in the most ordinary things. 70 | Everyone gets knocked down sometimes, but you always get back up and keep going. 71 | You're a candle in the darkness. 72 | You're a great example to others. 73 | Being around you is like being on a happy little vacation. 74 | You always know just what to say. 75 | You're always learning new things and trying to better yourself, which is awesome. 76 | If someone based an Internet meme on you, it would have impeccable grammar. 77 | You could survive a Zombie apocalypse. 78 | You're more fun than bubble wrap. 79 | When you make a mistake, you try to fix it. 80 | You're great at figuring stuff out. 81 | Your voice is magnificent. 82 | The people you love are lucky to have you in their lives. 83 | You're like a breath of fresh air. 84 | You make my insides jump around in the best way. 85 | You're so thoughtful. 86 | Your creative potential seems limitless. 87 | Your name suits you to a T. 88 | Your quirks are so you -- and I love that. 89 | When you say you will do something, I trust you. 90 | Somehow you make time stop and fly at the same time. 91 | When you make up your mind about something, nothing stands in your way. 92 | You seem to really know who you are. 93 | Any team would be lucky to have you on it. 94 | In high school I bet you were voted \"most likely to keep being awesome.\" 95 | I bet you do the crossword puzzle in ink. 96 | Babies and small animals probably love you. 97 | If you were a scented candle they'd call it Perfectly Imperfect (and it would smell like summer). 98 | There is ordinary, and then there's you. 99 | You are someone's reason to smile. 100 | You are even better than a unicorn, because you're real. 101 | How do you keep being so funny and making everyone laugh? 102 | You have a good head on your shoulders. 103 | Has anyone ever told you that you have great posture? 104 | The way you treasure your loved ones is incredible. 105 | You're really something special. 106 | Thank you for being you. 107 | You are a joy. 108 | You are a wonderful part of our family. 109 | You are excellent. 110 | You are so good at this. 111 | You are such a blessing to me. 112 | You are such a leader at school. 113 | You are worth so much to me. 114 | You brighten my life. 115 | You can do anything you put your mind to. 116 | You color my world. 117 | You do things with excellence. 118 | You encourage me. 119 | You have incredible insight. 120 | You have my heart. 121 | You impact me every day. 122 | You love me well. 123 | You love your friends well. 124 | You make a difference. 125 | You make gray skies disappear. 126 | You make me smile. 127 | You make memories sweeter. 128 | You make my days sweeter. 129 | You matter to me. 130 | You put others first. 131 | You rock. 132 | You set a great example. 133 | You shine every day. 134 | You’re a great chatter. I am a fan of yours. 135 | You’re a great leader. 136 | You’re a great bot user. 137 | You’re a team player. 138 | You’re amazing. 139 | You’re artistic. 140 | You’re athletic. 141 | You’re awesome. 142 | You’re beautiful. 143 | You’re compassionate. 144 | You’re creative. 145 | You’re delightful. 146 | You’re doing great things. 147 | You’re fantastic. 148 | You’re fun. 149 | You’re handsome. 150 | You’re helpful. 151 | You’re incredible. 152 | You’re inspiring. 153 | You’re kind. 154 | You’re marvelous. 155 | You’re nice to others. 156 | You’re one of a kind. 157 | You’re outstanding. 158 | You’re positive. 159 | You’re radiant. 160 | You’re smart. 161 | You’re so fun to play with. 162 | You’re so fun-loving. 163 | You’re so hopeful. 164 | You’re so refreshing. 165 | You’re so respectful. 166 | You’re so special. 167 | You’re so strong. 168 | You’re so trustworthy. 169 | You’re the best. 170 | You’re the light of my life. 171 | You’re thoughtful. 172 | You’re tremendous. 173 | You’re unbelievable. 174 | You’re unique. 175 | You have great dreams. 176 | You have great ideas. 177 | You make me so proud. 178 | You win me over every day. 179 | You’re intelligent. 180 | You’re interesting. 181 | You’re talented. 182 | I’m so glad you’re mine." | shuf -n1 183 | -------------------------------------------------------------------------------- /tiny-matrix-bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Don't change tabbing, spacing, or formating as file is automatically linted with autopep8 --aggressive 4 | # Ignore long lines 5 | # pylama:format=pep8:linters=pep8:ignore=E501 6 | 7 | import os 8 | import re 9 | import sys 10 | import logging 11 | import traceback 12 | import argparse 13 | import subprocess 14 | import configparser 15 | from time import sleep 16 | from matrix_client.client import MatrixClient 17 | 18 | 19 | class TinyMatrixtBot(): 20 | """This class implements a tiny Matrix bot. 21 | It also can be used to send messages from the CLI as proxy for the bot. 22 | """ 23 | 24 | def __init__(self, pargs): 25 | root_path = os.path.dirname(os.path.realpath(__file__)) 26 | self.config = configparser.ConfigParser() 27 | if "CONFIG" in os.environ: 28 | config_path = os.environ["CONFIG"] 29 | else: 30 | config_path = os.path.join(root_path, "tiny-matrix-bot.cfg") 31 | self.config.read(config_path) 32 | self.base_url = self.config.get("tiny-matrix-bot", "base_url") 33 | self.token = self.config.get("tiny-matrix-bot", "token") 34 | self.connect() 35 | logger.debug("arguments {}".format(pargs)) 36 | logger.debug("client rooms {}".format(self.client.rooms)) 37 | 38 | if pargs.room: 39 | if pargs.room not in self.client.rooms: 40 | logger.info( 41 | "Provided room argument is not in client rooms. Exiting ...") 42 | sys.exit(1) 43 | if pargs.message: 44 | text = pargs.message 45 | logger.debug("Provided message argument \"{}\".".format(text)) 46 | else: 47 | text = sys.stdin.read() # read message from stdin 48 | logger.debug("sending message to {}".format(pargs.room)) 49 | if pargs.code: 50 | logger.debug("sending message in format {}".format("code")) 51 | self.client.rooms[pargs.room].send_html( 52 | "
" + text + "
") 53 | elif pargs.html: 54 | logger.debug("sending message in format {}".format("html")) 55 | self.client.rooms[pargs.room].send_html(text) 56 | else: 57 | logger.debug("sending message in format {}".format("text")) 58 | self.client.rooms[pargs.room].send_text(text) 59 | logger.debug("message sent, now exiting") 60 | sys.exit(0) 61 | run_path = self.config.get( 62 | "tiny-matrix-bot", "run_path", 63 | fallback=os.path.join(root_path, "run")) 64 | os.chdir(run_path) 65 | scripts_path = self.config.get( 66 | "tiny-matrix-bot", "scripts_path", 67 | fallback=os.path.join(root_path, "scripts")) 68 | enabled_scripts = self.config.get( 69 | "tiny-matrix-bot", "enabled_scripts", fallback=None) 70 | self.scripts = self.load_scripts(scripts_path, enabled_scripts) 71 | self.inviter = self.config.get( 72 | "tiny-matrix-bot", "inviter", fallback=None) 73 | self.client.add_invite_listener(self.on_invite) 74 | self.client.add_leave_listener(self.on_leave) 75 | for room_id in self.client.rooms: 76 | self.join_room(room_id) 77 | self.client.start_listener_thread( 78 | exception_handler=lambda e: self.connect()) 79 | while True: 80 | sleep(0.5) 81 | 82 | def connect(self): 83 | try: 84 | # downgraded this from info to debug, because if this program is used by other 85 | # automated scripts for sending messages then this extra output is 86 | # undesirable 87 | logger.debug("connecting to {}".format(self.base_url)) 88 | self.client = MatrixClient(self.base_url, token=self.token) 89 | # same here, downgrade from info to debug, to avoid output for normal use 90 | # cases in other automated scripts 91 | logger.debug("connection established") 92 | except Exception: 93 | logger.warning( 94 | "connection to {} failed".format(self.base_url) + 95 | ", retrying in 5 seconds...") 96 | sleep(5) 97 | self.connect() 98 | 99 | def load_scripts(self, path, enabled): 100 | scripts = [] 101 | for script_name in os.listdir(path): 102 | script_path = os.path.join(path, script_name) 103 | if enabled: 104 | if script_name not in enabled: 105 | logger.debug( 106 | "script {} is not enabled".format(script_name)) 107 | continue 108 | if (not os.access(script_path, os.R_OK) or 109 | not os.access(script_path, os.X_OK)): 110 | logger.debug("script {} is not executable".format(script_name)) 111 | continue 112 | # the .copy() is extremely important, leaving it out is a major bug 113 | # as variables from the config file will then be constantly 114 | # overwritten! 115 | script_env = os.environ.copy() 116 | script_env["CONFIG"] = "1" 117 | logger.debug("script {} with script_env {}".format( 118 | script_name, script_env)) 119 | script_regex = subprocess.Popen( 120 | [script_path], 121 | env=script_env, 122 | stdout=subprocess.PIPE, 123 | universal_newlines=True 124 | ).communicate()[0].strip() 125 | if not script_regex: 126 | logger.debug("script {} has no regex".format(script_name)) 127 | continue 128 | del script_env["CONFIG"] 129 | if self.config.has_section(script_name): 130 | for key, value in self.config.items(script_name): 131 | script_env["__" + key] = value 132 | logger.debug( 133 | "add key-value pair key {} to script_env".format(key)) 134 | logger.debug( 135 | "add key-value pair value {} to script_env".format(value)) 136 | script = { 137 | "name": script_name, 138 | "path": script_path, 139 | "regex": script_regex, 140 | "env": script_env 141 | } 142 | scripts.append(script) 143 | logger.info("script {}".format(script["name"])) 144 | logger.debug("all scripts {}".format(scripts)) 145 | return scripts 146 | 147 | def on_invite(self, room_id, state): 148 | sender = "someone" 149 | for event in state["events"]: 150 | if event["type"] != "m.room.join_rules": 151 | continue 152 | sender = event["sender"] 153 | break 154 | logger.info("invited to {} by {}".format(room_id, sender)) 155 | if self.inviter: 156 | if not re.search(self.inviter, sender): 157 | logger.info( 158 | "{} is not inviter, ignoring invite" 159 | .format(sender)) 160 | return 161 | self.join_room(room_id) 162 | 163 | def join_room(self, room_id): 164 | logger.info("join {}".format(room_id)) 165 | room = self.client.join_room(room_id) 166 | room.add_listener(self.on_room_event) 167 | 168 | def on_leave(self, room_id, state): 169 | sender = "someone" 170 | for event in state["timeline"]["events"]: 171 | if not event["membership"]: 172 | continue 173 | sender = event["sender"] 174 | logger.info("kicked from {} by {}".format(room_id, sender)) 175 | 176 | def on_room_event(self, room, event): 177 | if event["sender"] == self.client.user_id: 178 | logger.debug( 179 | "event from sender (itself) {}".format(event["sender"])) 180 | return 181 | # ignore encrypted messages, but log them in debug mode 182 | if event["type"] == "m.room.encrypted": 183 | logger.debug( 184 | "event type (m.room.encrypted) {}".format(event["type"])) 185 | logger.debug("sender_key (m.content.sender_key) {}".format( 186 | event["content"]["sender_key"])) 187 | logger.debug("ciphertext (m.content.ciphertext) {}".format( 188 | event["content"]["ciphertext"])) 189 | return 190 | if event["type"] != "m.room.message": 191 | logger.debug( 192 | "event of type (!=room.message) {}".format(event["type"])) 193 | return 194 | # only plain text messages are processed, everything else is ignored 195 | if event["content"]["msgtype"] != "m.text": 196 | logger.debug("event of msgtype (!=m.text) {}".format( 197 | event["content"]["msgtype"])) 198 | return 199 | args = event["content"]["body"].strip() 200 | logger.debug("args {}".format(args)) 201 | for script in self.scripts: 202 | # multiple scripts can match regex, multiple scripts can be kicked 203 | # off 204 | if not re.search(script["regex"], args, re.IGNORECASE): 205 | continue 206 | self.run_script(room, event, script, args) 207 | 208 | def run_script(self, room, event, script, args): 209 | script["env"]["__room_id"] = event["room_id"] 210 | script["env"]["__sender"] = event["sender"] 211 | if "__whitelist" in script["env"]: 212 | if not re.search(script["env"]["__whitelist"], 213 | event["room_id"] + event["sender"]): 214 | logger.debug( 215 | "script {} not whitelisted".format(script["name"])) 216 | return 217 | if "__blacklist" in script["env"]: 218 | if re.search(script["env"]["__blacklist"], 219 | event["room_id"] + event["sender"]): 220 | logger.debug("script {} blacklisted".format(script["name"])) 221 | return 222 | logger.debug("script {} run with env {}".format( 223 | [script["name"], args], script["env"])) 224 | run = subprocess.Popen( 225 | [script["path"], args], 226 | env=script["env"], 227 | stdout=subprocess.PIPE, 228 | stderr=subprocess.PIPE, 229 | universal_newlines=True 230 | ) 231 | # output = run.communicate()[0].strip() 232 | output, std_err = run.communicate() 233 | output = output.strip() 234 | std_err = std_err.strip() 235 | if run.returncode != 0: 236 | logger.debug("script {} exited with return code {} and " + 237 | "stderr as \"{}\" and stdout as \"{}\"".format( 238 | script["name"], run.returncode, std_err, output)) 239 | output = "*** Error: script " + script["name"] + " returned error code " + str( 240 | run.returncode) + ". ***\n" + std_err + "\n" + output 241 | # return # don't return on error, also print any available output 242 | sleep(0.1) 243 | # higher up programs or scripts have two options: 244 | # Text with a single or a double linebreak (i.e. one empty line) stays together 245 | # in a single messages, allowing one to write longer messages and structure 246 | # them clearly with separating whitespace (an empty line). 247 | # When two empty lines are found, the text is split up in multiple messages. 248 | # That allows a single call to a script to generate multiple independent messages. 249 | # In short, everything with 1 or 2 linebreaks stays together, wherever there are 3 250 | # linebreaks the text is split into 2 or multiple messages. 251 | for p in output.split("\n\n\n"): 252 | for line in p.split("\n"): 253 | logger.debug( 254 | "script {} output {}".format( 255 | script["name"], line)) 256 | # strip again to get get rid of leading/trailing newlines and whitespaces 257 | # left over from previous split 258 | if p.strip() != "": 259 | if pargs.code: 260 | room.send_html("
" + p.strip() + "
") 261 | elif ("__format" in script["env"]) and (script["env"]["__format"] == "code"): 262 | room.send_html("
" + p.strip() + "
") 263 | elif pargs.html: 264 | room.send_html(p.strip()) 265 | elif ("__format" in script["env"]) and (script["env"]["__format"] == "html"): 266 | room.send_html(p.strip()) 267 | else: 268 | room.send_text(p.strip()) 269 | sleep(0.1) 270 | 271 | 272 | if __name__ == "__main__": 273 | logging.basicConfig() # initialize root logger, a must 274 | if "DEBUG" in os.environ: 275 | logging.getLogger().setLevel(logging.DEBUG) # set log level on root logger 276 | else: 277 | logging.getLogger().setLevel(logging.INFO) # set log level on root logger 278 | 279 | # Construct the argument parser 280 | ap = argparse.ArgumentParser( 281 | description="This program implements a simple Matrix bot.") 282 | # Add the arguments to the parser 283 | ap.add_argument("-d", "--debug", required=False, 284 | action="store_true", help="Print debug information") 285 | ap.add_argument("-r", "--room", required=False, 286 | help="Don't run bot. Just send a message to this bot-room. If --message is provided use that as message, if not provided read message from stdin.") 287 | ap.add_argument("-m", "--message", required=False, 288 | help="Don't run bot. Just send this message to the specified bot-room. If not specified, message will be read from stdin.") 289 | # -h already used for --help, -w for "web" 290 | ap.add_argument("-w", "--html", required=False, 291 | action="store_true", help="Send message(s) as format \"HTML\". If not specified, message will be sent as format \"TEXT\".") 292 | ap.add_argument("-c", "--code", required=False, 293 | action="store_true", help="Send message(s) as format \"CODE\". If not specified, message will be sent as format \"TEXT\". If both --html and --code are specified then --code takes priority.") 294 | pargs = ap.parse_args() 295 | if pargs.debug: 296 | logging.getLogger().setLevel(logging.DEBUG) # set log level on root logger 297 | logging.getLogger().info("Debug is turned on.") 298 | logger = logging.getLogger("tiny-matrix-bot") 299 | if pargs.message and (not pargs.room): 300 | logger.error( 301 | "If you provide a message you must also provide a room as destination for the message.") 302 | sys.exit(2) 303 | 304 | try: 305 | TinyMatrixtBot(pargs) 306 | except Exception: 307 | traceback.print_exc(file=sys.stdout) 308 | sys.exit(1) 309 | except KeyboardInterrupt: 310 | sys.exit(1) 311 | -------------------------------------------------------------------------------- /scripts/unused/solva: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | regex='^\!(solva|insult)\s*' 4 | 5 | if [ -n "$CONFIG" ] 6 | then 7 | echo "$regex" 8 | exit 0 9 | fi 10 | 11 | arg="$( echo "$@" | sed -r "s/$regex//I" )" 12 | 13 | # https://github.com/mth/hirc/blob/master/insult.txt 14 | 15 | echo "$arg: sa oled nuhtluseks maailmale loodud, et inimesed näeksid, kui madalale võib üks inimeseloom langeda. 16 | $arg: sa oled loll nagu lauajalg. 17 | Tead $arg, mine osta õige üks tükk seepi. 18 | Erikuradikinomees sa $arg oled, reede õhta maatriksis! 19 | $arg: sa oled üks plekist persega vedruvasikas. 20 | $arg: käi jala. 21 | $arg, sa vana pede, sinu kohta on artikkel: http://www.$arg.isgay.com/ 22 | $arg: kalla end piimaga üle ja pane traktori kõrval põlema. 23 | Oh püha perse kiriku laes, kuskohas küll $arg'suguseid produtseeritakse. 24 | $arg: sina mine perse ja jäägi sinna. 25 | $arg: vabanda, kui ma sind kuidagi solvasin. See juhtus täiesti tahtlikult. 26 | $arg: ma ei saa aru, kuidas päike küll sinu peale paistes oksendama ei hakka. 27 | $arg: tra küll, kui mina sinu moodi välja näeks, ei julgeks ma ilma maskita väljagi minna 28 | $arg: ma ei näe su silmis mõistusehelki. 29 | $arg: kes küll sinusugusele ajukääbikule kirjakunsti õpetas? 30 | $arg: sina, sitavikat, ime kella! 31 | $arg: kas see on su nina, või kasvatad endale kolmandat kätt? 32 | $arg: mina olen blond, aga mis sinu vabandus on? 33 | $arg: kuidas Sulle kõrvaltvaatajana inimsugu tundub? 34 | $arg: sina ja inetu? Sa ei ole inetu, sa oled lihtsalt ... äh kuradile, Sa oled inetu. Sitaks inetu. Ja paks ka. Ja kiilakas. 35 | $arg: mitu korda ma pean vett tõmbama, et sa ära kaoksid? 36 | $arg: oled sa alati nii loll või on sul lihtsalt blond hetk?? 37 | K: Mida ütles jumal, kui ta $arg' tegi? V: Oh shit! 38 | K: Kui Empire State Building'u katuselt kukuvad alla paks neeger ja $arg, siis kumb jõuab alla esimesena? V: Pole valge mehe asi. 39 | K: Mis on $arg' jaoks pikk ja raske? V: Algkool 40 | $arg pole just karbi kõige kirkam kriit 41 | $arg: sa oled erakordselt sita väljanägemisega. On see mingi uus trend? 42 | $arg: kumb meist nüüd mürki peaks võtma? 43 | $arg: mõni küla on sinu pärast praegu ilma lollita. 44 | $arg: on see kitsehabe või on tuvid su lõua täis sittunud? 45 | $arg: palun seisa allatuult. 46 | $arg: sae pekki. 47 | $arg: Ah keri pekki 48 | Kuule $arg, sina kõdunenud kammeljas, sina mädanenud mudakukk, sina solgitud särg, mine osta omale õng. 49 | $arg: näri muru! 50 | $arg: kes sinusugusele kulendile suu andis? 51 | $arg: tead mis, PANE ENNAST PÕLEMA! 52 | $arg: söö sitta! (miljardid kärbsed ei saa ju ometi valel teel olla) 53 | $arg: sa näed välja nagu keedetud kaheksajalg 54 | $arg: sa oled meditsiiniline ime 55 | $arg: sa näed ikka vahva välja! See kleit su seljas on pilapoest, eks? 56 | $arg: kao eemale! Sa seisad mu aura peal! 57 | $arg on mees, kes ei tee palju sõnu. Aga möliseb ikkagi rohkem kui vaja. 58 | . o O ( Kus on geenipolitsei? Siin on mingi jälk $arg ) O o . 59 | . o O ( Millise kivi alt küll sellised lontrused nagu $arg välja ronivad.. ) O o . 60 | $arg: kes ma Sinu arust olen? Kärbsepaber idiootidele? 61 | $arg: on Sul minut aega? Räägi mulle ära kõik, mida Sa üldse tead. 62 | $arg on nii loll, et sobiks ideaalselt Võrno saatesse 63 | $arg: Su jutt kõlab nagu eesti keel, aga ma ei saa mitte halligi aru. 64 | $arg: kõik mu eelarvamused Sinu suhtes on ajapikku tõeks osutunud. 65 | $arg: ilmselgelt on ainuke lahendus sinu probleemile suitsiid. 66 | $arg: see et keegi sind ei mõista, ei tähenda veel et oled kunstnik. 67 | $arg varub ilmselt alati spetsiaalselt aega, et end avalikus kohas lolliks teha. 68 | $arg: Kuuldavasti oli sul kunagi yks mõte, aga see suri yksinduse kätte ära. 69 | $arg: Ma vihkan kõiki. Sina oled järgmine. 70 | $arg: Ja sinu täiesti mõttetu arvamus on...? 71 | $arg: Pista pea perse ja tee porgandi häält. 72 | $arg: Kas sa nüüd taipad, mis juhtub kui sugulased omavahel abielluvad? 73 | $arg: Maakeral ei ole enam ruumi. Mine koju. 74 | $arg: Mine hoia oma pead vee all. 75 | Isegi lollide maailmameistrivõistlustel saaks $arg teise koha, kuna ta on lihtsalt niivõrd loll.... 76 | $arg: mine ära enne kui ma sind ümber lükkan. 77 | Näe, tõmbasin küll vett, aga $arg ikka alla ei läinud. 78 | Miskit rõvedat pininat tuleb kusagilt. Aaa, see oled sina, $arg! 79 | Tere $arg! Kuidas viinaravi edeneb? 80 | Vaene $arg, kas sa jäid rongi alla või oledki sellisena sündinud? 81 | $arg: Piiblis on kirjas: \"Juudas eemaldus ja läks ja poos end üles.\" Ja veel: \"Mine tee sina samuti\" 82 | $arg, miks sa ei lase oma mõistust teritada? 83 | $arg, tee mulle üks teene - ära unusta koduteel vales kohas tänavat ületada. 84 | $arg, mängime kodu, Sina oled uks ja mina löön su kinni. 85 | $arg, lähme kusagile, kus me saaksime teineteisest lahus olla. 86 | Ma ei unusta kunagi ühtegi nägu, aga $arg puhul olen ma valmis erandi tegema. 87 | $arg, vaata, rong läheneb! Roni rööbastele! 88 | $arg, Sul on väga huvitav nägu, mitu korda Sind sinna löödud on? 89 | $arg, mängime hobust. Mina olen esimene ots ja sina võid lihtsalt iseennast mängida. 90 | $arg nalju tervitab alati suur vaikusepahvak. 91 | Ahv heitis $arg'le ühe pilgu ning karjus: \"Persse see Darwini teooria - mina endast inimest teha ei lase!\" 92 | Peab tunnistama, et $arg'i sugused mehed ei kasva puu otsas - nad ripuvad okste küljes. 93 | Kas tõesti on sõnade helge pea ja $arg vahel nii suur erinevus? 94 | $arg on nagu lauaga löödud. Ja mitte ainult vastu rindu 95 | Vaata $arg't. Ilmne tõestus, et hullari aed on liiga madal. 96 | Mõistuse pooles on $arg'le kõige lähemal reha ... või äärmisel juhul labidas 97 | $arg, kas sa nüüd taipad, mis juhtub, kui sugulased omavahel abielluvad? 98 | $arg, ma suudan vaevu oma ükskõiksust vaos hoida 99 | $arg, sa tuled tuttav ette. Lahkasin sind vist zooloogiatunnis? 100 | Kui mind huvitaks su arvamus, $arg, siis ütleksin, milline see on. 101 | Sinuga dringile, $arg? Pigem teen endale ise tuimestuseta pimesooleoperatsiooni. 102 | $arg, kas sulle tundub, et ma vajan seltskonda? 103 | Hei, sina, $arg! Kao mu planeedilt minema! 104 | $arg, ja sinu tattnina-arvamus on...? 105 | $arg, ma ei ole tige. Olen lihtsalt juba 10 aastat väga halvas tujus. 106 | $arg, mis stiilis sa ka riietuda ei üritanud, välja see sul igastahes ei tulnud. 107 | $arg, kas su koduplaneedil keegi kunagi vait ka on? 108 | Ma ei ole sinu tüüp, $arg. Ma pole täispuhutav. 109 | $arg, kao eemale! Sa seisad mu aura peal. 110 | $arg: Ära muretse. Ma ei mäleta sinu nime ka. 111 | $arg, ma tahan lihtsalt kätte maksta. Mis selles halba on? 112 | $arg, kummarda ja ütle: \"Jah, mu käskija.\" 113 | $arg, kas ma mainisin, et kui sa minuga räägid, saad kohe jalaga munadesse? 114 | $arg, sa näed erakordselt sitt välja. On see mingi uus trend? 115 | $arg, kumb meist nüüd rohtu peaks võtma? 116 | $arg: Kuidas seda laserkaardikeppi taparežiimile lülitatakse? 117 | Ja milline seitsmest pöialpoisist sina, $arg, oled? 118 | $arg: Ma sorisin küll kaltsupoes, aga seda hilpu ma seal küll ei näinud 119 | Kus on geenipolitsei? Siin on mingi mutant, kes kasutab nime $arg. 120 | $arg, küll sa näed ikka vahva välja. See kleit on sul pilapoest, eks? 121 | $arg, muidugi on ka meestel tunded. Aga keda see kotib? 122 | Ilus kleit, $arg. Loodad alla võtta, et sellesse ära mahtuda? 123 | Parem ära mind vihasta $arg. Mul hakkavad kirstud otsa saama 124 | Oi, kui kena raseda kleit $arg. Sa polegi? Nojah ... 125 | Ma ei usu imesid, $arg. Ma arvestan nendega 126 | $arg, räägi siis ometi! Sul on õigus oma lollile arvamusele. 127 | Ma vihkan kõiki. Sina, $arg, oled järgmine. 128 | $arg, Ja sinu täiesti mõttetu arvamus on...? 129 | $arg: Vaata ette - mul on oma arvamus ja ma tean, kuidas seda kasutada. 130 | $arg: Miks kipuvad kinniste peadega inimesed alati suu lahti tegema? 131 | Ma olen andekas mitmel alal, $arg. Suudan ühteaegu rääkida ja sinu peale laias kaarest kusta. 132 | Ära hakka minuga plõksima, $arg. Nagunii sa jagu ei saa. 133 | Kuidas ma saangi sinust puudust tunda $arg, kui sa kuidagi ära ei lähe? 134 | $arg: Stress kasvab üle pea, aga kägistada pole kedagi. 135 | $arg, sina oled üks hirmus õnnetus, mis headele inimestele kaela kukub. 136 | $arg, Sul on õigus vaikida. Kasuta seda ometi! 137 | Kui inimest toiduga võrrelda, siis sina, $arg, oled odav, maitsetu ja saad kiiresti valmis. 138 | $arg, kuuldavasti oli sul kunagi üks mõte, aga see suri üksinduse kätte ära. 139 | $arg, inetusvõistlusel oleks sulle vääriliseks vastaseks ainlt üleeilne okseloik. 140 | $arg: Ma olen nii õnnelik, et võiksin tappa. 141 | $arg, vabanda, kui tundus, et huvitad mind. Ei huvita. 142 | $arg, su tänane meik on küll puhas raiskamine. 143 | $arg, ma pole sinu tüüp. Mul on pulss. 144 | $arg, ma ei tea, mis viga sul küljes on, aga kindlasti on see raskesti hääldatava diagnoosiga. 145 | $arg, mida ma küll sinuta pihta hakkaksin? Peale selle, et oleksin õnnelik. 146 | Palun räägi edasi, $arg. Ma tahan magada. 147 | $arg, jah, see on noku moodi küll, aga palju väiksem. 148 | Sina, $arg, oled vist palju Bushi kõnesid kuulanud? 149 | $arg: Mulle meeldib su lähenemine. Nüüd näita, kuidas sa kaugened. 150 | Sul, $arg, käis üks mõte peast läbi? See pidi vast pikk ja üksildane teekond olema. 151 | Kuule, $arg, mine õige Ameerika asepresidendiga pardijahile. 152 | kas su vanemad tõesti vihkasid sind niipalju et $arg sulle nimeks panid või astusid enesevihkajate klubisse ja võtsid omale sellise nime ?:) 153 | nimesid nimetamata aga $arg on ikka paras ajukääbik küll 154 | Sa meeldid mulle $arg. Inimesed küll ütlevad, et mul ei ole maitset, aga sa meeldid mulle. 155 | $arg: Ära hakka minuga plõksima. Nagunii sa jagu ei saa. 156 | $arg: ära täna mind su solvamise eest. Seda oli nauding teha. 157 | $arg: ära tunne ennast halvasti. Paljudel inimeste ei ole talenti. 158 | $arg: ehk oled kunagi iluoperatsioonile mõelnud ? 159 | $arg: Hei, sina! Kao mu planeedilt minema! 160 | $arg: Hoiatus: mul on oma arvamus ja ma tean, kuidas seda kasutada. 161 | $arg: Huvitav, miks tulnukad sulle pärakusse sondi jätsid? 162 | $arg: Ideaalne aeg hakata kadunud inimeseks. 163 | $arg: Ilus kleit. Loodad alla võtta, et sellesse ära mahtuda? 164 | $arg: Ilus raseda kleit, sünnitad sa varsti? 165 | $arg: ime kanni! 166 | $arg: Inetusvõistlusel oleks sulle vääriliseks vastaseks ainlt üleeilne okseloik. 167 | $arg: Jah, see on noku moodi küll, aga palju väiksem. 168 | $arg: Ja milline seitsmest pöialpoisist sina oled? 169 | $arg: ja mina mõtlesin maailma koledaim inimene küll siia ei juhtu... 170 | $arg: käi jala. 171 | $arg: kaos, paanika, korralagedus - sinu töö on siin edukalt tehtud. 172 | $arg: kas ma mainisin, et kui sa mind puudutad, saad otsekohe jalaga munadesse? 173 | $arg: kas sa käid ilusalongis tagavaraväljapääsu kaudu? 174 | $arg: Kas su koduplaneedil keegi kunagi vait ka on? 175 | $arg: Kas sulle tundub, et ma vajan seltskonda? 176 | $arg: kui aju oleks vihm, siis sina oleks kõrb. 177 | $arg: Kuidas ma saangi sinust puudust tunda, kui sa kunagi ära ei lähe? 178 | $arg: Kuidas seda laserkaardikeppi taparežiimile lülitatakse 179 | $arg: Kui inimest toiduga võrrelda, siis sina oled odav, maitsetu ja saad kiiresti valmis. 180 | $arg: kui ma luban, et igatsen su järele, kas sa siis läheksid ära? 181 | $arg: kui ma peaks tapma kõik kes sind vihkavad, siis see ei oleks mõrv... ...see oleks genotsiid. 182 | $arg: kui ma vajaks aju, siis ma võtaks sinu oma, sest seda ei ole kunagi kasutatud. 183 | $arg: kui mu koeral oleks selline nägu nagu sul, siis ma raseeriks ta tagumiku ja õpetaks ta tagurpidi käima. 184 | $arg: kui mul oleks vaja lonti saada, mõtleksin ma sinu peale 185 | $arg: Küll sa näed ikka vahva välja. See kleit on sul pilapoest, eks? 186 | $arg: kumb meist nüüd rohtu peaks võtma? 187 | $arg: Kus on geenipolitsei? Siin on mingi mutant. 188 | $arg: Kuuldavasti oli sul kunagi üks mõte, aga see suri üksinduse kätte ära. 189 | $arg: ma annaks sulle ühe mõtte, aga ma ei ole kindel, kas sul on panna seda kuskile. 190 | $arg: ma austan mulda, mis sind ootab. 191 | $arg: Ma ei ole sinu tüüp. Ma pole täispuhutav. 192 | $arg: ma ei tea mis sind nii lolliks teeb, aga see tõesti töötab. 193 | $arg: Ma ei tea, mis viga sul küljes on, aga kindlasti on see raskesti hääldatava diagnoosiga. 194 | $arg: ma ei unusta ühtegi nägu, aga sinu puhul tahaks küll erandi teha 195 | $arg: Ma ei usu imesid. Ma arvestan nendega 196 | $arg: ma küsiks kui vana sa oled, aga ma tean, et sa ei tunne nii suuri numbreid. 197 | $arg: Ma kuulsin, et läksid ajuuuringutele, aga arstid ei leidnud sealt midagi. 198 | $arg: mängime hobust. Mina olen esimene pool ja sina oled sina ise. 199 | $arg: ma tõesti ei arva, et sa oled loll, aga mis minu arvamus loeb tuhandete teiste vastu. 200 | $arg: ma tuleks meelsasti sinuga kohtama, aga mu lemmik reklaam on praegu telekas. 201 | $arg: milline darwini auhind sulle kuulus ? 202 | $arg, muidugi on ka sinul tunded. Aga keda see kotib? 203 | $arg: mul on kiire praegu, võin ma sind mõni teine kord ignoreerida? 204 | $arg: Naerata ja ütle: \"Jah, mu käskija.\" 205 | $arg: Näri leiba! 206 | $arg: nii-nii. Jälle on tsirkusest paar klouni putku pannud. 207 | $arg: oled sa alati nii loll või pingutad täna eriti selle nimel? 208 | $arg: oled sa TONT või Inimene ? 209 | $arg: on need sinu silmamunad, mis ma oma dekolteest leidsin? 210 | $arg: on see su nina või sööd sa banaani? 211 | $arg: Parem ära mind vihasta. Mul hakkavad kirstud otsa saama 212 | $arg: sa ei ole paranoik. Kõik vihkavad sind tõesti. 213 | $arg: sa ei saa iialgi nii vanaks kui välja näed. 214 | $arg: sa ei tea sõna \"hirm\" tähendust. Aga kui järele mõelda, siis sa ei tea enamuse sõnade tähendust. 215 | $arg: sa oled loll kui leivaauto. 216 | $arg: sa oled nii kole, et kui ma su loomaaeda viisin, siis talitaja ütles: \"Tänan, et ta tagasi tõite.\" 217 | $arg, sul on nii inetu nägu, et see trükiti Ryanair oksekottidele. 218 | $arg: sa oled nii kole, et su pilt trükiti Ryanair oksekottidele. 219 | $arg: sa oled täpselt nagu Action Man: Kandiline soeng, armiline nägu ja püksis mitte midagi. 220 | $arg: sa tõendad seda, et isegi jumal eksib vahest. 221 | $arg: see, kui keegi sind ei mõista, ei tähenda veel, et sa oled kunstnik, 222 | $arg: sind tehes läks Loojal vist küll vorm katki. Ja mõned nurgad jäid ilmselt maha kraapimata. 223 | $arg: Sinuga dringile? Pigem teen endale ise tuimestuseta pimesooleoperatsiooni. 224 | $arg: sinu lolliks nimetamine on solvang kõigile teistele lollidele. 225 | $arg: sinu nõuannet ma küll ei vaja. Sa ei oska ju kahekümne ühenigi lugeda, kui sa alasti pole. 226 | $arg, Sul on nii ilusad kõverad jalad 227 | $arg: tavaliselt inimesed elavad ja õpivad. Sina ainult elad. 228 | $arg: tunne end nagu kodus. Korista mu köök ja WC ära. 229 | $arg: üldiselt ma ei taha küll kellegi kohta sitasti öelda aga sina oled ikka tõsiselt räige 230 | $arg: võin ma sinult su nägu laenata, mu tagumik on puhkusel. 231 | $arg: pane müts pähe.. rähn lendab 232 | Kuule $arg, oled sa mingi Transport Object Assembler? 233 | Võiks arvata, et $arg on mingi Konfiguratsioon. 234 | $arg on topis nagu mingi java. 235 | $arg: sinuga läheks luurele küll, aga tagasi tuleksin üksi 236 | Ettevaatust: $arg võib pikaajalisel tarvitamisel pöördumatult kahjustada teie tervist 237 | Mis on selle vaimuhaiguse nimi, mille põdeja tõi $arg ilmale? 238 | Põrgusse see $arg, pigem närin endal pea otsast 239 | $arg puhul on igasuguste teotuste väljamõtlemine mõttetu 240 | $arg, häda on tulnud maale koos sinuga! 241 | $arg: Kas sulle tundub, et ma vajan seltskonda? 242 | Võrreldes $arg õudusega on Cthulhu nagu pehme kiisupoeg 243 | Mis kuradi käkk see $arg sihuke on? 244 | $arg meeldib mulle. Inimesed ütlevad, et mul puudub igasugune maitse, aga mulle ta meeldib. 245 | rattaletõmbamise võiks asendada $arg kasutamisega 246 | mullast on $arg tulnud ja mullaks peab ta ka saama 247 | $arg: tahaks sulle vastu hambaid anda aga miks peaksin ma su välimust parandama? 248 | $arg peal lasub vaaraode needus 249 | peaga vastu seina peksmine on meeldivam kui $arg 250 | $arg kui ohtlik psühholoogiline relv tuleks Genfi konventsiooniga keelustada 251 | $arg: oled sa alati nii loll või on sul lihtsalt blond hetk? 252 | $arg on nagu heroiin: korra proovid, igaveseks jama kaelas 253 | $arg, siin on sulle Statoili kinkepakk, tarvita julgelt 254 | $arg: kas sa oled alati nii loll või on täna mingi eriolukord? 255 | ma ei tea, mis $arg nii lolliks teeb, aga igatahes see mõjub 256 | $arg: mitu korda ma pean vett tõmbama, et sa ära kaoksid? 257 | $arg, ükskord viid sa mu hauda! 258 | $arg: ja mis on sinu olemasolu õigustus? 259 | $arg on vajalik nagu ürask männile 260 | $arg: sinu pilt on preservatiivipakkidel hoiatava näitena 261 | $arg vanematest oli väga vastutustundetu keppida 262 | $arg näeb pimedas palju parem välja 263 | $arg: sina pede mine tagasi munni imema 264 | $arg võiks oma vinnid ära pigistada enne mölisemist 265 | $arg, kas sul tuld on? Siis pane end põlema. 266 | isegi $arg psühhiaater keeldub teda kuulamast 267 | $arg: ma ei mäleta su nime, luba ma kutsun sind perseussiks? 268 | miks $arg mütsi perse peal kannab? 269 | $arg on nii kole, et isegi kärbestel läheb süda pahaks 270 | $arg on jälle eksinud nagu sõrm seedekulglasse 271 | $arg ei saa kunagi nii kõvaks meheks kui ta ema oli 272 | ma ei ole küll proktoloog, aga $arg ajud on pärasoolega vahetusse läinud 273 | $arg: kondoom peas on tõepoolest sulle sobiv riietus! 274 | $arg on vormis - ümmargune on ka vorm. 275 | $arg: ema ütles sulle, et oled eriline, aga tegelikult oled sa lihtsalt loll 276 | $arg on universumi loomulik hälve 277 | $arg püstitas negatiivse IQ maailmarekordi 278 | $arg on värske nagu munn saunas 279 | $arg ei ole mitte homo vaid harilik pede 280 | kui mul oleks Tourette sündroom, siis $arg põhjustaks hoogusid 281 | $arg: näed seda kasti? Värsti näed ainult natuke vasaku silmaga seda. Seestpoolt. 282 | $arg on nagu emo, kes on zileti kaotanud 283 | $arg aju on evolutsiooni jäänuk 284 | $arg: mine kümme meetrit eemale, sa solgid mu aura ära. 285 | paistab, et $arg vanemad ei osanud lapsi teha 286 | K: Mis on vahet $arg'l ja ämbritäiel sital? V: Ämber. 287 | $arg: õpi oma vanemate vigadest - kasuta kondoomi. 288 | ma oleks $arg isa, kui sada krooni poleks liiga palju olnud ta ema eest 289 | $arg: mine varju - prügiauto tuleb 290 | loodus oli $arg suhtes helde ainult 21. kromosoomi andes 291 | $arg: ütle oma boyfriendile, et ta sulle rohkem suhu ei situks 292 | kas kevad on juba, et $arg on lume alt välja sulanud? 293 | kas keegi peeretas või ütles $arg midagi? 294 | enamus inimesi moodustab sõnadest lauseid - kuid $arg on eriline 295 | $arg: Sa käia oskad? Siis käi perse! 296 | $arg vanemad kohtusid esimest korda suguvõsa kokkutulekul 297 | see, et $arg jalge vahel midagi ripub ei tee temast veel meest 298 | $arg: Kas sa põgenesid geneetikalaborist eile? 299 | $arg: Sul on jälle päevad? 300 | $arg: Palun mine katseklaasi tagasi! 301 | see, et $arg ahvi moodi haiseb, ei tähenda veel, et ta oleks Tarzan 302 | Vau! See pidi küll pirakas teerull olema, mis $arg näost üle sõitis. 303 | $arg: säästa oma kopsumahtu tüdruku täis puhumiseks 304 | ma ei suuda nii palju juua, et $arg inimest meenutama hakkaks 305 | $arg on elav tõestus, et inimene saab elada ilma ajudeta. 306 | ajud pole veel kõik - $arg korral pole nad mitte midagi 307 | igasugune sarnasus $arg ja inimese vahel on täielik kokkusattumus 308 | kui Frankenstein tahaks idiooti kokku panna, siis vajaks ta $arg tükke 309 | kes jättis $arg puuri lahti? 310 | $arg: ära tunne end halvasti - paljud inimesed on andetud 311 | $arg: ära mõtle, sa võid oma ajud ära nikastada 312 | $arg: palun räägi edasi, ehk ühel päeval ütled sa ka midagi tarka 313 | Kui ma sööksin sada kilo nisukliisid, siis mu sitt oleks parem inimene kui $arg 314 | $arg on kahjuks langenud anentsefaalia ohvriks 315 | $arg: Su ema kepib telliste eest, et su õele litsimaja ehitada... 316 | $arg on kole nagu hommikune Halonen 317 | $arg: sul pole midagi sellist viga, mida reinkarnatsioon ei parandaks 318 | $arg on tõestus, et jumalal on huumorimeel 319 | $arg aju on samahästi kui uus, kuna seda pole kunagi kasutatud 320 | tänu $arg jutu lugemisele on nüüd kõik siin kanalil lollimad... 321 | Ma just kuulsin, et $arg on haige. Loodetavasti pole see midagi kerget. 322 | $arg on tagasihoidlik inimene. Tal on põhjust selleks... 323 | $arg: mulle tundub, et parim osa sinust jooksis mööda su ema persepragu alla ja lõppes pruuni plekina madratsil 324 | Mõned toovad rõõmu igale poole, kus nad on. Ka $arg - lahkudes. 325 | kui $arg auto alla jääb, siis ei ole see õnnetus. 326 | Mind ei sega, et $arg räägib. Vähemalt niikaua kuni ma seda kuulama ei pea. 327 | $arg tõestab, et ligi paari meetrine sitahunnik võib püsti püsida. 328 | $arg: Sul on nägu mida ainult ema võiks armastada. Kuid ta vihkab sind... 329 | $arg, külast just helistati. Nad tahavad oma lolli tagasi. 330 | $arg: Ma ei elaks sinuga koos, isegi kui maailm oleks kusega üle ujutatud ja sa oleksid ainsa puu otsas. 331 | $arg on alaväärsuskompleksiga - ja täiesti põhjendatult 332 | $arg: Kas sa sündisid paksu limase sitajunnina, või pidid selleks saamiseks vaeva nägema? 333 | $arg: Kas su vanematel on ka mõni elus laps? 334 | $arg: Vastandid pidavat tõmbuma. Loodetavasti kohtud kellegi ilusa, targa ja kultuursega. 335 | $arg: Sul on sitt arvamus inimestest kui arvad, et nad on sinuga võrdsed. 336 | $arg on tugev nagu härg ja peaaegu sama intelligentne 337 | $arg: Mul on hea meel, kui ütlesin sulle midagi mille pärast vabandama peaks :) 338 | Taburet oleks $arg jaoks võrdväärne vestluspartner. 339 | Ma ei tea mitu jalga on $arg-l, kuid taburetil on neid umbes samapalju. 340 | Kui $arg kenam välja näeks, võiks ta töötada IT alal. 341 | $arg: Tead, ma valan su munadeni betooni ja jätan suruõhuvasara kahe meetri kaugusele. 342 | $arg, sina sinirohekollane tipitäpiline puust peaga ja plekist kõrvadega villastes sokkides lollaka naeratusega pilusilmne poolearuline ärakaranud vangi sarnane lampjalgne lasteaia lollpea, kas sa ei mäleta oma kohta? 343 | $arg, tead sina, mine õige kasvata omale uus aju 344 | $arg, palun loobu sellest liiva täis põlvikust, mida sa püksis kannad. 345 | $arg: MIS SUL VIGA ON? 346 | $arg: keri kolmikhüppega perse ja tõmba luuk ka tagant kinni 347 | Kui taburet tagurpidi panna, siis saab $arg koos oma pedesõbraga istuda. 348 | $arg kõlbab ainult litsimajja linu pesema 349 | $arg: ebakõla sinu ja looduse vahel on sulle näkku kirjutatud 350 | $arg: sina sitaviiul jää vait 351 | $arg kuskil munni ei peaks imema? 352 | $arg on nagu kaamel - küür seljas ja ila voolab 353 | $arg: Miks sa minuga räägid? Ma pole puuetega laste hooldaja. 354 | $arg: mängi endaga kusagil mujal. 355 | $arg: tead, kui ma oleks sinu näoga, jookseks ma naerdes ketassae otsa 356 | $arg: mine ära ja võta oma pokemon kaasa! 357 | $arg: millal sa viimati ilma peeglit kasutamata oma munni nägid? 358 | $arg: mängisid pipimängu jälle? 359 | $arg: kaotasid küpsisemängus jälle? 360 | $arg: miks sul häbe näos on? 361 | $arg pärast ongi piimapakkidel kiri \"Ava siit\" 362 | $arg on hea näide sellest, mis juhtub, kui õigel ajal aborti ei tehta 363 | $arg on nii loll, et ei läbi isegi Turingi testi 364 | $arg pea püsib ikka püsti - sooja õhku täis skalp ei kaalu ju palju ;)" | shuf -n1 365 | --------------------------------------------------------------------------------