├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── bashbot.sh ├── commands.json ├── commands ├── info.sh └── ping.sh ├── index.js ├── package-lock.json ├── package.json └── timers.sh /.env.example: -------------------------------------------------------------------------------- 1 | token="YOUR_BOT_TOKEN" 2 | client_id="YOUR_APPLICATION_ID" 3 | owner_id="YOUR_DISCORD_ID" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | 4 | 5 | .env 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shade 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord Bash Bot For The [Discord Linux](https://discord.gg/discord-linux) Server 2 | 3 | ## About Bash Bot 4 | 5 | This bot is very much a work in progress. The core and few available commands are working, but may be changed to accommodate future needs. 6 | 7 | This repository contains the source code for `@bot.sh` for the [Discord Linux](https://discord.gg/discord-linux) server. This bot is not intended for use elsewhere as is. If you would like to use this bot, it will require a bit of modification such as changing/removing the existing commands and setting up a realtime database on [Google Firebase](https://firebase.google.com/). 8 | 9 | The backend for bash bot runs on nodejs using [discord.js](https://discord.js.org) and [discord-slash-commands](https://github.com/shadeoxide/discord-slash-commands). 10 | 11 | On startup, bash bot creates a named pipe at `/tmp/.bashbot` to listen for output, and then the nodejs backend is started with its `stdout` redirected to the named pipe at `/tmp/.bashbot`. The output from the nodejs backend uses this format: 12 | 13 | ``` 14 | { 15 | "name": "ping", 16 | "id": "851338272415416320", 17 | "token": "aW50ZXJhY3Rpb246ODUxMzM4MjcyNDE1NDE2MzIwOmZJYzVwdG42cHlHZHl1SnRkS0VWNzVrWlQ1Slp0dGVUUUpJMHN6bkRHOUN6R01ZZGp6aUl6YzFaNWxza1J1ek9rclFsYXJlUjdiVjYwNllUbVoxbXd6dFlBU2RMT1pic3liYUxhaEE4cU51aDFRd0FiMDlyMXdLdEs4UFhpaWM4", 18 | "type": 2, 19 | "member": { 20 | "user": { 21 | "username": "Syretia", 22 | "public_flags": 640, 23 | "id": "86201442112671744", 24 | "discriminator": "4268", 25 | "avatar": "fb76f500b4d6b0f05ae1bb470d511a83" 26 | }, 27 | "roles": [ 28 | "204077487657975808", 29 | "437040802393489408", 30 | "459245940876771328", 31 | "501257816015634452" 32 | ], 33 | "premium_since": null, 34 | "permissions": "137438953471", 35 | "pending": false, 36 | "nick": null, 37 | "mute": false, 38 | "joined_at": "2016-07-17T02:27:21.613000+00:00", 39 | "is_pending": false, 40 | "deaf": false, 41 | "avatar": null 42 | }, 43 | "guildId": "204061452707954688" 44 | } 45 | ``` 46 | 47 | If the `.name` from the slash command used matches a script found in the `commands` directory, the script will be sourced by the main script with the output from the nodejs backend passed to it as an argument. 48 | 49 | ## Installation 50 | 51 | To use the core of the bot, you will need `jq`, `npm`, `node` (only tested with version 14.17.0), and, of course, `bash`. The commands all require at least `curl` in order to use Discord's API and may also have additional dependencies. 52 | 53 | To install bash bot, run the following commands in a terminal: 54 | 55 | ``` 56 | git clone https://github.com/discordlinux/bot 57 | cd ./bot 58 | npm install 59 | cp ./.env.example ./.env 60 | ``` 61 | 62 | After running the above commands, open the `.env` file you just copied in the editor of your choice and fill out the `token`, `client_id`, and `owner_id` variables. 63 | 64 | ## Running Bash Bot 65 | 66 | After installing bash bot by following the instructions above, simply run the `bashbot.sh` script in a terminal. 67 | -------------------------------------------------------------------------------- /bashbot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Author: Syretia 3 | # License: MIT 4 | # script to create fifo pipe, run while loop to monitor it, and start node bot process 5 | 6 | # set botdir variable 7 | export botdir="$(dirname "$(readlink -f "$0")")" 8 | # get variables from .env file 9 | source "$botdir"/.env 10 | 11 | # function to create fifo pipe and run while loop to monitor it 12 | pipestart() { 13 | # remove pipe on exit 14 | trap "rm -f /tmp/.botpipe" EXIT 15 | # create pipe if it doesn't exist 16 | if [[ ! -p "/tmp/.botpipe" ]]; then 17 | mkfifo /tmp/.botpipe 18 | fi 19 | # while loop to monitor pipe 20 | while true; do 21 | # read line from fifo pipe 22 | if IFS= read -r line /dev/null)" 25 | # check if command script exists for input 26 | if [[ -f "${botdir}/commands/${input}.sh" ]]; then 27 | # source command script with line var as argument and fork it 28 | source "$botdir"/commands/"$input".sh "$line" & disown 29 | # break if input is exit and user id == owner_id 30 | elif [[ "$input" == "exit" && "$(printf "%s\n" "$line" | jq -r '.member.user.id')" == "$owner_id" ]]; then 31 | break 32 | # else unknown input 33 | else 34 | [[ "$input" != "Ready" ]] && echo -e "\nUnknown input:" 35 | printf "%s\n" "$line" | jq -r '.' 2>/dev/null || printf "%s\n" "$line" 36 | fi 37 | unset input 38 | fi 39 | done 40 | # remove pipe before exiting 41 | rm -f /tmp/.botpipe 42 | exit 0 43 | } 44 | 45 | # function to kill node and this script on exit or sigint 46 | exitfunc() { 47 | pkill node 48 | pkill bashbot 49 | } 50 | 51 | # start and fork pipe function 52 | echo "Starting bashbot pipe..." 53 | pipestart & disown 54 | 55 | # sleep to allow pipe to be created 56 | sleep 1 57 | trap "exitfunc" EXIT SIGINT 58 | # cd to botdir and start node process redirected to fifo pipe 59 | echo "Starting bashbot node process..." 60 | cd "$botdir" 61 | node index.js > /tmp/.botpipe 62 | -------------------------------------------------------------------------------- /commands.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "name": "info", 3 | "description": "NOTE: 'query' is *REQUIRED* when using the search and supported options!", 4 | "options": [ 5 | { 6 | "type": 3, 7 | "name": "option", 8 | "required": true, 9 | "description": "NOTE: 'query' is *REQUIRED* when using the search and supported options!", 10 | "choices": [ 11 | { 12 | "name": "Search for info", 13 | "value": "search" 14 | }, 15 | { 16 | "name": "Supported Linux Distros", 17 | "value": "supported" 18 | }, 19 | { 20 | "name": "Recommended Linux Distros", 21 | "value": "recommended" 22 | }, 23 | { 24 | "name": "Kubuntu", 25 | "value": "kubuntu" 26 | }, 27 | { 28 | "name": "Xubuntu", 29 | "value": "xubuntu" 30 | }, 31 | { 32 | "name": "Ubuntu MATE", 33 | "value": "ubuntu%20mate" 34 | }, 35 | { 36 | "name": "KDE neon", 37 | "value": "kde%20neon" 38 | }, 39 | { 40 | "name": "openSUSE Leap", 41 | "value": "opensuse" 42 | }, 43 | { 44 | "name": "Mageia", 45 | "value": "mageia" 46 | }, 47 | { 48 | "name": "Ubuntu", 49 | "value": "ubuntu" 50 | }, 51 | { 52 | "name": "Lubuntu", 53 | "value": "lubuntu" 54 | }, 55 | { 56 | "name": "Ubuntu Budgie", 57 | "value": "ubuntu%20budgie" 58 | }, 59 | { 60 | "name": "Long Term Support (LTS) Releases", 61 | "value": "lts" 62 | }, 63 | { 64 | "name": "Rolling release distros", 65 | "value": "rolling" 66 | }, 67 | { 68 | "name": "Arch", 69 | "value": "arch" 70 | }, 71 | { 72 | "name": "Arch Variants", 73 | "value": "arch%20variants" 74 | }, 75 | { 76 | "name": "Kali Linux", 77 | "value": "kali" 78 | }, 79 | { 80 | "name": "Manjaro", 81 | "value": "manjaro" 82 | }, 83 | { 84 | "name": "openSUSE Tumbleweed", 85 | "value": "tumbleweed" 86 | }, 87 | { 88 | "name": "Mint", 89 | "value": "mint" 90 | }, 91 | { 92 | "name": "Ubuntu Based", 93 | "value": "ubuntu%20based" 94 | }, 95 | { 96 | "name": "Snap Packages", 97 | "value": "snaps" 98 | } 99 | ] 100 | }, 101 | { 102 | "type": 3, 103 | "name": "query", 104 | "required": false, 105 | "description": "Only required when using 'search' or 'supported' options; will be ignored for other options." 106 | } 107 | ] 108 | }, 109 | { 110 | "name":"ping", 111 | "description":"Ping pong" 112 | }] -------------------------------------------------------------------------------- /commands/info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # function to get list of supported distros from spreadsheet maintained by Faith 4 | info_supported() { 5 | # use mapfile to create an array split on linebreaks from: 6 | # curl spreadsheet | 7 | # get rid of DataTable junk which leaves just json | 8 | # get rid of first line | 9 | # output each row from table | 10 | # get rid of first 3 rows | 11 | # find results that match $q | 12 | # limit results to 25 (max amount of fields that can be in embed) 13 | mapfile -t results < <(curl -sL 'https://spreadsheets.google.com/tq?&tq=&key=124ayAVJ1QPqEYZvtk_0uT3n-8QByf8LR7A43ah8QvDA&gid=2' | \ 14 | perl -pe 's%(.*google.visualization.Query.setResponse\(|\);)%%gm' | \ 15 | tail -n -1 | \ 16 | jq -c '.table.rows[].c' | \ 17 | tail -n +3 | \ 18 | grep -i "$1" | \ 19 | head -n 25) 20 | # check if results found 21 | if [[ -z "${results[@]}" ]]; then 22 | # results not found; set json to error message and return 23 | export json="$(jq -n --arg tit "Is ${1^} Supported in Discord Linux?" --arg res "No results found for '${1^}'." '{ "embeds": [ { "title": $tit, "url": "https://kutt.it/supported", "description": $res, "color": "13458524" } ] }')" 24 | return 25 | fi 26 | # results found; set initial json with title, url, color, and empty fields array 27 | json="$(jq -n --arg tit "Is ${1^} Supported in Discord Linux?" '{ "embeds": [ { "type": "rich", "title": $tit, "url": "https://kutt.it/supported", "color": "5793266", "fields": [] } ] }')" 28 | # run a for loop on the results to populate the fields 29 | for result in "${results[@]}"; do 30 | # distro 1st column 31 | distro="__$(echo "$result" | jq -r '.[0].v')__" 32 | # supported status 2nd column 33 | supd="**Supported**: $(echo "$result" | jq -r '.[1].v')" 34 | # experience level 3rd column 35 | exp="**Experience Level**: $(echo "$result" | jq -r '.[2].v')" 36 | # recommended status 4th column 37 | recd="**Recommended**: $(echo "$result" | jq -r '.[3].v')" 38 | # if notes exist, 5th column 39 | notes="$(echo "$result" | jq -r '.[4].v')" 40 | # if notes not found, do not include it in value 41 | if [[ "$notes" == "null" ]]; then 42 | value="$(echo -e "$supd\n$exp\n$recd")" 43 | # else format notes var and add to value 44 | else 45 | notes="**Notes**: $notes" 46 | value="$(echo -e "$supd\n$exp\n$recd\n$notes")" 47 | fi 48 | # add the values above to the existing fields array in the embed 49 | json="$(echo "$json" | jq --arg dist "$distro" --arg val "$value" '.embeds[0].fields += [ { "name": $dist, "value": $val, "inline": true } ]')" 50 | # unset any vars that might cause problems 51 | unset distro supd exp recd notes value 52 | done 53 | export json 54 | } 55 | 56 | # function to handle all other info queries 57 | info_other() { 58 | # try to get embed from firebase real time database 59 | embed="$(curl -sL "https://discord-fde27-default-rtdb.firebaseio.com/discord/info/$1.json")" 60 | if [[ "$embed" == "null" ]]; then 61 | # set embed to error if no entry in firebase exists 62 | # TODO: check wikipedia for results here and then set embed to error if no wikipedia results 63 | embed="$(jq -n --arg tit "Info for '$1'" --arg res "No results found for '$1'." '{"embed":{"title":$tit,"description":$res,"color":"13458524"}}')" 64 | fi 65 | # setup json using embed var from above 66 | json="$(printf "%s\n" "$embed" | jq '{ "embeds": [ .embed ] }')" 67 | } 68 | 69 | # get value of first option 70 | opt_value="$(printf "%s\n" "$@" | jq -r '.options[0].value')" 71 | # get interaction ID 72 | int_id="$(printf "%s\n" "$@" | jq -r '.id')" 73 | # get interaction token 74 | int_token="$(printf "%s\n" "$@" | jq -r '.token')" 75 | # respond to interaction with type 5 to tell user we're thinking and to prevent interaction timeout 76 | jq -cn '{ "type": 5 }' | curl -sSLX POST -d @- -H 'content-type: application/json' "https://discord.com/api/v8/interactions/$int_id/$int_token/callback" 77 | 78 | # check opt_value 79 | case "$opt_value" in 80 | supported) 81 | # set q to value of second option and run info_supported function 82 | q="$(printf "%s\n" "$@" | jq -r '.options[1].value')" 83 | info_supported "$q" 84 | ;; 85 | search) 86 | # set q to lowercase uri encoded value of second option and run info_other function 87 | q="$(printf "%s\n" "$@" | jq -r '.options[1].value | ascii_downcase | @uri')" 88 | info_other "$q" 89 | ;; 90 | *) 91 | # set q to opt_value and run info_other function 92 | q="$opt_value" 93 | info_other "$q" 94 | ;; 95 | esac 96 | 97 | # send json from above as data to webhook API using client_id and int_token to edit interaction with our results 98 | printf "%s\n" "$json" | curl -sSLX PATCH -d @- -H 'content-type: application/json' "https://discord.com/api/v8/webhooks/$client_id/$int_token/messages/@original" > /dev/null 99 | # log command, guild, user, and time 100 | echo -e "\ncommand: $(printf "%s\n" "$@" | jq -r '.name')\nguild: $(printf "%s\n" "$@" | jq -r '.guildId')\nuser: $(printf "%s\n" "$@" | jq -r '.member.user.id')\ntime: $(date)" 101 | -------------------------------------------------------------------------------- /commands/ping.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get interaction id from input 4 | int_id="$(printf "%s\n" "$@" | jq -r '.id')" 5 | # convert interaction id snowflake to unix time in ms 6 | int_time="$(((int_id>>22)+1420070400000))" 7 | # get ping by subtracting int_time from current unix time in ms 8 | ping="Pong! ($((($(date +%s%N)/1000000)-${int_time}))ms)" 9 | # get interaction token from input 10 | int_token="$(printf "%s\n" "$@" | jq -r '.token')" 11 | 12 | # use jq to create json and curl to make request to respond to interaction 13 | jq -n --arg pg "$ping" '{ "type": 4, "data": { "content": $pg } }' | curl -sSLX POST -d @- -H 'content-type: application/json' "https://discord.com/api/v8/interactions/$int_id/$int_token/callback" > /dev/null 14 | # log command, guild, user, and time 15 | echo -e "\ncommand: $(printf "%s\n" "$@" | jq -r '.name')\nguild: $(printf "%s\n" "$@" | jq -r '.guildId')\nuser: $(printf "%s\n" "$@" | jq -r '.member.user.id')\ntime: $(date)" 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const client = new(require("discord.js").Client) 2 | const { 3 | Slash 4 | } = require("discord-slash-commands"); 5 | const slash = new Slash({ 6 | client: client 7 | }) 8 | require('dotenv').config(); 9 | 10 | slash.on("command", async (command) => { 11 | var cmd = JSON.stringify({ "name" :command.name, "id": command.id, "token": command.token, "type": command.type, "options": command.options, "member": command.member, "guildId": command.guild.id }) 12 | console.log(cmd); 13 | if (command.name === "exit") { 14 | if (command.member.user.id === process.env.owner_id){ 15 | console.log('Disconnecting client...'); 16 | client.destroy(); 17 | console.log('Client disconnected. Exiting...'); 18 | process.exit(); 19 | } 20 | } 21 | }) 22 | 23 | client.on("ready", () => { 24 | console.log("Ready"); 25 | client.user.setActivity('with slash commands', { type: 'PLAYING' }); 26 | }) 27 | 28 | client.login(process.env.token) 29 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bashbot", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@discordjs/collection": { 8 | "version": "0.1.6", 9 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 10 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 11 | }, 12 | "@discordjs/form-data": { 13 | "version": "3.0.1", 14 | "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", 15 | "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", 16 | "requires": { 17 | "asynckit": "^0.4.0", 18 | "combined-stream": "^1.0.8", 19 | "mime-types": "^2.1.12" 20 | } 21 | }, 22 | "abort-controller": { 23 | "version": "3.0.0", 24 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 25 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 26 | "requires": { 27 | "event-target-shim": "^5.0.0" 28 | } 29 | }, 30 | "asynckit": { 31 | "version": "0.4.0", 32 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 33 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 34 | }, 35 | "axios": { 36 | "version": "0.21.1", 37 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", 38 | "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", 39 | "requires": { 40 | "follow-redirects": "^1.10.0" 41 | } 42 | }, 43 | "combined-stream": { 44 | "version": "1.0.8", 45 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 46 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 47 | "requires": { 48 | "delayed-stream": "~1.0.0" 49 | } 50 | }, 51 | "delayed-stream": { 52 | "version": "1.0.0", 53 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 54 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 55 | }, 56 | "discord-slash-commands": { 57 | "version": "git+https://github.com/ShadeDevelopment/discord-slash-commands.git#be16b7cdc3076af20ed7211639e22c0b1c5a407c", 58 | "from": "git+https://github.com/ShadeDevelopment/discord-slash-commands.git", 59 | "requires": { 60 | "axios": "^0.21.1" 61 | } 62 | }, 63 | "discord.js": { 64 | "version": "12.5.3", 65 | "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz", 66 | "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==", 67 | "requires": { 68 | "@discordjs/collection": "^0.1.6", 69 | "@discordjs/form-data": "^3.0.1", 70 | "abort-controller": "^3.0.0", 71 | "node-fetch": "^2.6.1", 72 | "prism-media": "^1.2.9", 73 | "setimmediate": "^1.0.5", 74 | "tweetnacl": "^1.0.3", 75 | "ws": "^7.4.4" 76 | } 77 | }, 78 | "dotenv": { 79 | "version": "10.0.0", 80 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 81 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" 82 | }, 83 | "event-target-shim": { 84 | "version": "5.0.1", 85 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 86 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" 87 | }, 88 | "follow-redirects": { 89 | "version": "1.14.1", 90 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", 91 | "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" 92 | }, 93 | "mime-db": { 94 | "version": "1.47.0", 95 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", 96 | "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" 97 | }, 98 | "mime-types": { 99 | "version": "2.1.30", 100 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", 101 | "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", 102 | "requires": { 103 | "mime-db": "1.47.0" 104 | } 105 | }, 106 | "node-fetch": { 107 | "version": "2.6.1", 108 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 109 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 110 | }, 111 | "prism-media": { 112 | "version": "1.2.9", 113 | "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.9.tgz", 114 | "integrity": "sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q==" 115 | }, 116 | "setimmediate": { 117 | "version": "1.0.5", 118 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 119 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" 120 | }, 121 | "tweetnacl": { 122 | "version": "1.0.3", 123 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", 124 | "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" 125 | }, 126 | "ws": { 127 | "version": "7.4.5", 128 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", 129 | "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==" 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bashbot", 3 | "version": "0.0.1", 4 | "description": "Logs slash commands to console to be used as a wrapper for bashbot", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Syretia", 11 | "license": "MIT", 12 | "dependencies": { 13 | "discord-slash-commands": "https://github.com/ShadeDevelopment/discord-slash-commands", 14 | "discord.js": "^12.5.2", 15 | "dotenv": "^10.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /timers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # script to execute timed events for bashbot 3 | 4 | # while loop that checks timers every 60 seconds 5 | while true; do 6 | # check if timers dir exists 7 | if [[ ! -d "$botdir/timers" ]]; then 8 | mkdir -p "$botdir"/timers 9 | fi 10 | # cd to timers dir and run a for loop on each timer in dir 11 | cd "$botdir"/timers 12 | for timer in *; do 13 | # check if any timers exist 14 | if [[ -z "$timer" ]]; then 15 | break 16 | fi 17 | # if timer is less than or equal to current unix time in nanoseconds 18 | if [[ "$timer" -le "$(date +%s%N)" ]]; then 19 | # get timer_action from stored json 20 | timer_action="$(cat "$botdir"/timers/"$timer" | jq -r '.name')" 21 | # check if command for timer_action exists 22 | if [[ -f "${botdir}/commands/${timer_action}.sh" ]]; then 23 | # get timer_json from timer file 24 | timer_json="$(cat "$botdir"/timers/"$timer")" 25 | # run timer_action command with timer_json as argument 26 | source "$botdir"/commands/"$timer_action".sh "$timer_json" 27 | rm "$botdir"/timers/"$timer" 28 | else 29 | # unknown timer_action 30 | echo -e "\nUnknown timer action: $timer_action" 31 | cat "$botdir"/timers/"$timer" | jq '.' 32 | rm "$botdir"/timers/"$timer" 33 | fi 34 | fi 35 | done 36 | sleep 60 37 | done 38 | --------------------------------------------------------------------------------