├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── alertsTesting.js
├── chartscreens
├── chart.png
├── failchart.png
├── failchartdiff.png
└── notfoundchart.png
├── common
├── commands.md
├── help_old.txt
└── metadata.json
├── docs
├── DB Schema is plain type with big5 encoding.txt
├── Fix for bug in graviex package.txt
├── How to set up keys file.txt
├── TsukiBotDB_Schema
└── puppeteer-debian-deps.txt
├── getCoinMeta.js
├── getCoinsCG.js
├── main.js
├── metaProcess.json
├── package-lock.json
├── package.json
├── process.json
├── public
├── bera1.png
├── bera2.png
├── blul1.png
├── blul2.png
├── crab0.png
├── crab1.png
├── crab2.png
├── crab3.png
├── cryptosoy1.png
├── cryptosoy2.png
└── tsukilogo.png
├── puppeteer.config.cjs
└── scheduledactiontestinhell.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es2021": true
6 | },
7 | "extends": "eslint:recommended",
8 | "parserOptions": {
9 | "ecmaVersion": "latest"
10 | },
11 | "rules": {
12 | "indent": [
13 | "error",
14 | 2
15 | ],
16 | "linebreak-style": [
17 | "error",
18 | "windows"
19 | ],
20 | "quotes": [
21 | "error",
22 | "single"
23 | ],
24 | "semi": [
25 | "error",
26 | "always"
27 | ]
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | tags.json
3 | docs/.DS_Store
4 | common/admin.json
5 | common/bannedWords.json
6 | common/coinsCG.json
7 | common/keys.api
8 | common/shortcuts.json
9 | common/metadata.json
10 | common/coinsCGtickers.json
11 | .DS_Store
12 | stuff
13 | graviex
14 | .vs
15 | .jshintrc
16 | *.png
17 | chartscreens
18 | .vscode
19 | common/coins.json
20 | common/coins_filtered.json
21 | common/help.json
22 | common/msg_id
23 | common/serverPerms.json
24 | common/puppeteer-cache
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Oscar F
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 | TsukiBot [](https://discordbots.org/bot/506918730790600704) [](https://discordbots.org/bot/506918730790600704)
2 | =======
3 | ### Welcome to the official GitHub repository for the ultimate all-in-one cryptocurrency bot for Discord! All features and code used in the production instance of TsukiBot is housed and maintained right here in this repo. If you have any questions, issues, suggestions, or just want to chat with us, feel free to join the TsukiBot discord server [here](https://discord.gg/VWNUbR5).
4 |
5 | ---
6 |
7 | ##### No annoying ads, no limits, no locked features, no BS! TsukiBot is a very powerful and easy to use Discord bot that makes for an excellent addition to your Discord crypto community!
8 |
9 | ##### Founded in 2017 and widely used in the earliest crypto Discord servers, TsukiBot is one of the oldest and most featured bots around with a proven reputation. TsukiBot is still in very active development with new features and enhancements being added regularly. So, what are you waiting for? Add TsukiBot to your server today and transform your community into a cryptocurrency powerhouse!
10 |
11 |
12 | ### The full detailed list of commands and their usage can be found in the commands document [right here in the repo.](https://github.com/EthyMoney/TsukiBot/blob/master/common/commands.md)
13 |
14 |
15 |
16 | ## Main Features:
17 | + Simple and detailed crypto prices
18 | + Customizable personal coin watch lists
19 | + TradingView charts
20 | + Coin market stats
21 | + Coin info and descriptions
22 | + Currency conversion tools
23 | + Global crypto market stats
24 | + Exchange margin funding stats
25 | + Specific price pairs from exchanges
26 | + Coin price movement heat maps
27 | + Traditional stocks prices
28 | + ETH gas fees tracking
29 | + Ethereum address balances lookup
30 | + Language translations
31 | + Server tags for saving links
32 | + Customizable command shortcuts
33 | + Market fear/greed index ratings
34 | + Biggest gainer and loser coin prices
35 | + Metrics for trending coins and bot usage
36 | + Protection from malicious files
37 | + ....and more! Join the support server to suggest features you want to see. We are listening!
38 |
39 |
40 |
41 | ## More of a visual person? Check out the screenshot gallery:
42 |
TsukiBot Demo
43 |
44 |
45 | ## Free Forever
46 | Wanna know a little secret? We don't operate on advertising, referrals, or commissions whatsoever. We operate solely on donations from kind users like yourself! If you like TsukiBot and want to show support for this effort, you can do so with a generous donation :)
47 |
48 | ETH & ERC20 donations to: `0x169381506870283cbABC52034E4ECc123f3FAD02` are greatly appreciated and help support future development!
49 |
50 |
51 | ---
52 |
53 | Let's keep in touch! Join our support Discord server where you can get help, report problems, and make suggestions for future updates and features!
54 | Join the support server here: [discord.gg/TsukiBot](https://discord.gg/VWNUbR5)
55 |
56 |
57 |
58 | [](https://discordbots.org/bot/506918730790600704)
59 |
60 |
--------------------------------------------------------------------------------
/alertsTesting.js:
--------------------------------------------------------------------------------
1 | // } else if (command === 'createalert' || command === 'delete' || command === 'modify') {
2 | // priceAlertsEngine(message, command, code_in[1], code_in[2], code_in[3], code_in[4], code_in[5]);
3 |
4 | // ^^^^ this is the commands section
5 |
6 | // vvvv here's the function
7 |
8 | // async function priceAlertsEngine(message, command, coinID, price, alertdirection, expiry, deleteAll = true) {
9 |
10 | // let authorID = message.author.id;
11 | // let authorName = message.author.username;
12 | // let channel = message.channel;
13 | // let current = [];
14 | // let availableExpSymbols = ["h", "d", "m", "y"];
15 |
16 | // // Expiration value validation
17 | // if (expiry && command == "create") {
18 | // let selectedExpSymbol = expiry.toLowerCase().substr(-1);
19 | // let selectedExpParam = expiry.toLowerCase().slice(0, -1);
20 | // let validExpSymbol = availableExpSymbols.includes(selectedExpSymbol);
21 | // let validExpParam = typeof value === 'number';
22 | // if (!validExpParam || !validExpSymbol) {
23 | // channel.send("Invalid expiration provided.");
24 | // return;
25 | // }
26 | // }
27 | // else {
28 | // let expiry = -1; // no expiration
29 | // }
30 |
31 |
32 |
33 | // switch (command) {
34 |
35 | // // * Works!
36 | // case "createalert":
37 | // // grab current alerts
38 | // await connp.one("SELECT * FROM tsukibot.pricealerts where userid = $1;", [authorID], (res) => {
39 | // //Check if current user array is empty or not and exit if it is
40 | // if (res.alerts && res.alerts.length > 0) {
41 | // // collect the current list if there is one
42 | // current = JSON.parse(res.alerts);
43 | // }
44 | // });
45 |
46 | // let alertJSON = {
47 | // "coinID": coinID,
48 | // "price": price,
49 | // "direction": alertdirection,
50 | // "creationTS": Date.now(),
51 | // "expirationTS": expiry,
52 | // "hasTriggered": false,
53 | // "triggeredTS": "null"
54 | // };
55 |
56 | // // add our new entry to db
57 | // current.push(alertJSON);
58 | // await connp.any(("INSERT INTO tsukibot.pricealerts(userid, alerts) VALUES($1,$2) ON CONFLICT(userid) DO UPDATE SET alerts = $2;"), [authorID, JSON.stringify(current)], (err, res) => {
59 | // if (err) { chalk.red.bold((err + "------price alert save error")); }
60 | // else {
61 | // console.log("new entry saved!");
62 | // }
63 | // });
64 | // break;
65 |
66 |
67 | // // * Works!
68 | // case "delete":
69 | // if (deleteAll) {
70 | // await connp.any("DELETE FROM tsukibot.pricealerts where userid = $1;", [authorID]);
71 | // break;
72 | // }
73 | // else {
74 | // // grab current alerts
75 | // await connp.one("SELECT * FROM tsukibot.pricealerts where userid = $1;", [authorID], (res) => {
76 | // //Check if current user array is empty or not and exit if it is
77 | // if (res.alerts && res.alerts.length > 0) {
78 | // // collect the current list if there is one
79 | // current = JSON.parse(res.alerts);
80 | // }
81 | // });
82 | // }
83 |
84 | // break;
85 | // case "modify":
86 |
87 | // break;
88 | // default:
89 | // console.log("we ded boisss");
90 | // }
91 | // }
92 |
93 | console.log(isNaN("kjjk"))
--------------------------------------------------------------------------------
/chartscreens/chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/chartscreens/chart.png
--------------------------------------------------------------------------------
/chartscreens/failchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/chartscreens/failchart.png
--------------------------------------------------------------------------------
/chartscreens/failchartdiff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/chartscreens/failchartdiff.png
--------------------------------------------------------------------------------
/chartscreens/notfoundchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/chartscreens/notfoundchart.png
--------------------------------------------------------------------------------
/common/commands.md:
--------------------------------------------------------------------------------
1 | TsukiBot [](https://discordbots.org/bot/506918730790600704) [](https://discordbots.org/bot/506918730790600704)
2 | ========
3 |
4 | #### Welcome to the official commands list! Here you can find all available commands and details on how to use them.
5 |
6 | (09/01/2022) IMPORTANT UPDATE REGARDING COMMAND INPUTS:
7 | ========
8 | As of September 1st, Discord is now requiring large bots to use slash commands reather than text prefix commands. What this means for TsukiBot is that you will now call the commands by starting with a / rather than the text prefixes like .tb or t
9 |
10 | TsukiBot currently supports slash commands at a fairly basic level, and not eveything will be perfect yet. This includes the documentation here, use it as reference, but keep in mind that these have been moved to being slash commands and not all of them are available as a slash command just yet.
11 |
12 | I'm working very hard to get things polished up and get everything working well and fully supported on slash commands, I just need to ask that you bear with me for this week as this transition is occurring. Be sure to [join the TsukiBot discord](https://discord.gg/VWNUbR5) for updates as I get this transition finished up.
13 |
14 | To use slash commands, simply start typing a "/" in discord and select TsukiBot from the list of bots. You will see all of the currently available commands and how to use them.
15 |
16 | If you are an experienced TsukiBot user, here's some quick translations that will help you get going:
17 | Coin Gecko price shortcut "t" is now /cg
18 | Charts ".tbc" is now /c
19 | Gas ".tb gas" is now /gas
20 | All other ".tb" commands are now just the command name with a / in front.
21 | Some commands have been renamed, you'll need to look over the list to see what you are looking for. I appologize for this, it will improve in the coming week!
22 |
23 |
24 | To resolve permissions issues, kick the bot and add it back using [THIS INVITE LINK](https://discordapp.com/oauth2/authorize?client_id=506918730790600704&scope=bot&permissions=268823664) and keep the requested permissions checked! These permissions are **REQUIRED** for the bot to work correctly!! If you need help, join the support server using the link at the bottom of this page.
25 |
26 | TsukiBot deletes files that are not photos or videos by default. The bot will create a role named "File Perms" when it joins. Add this role to yourself
27 | and any users that you authorize to send files. If a user doesn't have this role and the bot has manage messages perms allowed, their files will be deleted.
28 | This a recommended protection measure for crypto users to prevent the spread of malicious scripts, phishing malware, or accidentally shared private key files.
29 |
30 |
31 |
32 |
33 | Below is the old version of this commands doc, use it as reference until it gets rewritten for the newer slash commands very soon:
34 |
35 |
36 |
37 |
38 |
39 | #### All commands follow this general structure unless noted otherwise: `.tb `
40 |
41 |
42 | ## Simple CoinGecko Price Checks:
43 | ##### Usage: `t ` (either a single coin ticker, or a space-separated list of multiple tickers)
44 | This is the most commonly used command in the bot. It's a super simple and fast way to check prices of coins using CoinGecko. The prices available for this command are updated every 2 minutes and supports all (over 6000 and counting) coins listed on CoinGecko.
The default prefix to call for these prices is just `t`, but you can change this prefix to whatever you want it to be for your server using the shortcut command found down below on this page. You can call the price for just one coin, or multiple coins by listing them out with spaces between them. You must provide the coin TICKER symbol when using this command. For example, Ethereum has the ticker symbol ETH, and Bitcoin has the ticker symbol BTC, and so on..
You can also call this command and have it give prices in terms of ETH and BTC by adding a symbol behind the prefix. You can do this by adding a `*` or `+` right behind the prefix to call the coin(s) in BTC(satoshi) prices, or a `e` for ETH prices. See the examples down below on this page to see this in action.
45 |
46 | Examples:
47 | + `t eth` : Price of Ethereum
48 | + `t eth btc glm` : Price of Ethereum, Bitcoin, and Golem
49 | + `t+ eth` : Price of Ethereum in terms of BTC price
50 | + `te btc` : price of Bitcoin in terms of ETH price
51 | Simple enough right?
52 |
53 |
54 |
55 |
56 | ## TradingView Charts:
57 | ##### Usage: `.tbc `
58 | TsukiBot supports grabbing charts from TradingView and sending them as an image right in the channel where you called for them. This command is very versatile as its input is basically only limited by whatever TradingView can take. You can put stocks, cryptocurrencies, and whatever else is listed on TradingView these days.
Providing a timeframe, indicator, exchange, or other options are all completely optional and you can call this command with just a market/tradingview pair and it will default to the other options to TradingView's chart defaults (such as one hour timeframe, no idicators, and so on).
The following are the options currently tested to be supported by this command (with more on the way):
59 |
60 | + Pairs: Whatever pairs and tickers that TradingView supports. **NOTE:** with cryptos it works best to use a full pairing rather than just the single ticker. Like "btcusd" instead of just "btc"
61 | + Timeframes: 1m, 1, 3m, 3, 5m, 5, 15m, 15, 30m, 30, 1h, 60, 2h, 120, 3h, 180, 4h, 240, 1d, d, day, daily, 1w, w, week, weekly, 1mo, m, mo, month, monthly
62 | + Indicators: bb, bbr, bbw, crsi, ichi, ichimoku, macd, ma, ema, dema, tema, moonphase, pphl, pivotshl, rsi, stoch, stochrsi, williamr
63 | + Exchanges: binance, bitstamp, bitbay, bitfinex, bittrex, bybit, coinbase, ftx, gemini, hitbtc, kraken, kucoin, okcoin, okex, poloniex
64 | + Other Options: wide (widens the image to show more history), bera, blul (I won't tell you what these do, go ahead and try them yourself)
65 |
66 | Need a visual example? Check out the visual demo down below to see the charts command in action.
67 |
68 |
69 |
70 |
71 | ## Specific Real-Time Exchange/Index Price Checks:
72 | ##### Usage: `.tb `
73 | `` is the symbol of the exchange or index to check from. The available symbols are listed below. `` is the coin ticker to check the price of and `` is the currency ticker to show the price in. Providing a comparison is **optional** and will default to BTC or USD (depending on the exchange) if none is provided. While every exchange and index will support different comparisons, some common ones inlcude USD, BTC, EUR, and ETH. You can use the following shortcut symbols for the `` parameter, otherwise you can write the full name of the exchange if you prefer or forget the shortcut.
74 |
75 | + `cb`: Coinbase
76 | + `k`: Kraken
77 | + `p`: Poloniex
78 | + `b`: Binance
79 | + `cg`: CoinGecko
80 | + `f`: Bitfinex
81 | + `m`: BitMEX
82 | + `x`: Bittrex
83 | + `st`: STEX
84 | + `gr`: Graviex
85 |
86 | The following have this usage: `.tb ` Where `` can be either a single coin, or a space-separated list of multiple coins.
87 | + `c`: CryptoCompare in USD
88 | + `cs`: CryptoCompare in BTC
89 | + `cmc`: CoinMarketCap in USD
90 | + `cmcs`: CoinMarketCap in BTC
91 |
92 |
93 |
94 | ## Personal Array (Personal Coin Watchlists):
95 | These commands are for managing and checking your very own personal list of coins which you can call the prices of in various ways. All data for this command is sourced from CoinGecko.
96 | The following 3 commands follow the exact usage shown, followed by a space and then a space-separated list of mulptiple coin tickers. An example of this would be `.tb pa eth btc xrp glm`. This example would create a new personal list for you that contains eth, btc, xrp, and glm.
97 |
98 | + `.tb pa`: Create a new personal array, or overwrite your existing one
99 | + `.tb pa+`: Add coin(s) to your existing personal array
100 | + `.tb pa-`: Remove coin(s) from your current personal array
101 |
102 | These commands are used exactly as shown:
103 | + `.tbpa`: Call your array
104 | + `.tbpa+`: Call your array with BTC prices
105 | + `.tbpa*`: Call your array in expanded format with BTC prices
106 | + `.tbpae`: Call your array with ETH prices
107 | + `.tbpa%`: Call your array ordered by % change (greatest to least)
108 |
109 |
110 |
111 | ## Server Tags
112 | What are server tags? Server tags are an easy way to store links and images within your server that can be referenced by a name that you assign to them. Now instead of needing to find that old link to a page or picture, you can simply pull it up by its tag name. Think of this like bookmarking or "tagging" links that you want to have easily accessable within the server. This will work for direct links to pictures, videos, and webpages. Here's how to use TsukiBot's tag system:
113 |
114 | #### Warning: Tag names must have no spaces!
115 |
116 | + To make a new tag, use the createtag command: `.tb createtag `
117 | + To view a tag, use the tag command: `.tb tag `
118 | + To view all available tags in the server, use the taglist command: `.tb taglist`
119 | + To delete a tag, use the deletetag command: `.tb deletetag `
120 |
121 | Here's an example of creating a tag so you get the idea: `.tb createtag google www.google.com` (google being the tag's name, and www.google.com being the tag URL)
122 |
123 |
124 |
125 | ## Miscellaneous Commands
126 | ##### Usage: `.tb `
127 | These are commands that didn't cleanly fit into the other catagories, so they are here. They all follow the usage listed above and their parameters vary. Each commands parameter is listed next to the command below (if they have a parameter).
128 |
129 | + `mc` : Total global market cap as well as BTC dominance for all of crypto. (no parameter, and does not require the ".tb" prefix)
130 | + `mc `: Market cap, supply, and volume data for the provided coin. (accepts ticker, name, or MC rank number and does not require the ".tb" prefix)
131 | + `e `: Etherscan ETH balance details of ethereum address or transaction (accepts both 0x addresses, and ENS (name.eth) addresses!
132 | + `t `: Translate provided text to English using Google Translate
133 | + `myavatar` : Display and provide a link to your current avatar
134 | + `stock `: NSADAQ/NYSE Averaged price for a stock
135 | + `info `: Description about a given coin (accepts ticker, name, or MC rank number)
136 | + `id` : Get your unique Discord ID number DM'd to you
137 | + `funding` : Get the BitMEX perpetual swap contracts funding rates
138 | + `fg` : Get the current Bitcoin fear and greed index value
139 | + `ls` : Get the current open long and short positions for BTC on Bitmex
140 | + `invite` : Get a pre-permissioned link to add TsukiBot to your own server!
141 | + `@TsukiBot` : If you mention the bot it will reply to you and show the current response ping (doesn't require a command)
142 | + `gas` : Shows the current Ethereum gas prices required to send a transaction (shows the current slow price, standard price, and fast price)
143 | + `movers` : Shows the top 5 biggest gainers and losers coins for the day according to their % change. (filters the result to only show coins with a valid market cap and 24hr volume that's over 10k USD)
144 | + `.tb cv to ` Currency conversion tool for coins. This will convert a given amount of a coin(coin1) to another coin(coin2). Use the coin tickers for this command, not full names or IDs. You can use either "cv" or "convert" for the command (up to you). Example use:" `.tb cv 100 eth to usd`
145 |
146 | This one provides the bot session statistics and is used exactly as shown:
147 | + `.tb stat` : Bot session stats, most most requested coin, messages per minute, and link to support server
148 |
149 |
150 |
151 | ## Shortcuts
152 | These are shortcuts for getting to things a little faster and easier! All shortcuts follow the exact usage shown below.
153 |
154 | + `.tb shortcut ` : Set a new custom prefix to quickly access the CoinGecko price command in the server.
155 | Allowed shortcuts can only contain alphanumeric characters and/or `! $ % . _ , < > = + * &` with a max of 3 characters. This can only be set by a server admin.
156 | When calling your shortcut for prices, you can add a `*` or `+` right behind the shortcut to call the coin(s) in satoshi prices, or a `e` for ETH prices. See the examples down below to see this in action.
157 | + `.tbpop` : Get prices of top 10 coins my market cap
158 | + `.tbp` : Poloniex ETH/USD price
159 | + `.tbb` : Bittrex ETH/USD price
160 | + `.tbm` : Bitmex ETH/USD price
161 | + `.tbn` : Binance ETH/USD price
162 | + `.tbf` : Bitfinex ETH/USD price
163 | + `.tbt ` : Translation command shortcut
164 | + `.tbhmap`: Coin % changes as a heatmap image from Coin360
165 | + `mc` : Global market cap command shortcut
166 | + `mc ` : Specific coin market cap command shortcut
167 |
168 | The following can be used like the ones above to get ETH/USD prices **OR** they can have a comparison currency passed to them them. `` is optional and will default to USD if none is provided. USD, EUR, and BTC is supported for the comparison.
169 | + `.tbg ` : Coinbase ETH price in terms of the proivded comparison currency.
170 | + `.tbk ` : Kraken ETH price in terms of the provided comparison currency.
171 |
172 |
173 |
174 | ## Some helpful examples of usage:
175 | + `.tb k dash usd` ⇒ Kraken price for DASHUSD
176 | + `.tb c btc bch zec` ⇒ CryptoCompare price for BTCUSD, BCHUSD, ZECUSD
177 | + `.tb p doge xmr` ⇒ Poloniex price for DOGEXMR
178 | + `.tb cg eth eur` ⇒ CoinGecko price for ETHEUR
179 | + `.tb m btc` ⇒ BitMEX price for BTCUSD
180 | + `mc`
181 | ⇒ Total crypto market capitalization and BTC dominance
182 | + `mc eth` ⇒ Market cap and price history for ETH
183 | + `.tb t ` ⇒ Translate text to English (Example: `.tb t hola`)
184 | + `.tbg` ⇒ Shortcut Coinbase price for ETHUSD
185 | + `.tbg eur` ⇒ Shortcut Coinbase price for ETHEUR
186 | + `.tbk` ⇒ Shortcut Kraken price for ETHUSD
187 | + `.tb stock amd` ⇒ Stock price for $AMD
188 | + `.tb info eth` ⇒ Information about Ethereum (ETH)
189 | + `.tb cv 12 eth to btc` ⇒ See how much btc 12 eth equals (currency conversion)
190 |
191 |
192 |
193 | ## More of a visual learner? Check out these demonstration screenshots:
194 | TsukiBot Demo
195 |
196 |
197 | ---
198 |
199 | This document is subject to change as development continues.
200 | Be sure to join the support server for help with using the bot or understanding these commands. You can get help, report problems, and make suggestions for future updates and features!
201 | Join the support server here: [discordapp.com/TsukiBot](https://discord.gg/VWNUbR5)
202 | We also have a live [Trello board](https://trello.com/b/EVy3p2IU/tsukibot-development) where you can see what we're working on!
203 |
204 | ---
205 |
206 | ETH donations to: `0x169381506870283cbABC52034E4ECc123f3FAD02` are greatly appreciated! The bot is 100% free to use and a lot work goes into making TsukiBot the best crypto bot on Discord. We don't have any paid features, ads, or commissions whatsoever. A donation is an excellent way to say thanks and to help support future development!
207 |
208 | [](https://discordbots.org/bot/506918730790600704)
209 |
--------------------------------------------------------------------------------
/common/help_old.txt:
--------------------------------------------------------------------------------
1 | __**TsukiBot Commands**__
2 |
3 | **General Usage: ** `.tb `
4 |
5 | __Commands__
6 | `mc`: Market Cap (returns total market cap if called alone, otherwise will show the MC for a given coin)
7 | `m`: BitMEX
8 | `g`: Coinbase
9 | `k`: Kraken
10 | `p`: Poloniex
11 | `n`: Binance
12 | `f`: Bitfinex
13 | `b`: Bittrex
14 | `stex`: STEX
15 | `e`: Etherscan (address or transaction)
16 | `cg`: CoinGecko
17 | `t`: Translation
18 |
19 | (the following commands accept multiple coins for input)
20 | `c`: CryptoCompare in USD
21 | `cs`: CryptoCompare in BTC
22 | `cmc`: CoinMarketCap in USD (CMC can be called using a quicker custom shortcut, see below for details)
23 | `cmcs`: CoinMarketCap in BTC
24 |
25 |
26 | __Personal Array__
27 | `.tb pa`: Create or overwrite your personal array
28 | `.tb pa+`: Add coins to your current pa
29 | `.tb pa-`: Remove coins from your current pa
30 |
31 | `.tbpa`: Call the array
32 | `.tbpa+`: Call the array with BTC prices
33 | `.tbpa*`: Call the array in expanded format with BTC prices
34 | `.tbpa%`: Call the array ordered by % change (least to greatest)
35 |
36 | __Extras__
37 | `.tbstat`: Bot Session Statistics
38 | `.tb shortcut [prefix]`: Set a custom prefix to access CMC in the server. Alphanumeric and/or `! $ % . _ , < > = + * &`; max. 3 characters.
39 | When calling your shortcut for prices, you can add a `*` right behind the shortcut set to call the coin(s) in satoshi prices. See below for example.
40 |
41 | (Use as [prefix] eth btc xrp, or as [prefix]* eth btc xrp for prices in sats)
42 |
43 |
44 | __Server Management and Coin Subs__
45 |
46 | __Rooms and Roles__
47 | `.tb join [valid coin]` : TsukiBot assigns the role to the user, granting the user access to the corresponding room
48 | `.tbleave` : Leave all rooms
49 | `.tblist` : Get the available rooms for the server
50 |
51 | __(Owner Only)__
52 | `.tb subrole [Name]` : Create a role
53 | `.tb makeroom [valid coin]`: Create a private room and a role for a whitelisted coin
54 |
55 |
56 |
57 | __Some helpful examples of usage__:
58 | `.tb k dash usd` ⇒ Kraken price for DASHUSD
59 | `.tb c btc bch zec` ⇒ CryptoCompare price for BTCUSD, BCHUSD, ZECUSD
60 | `.tb p doge xmr` ⇒ Poloniex price for DOGEXMR
61 | `.tb cg eth eur` ⇒ CoinGecko price for ETHEUR
62 | `.tb m btc` ⇒ BitMEX price for BTCUSD
63 | `mc` ⇒ Total crypto market capitalization and BTC dominance
64 | `mc eth` ⇒ Market cap and price history for ETH
65 | `.tb t ` ⇒ Translate text to English (Example: `.tb t hola`)
66 | `.tbg` ⇒ Shortcut Coinbase price for ETHUSD
67 | `.tbg eur` ⇒ Shortcut Coinbase price for ETHEUR
68 | `.tbk` ⇒ Shortcut Kraken price for ETHUSD
69 |
70 | __Side Notes__:
71 | All exchange price commands will default to showing the requested coin in terms of USD unless you specify a coin to show it in.
72 |
73 | `I delete non-image files if I have deletion perms. Files are unsafe!`
74 |
--------------------------------------------------------------------------------
/docs/DB Schema is plain type with big5 encoding.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/docs/DB Schema is plain type with big5 encoding.txt
--------------------------------------------------------------------------------
/docs/Fix for bug in graviex package.txt:
--------------------------------------------------------------------------------
1 | The graviex.js file in the graviex module will need to have the callbacks uncommented, and the console outputs commented out for the ticker function. This is necessary or the module will not function correctly. This setup will also feed the bot any errors found in the response from the API so that it can be caught, handled, and reported nicely.
2 |
3 |
4 |
5 | Copy and paste this code over the existing ticker function in the graviex.js file. The ticker function should look as follows:
6 |
7 |
8 |
9 | exports.ticker = function(market, callback){
10 |
11 | var uri = "tickers/" + market;
12 |
13 | exports.apiRequest(uri, function(result){
14 |
15 | if(result.success){
16 |
17 | return callback(JSON.parse(result.message));
18 |
19 | //console.log(result.message);
20 |
21 | }else{
22 |
23 | return callback(JSON.parse(result.error));
24 |
25 | //console.log(result.error);
26 |
27 |
28 | }
29 |
30 | })
31 |
32 | }
--------------------------------------------------------------------------------
/docs/How to set up keys file.txt:
--------------------------------------------------------------------------------
1 | Create a file named keys.api in the common folder. Put the following structure in that file:
2 |
3 |
4 | {
5 | "name": "TsukiBot",
6 | "etherscan": "",
7 | "infura": "",
8 | "coinbase": "",
9 | "apisecret": "",
10 | "tsukibot": "",
11 | "stex": "",
12 | "stexSecret": "",
13 | "token": "",
14 | "dbl": "no",
15 | "coinmarketcap1": "",
16 | "coinmarketcap2": "",
17 | "coinmarketcap3": "",
18 | "coinmarketcap4": "",
19 | "coinmarketcap5": "",
20 | "coinmarketcap6": "",
21 | "coinmarketcap7": "",
22 | "coinmarketcap8": "",
23 | "coinmarketcap9": "",
24 | "coinmarketcap10": "",
25 | "coinmarketcap11": "",
26 | "coinmarketcap12": "",
27 | "coinmarketcapfailover": "",
28 | "coinmarketcapfailover2": "",
29 | "graviexAccessKey": "",
30 | "graviexSecretKey": "",
31 | "finnhub": ""
32 | }
33 |
34 |
35 | This is where you put your api keys and other various keys and passwords that will be plugged into the bot during initialization. Put your own keys inside the empty quotes next to each field. Leave the name and dbl feilds alone.
36 |
37 |
38 | For reference, here's what a few of those actually are:
39 |
40 | "tsukibot" -> your postgresql database password
41 | "token" -> your bot's token from the discord dev portal
42 | "alpha" -> your api key for alpha vantage (stocks)
43 |
44 |
--------------------------------------------------------------------------------
/docs/TsukiBotDB_Schema:
--------------------------------------------------------------------------------
1 | --
2 | -- PostgreSQL database dump
3 | --
4 |
5 | -- Dumped from database version 12.0
6 | -- Dumped by pg_dump version 12.0
7 |
8 | -- Started on 2019-11-21 19:02:29
9 |
10 | SET statement_timeout = 0;
11 | SET lock_timeout = 0;
12 | SET idle_in_transaction_session_timeout = 0;
13 | SET client_encoding = 'BIG5';
14 | SET standard_conforming_strings = on;
15 | SELECT pg_catalog.set_config('search_path', '', false);
16 | SET check_function_bodies = false;
17 | SET xmloption = content;
18 | SET client_min_messages = warning;
19 | SET row_security = off;
20 |
21 | --
22 | -- TOC entry 8 (class 2615 OID 16396)
23 | -- Name: tsukibot; Type: SCHEMA; Schema: -; Owner: postgres
24 | --
25 |
26 | CREATE SCHEMA tsukibot;
27 |
28 |
29 | ALTER SCHEMA tsukibot OWNER TO postgres;
30 |
31 | SET default_tablespace = '';
32 |
33 | SET default_table_access_method = heap;
34 |
35 | --
36 | -- TOC entry 203 (class 1259 OID 16412)
37 | -- Name: profiles; Type: TABLE; Schema: tsukibot; Owner: bigboi
38 | --
39 |
40 | CREATE TABLE tsukibot.profiles (
41 | coins character(1000),
42 | id character(45)
43 | );
44 |
45 |
46 | ALTER TABLE tsukibot.profiles OWNER TO bigboi;
47 |
48 | --
49 | -- TOC entry 2688 (class 2606 OID 16435)
50 | -- Name: profiles id; Type: CONSTRAINT; Schema: tsukibot; Owner: bigboi
51 | --
52 |
53 | ALTER TABLE ONLY tsukibot.profiles
54 | ADD CONSTRAINT id UNIQUE (id);
55 |
56 |
57 | -- Completed on 2019-11-21 19:02:29
58 |
59 | --
60 | -- PostgreSQL database dump complete
61 | --
62 |
63 |
--------------------------------------------------------------------------------
/docs/puppeteer-debian-deps.txt:
--------------------------------------------------------------------------------
1 | sudo apt install ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils -y
2 |
--------------------------------------------------------------------------------
/getCoinMeta.js:
--------------------------------------------------------------------------------
1 | //
2 | // This file is responsible for caching all of the coin metadata from the CoinGecko API
3 | // This is done by calling the CoinGecko API for each coin and then adding it to a json object that is then written to a file
4 | // Coins are cached one at a time with a delay between them so as to not exceed the API rate limit for the CoinGecko metadata endpoint
5 | //
6 |
7 | const fs = require('fs');
8 | const chalk = require('chalk');
9 | const CoinGecko = require('coingecko-api');
10 | const { JSDOM } = require('jsdom');
11 | const S = require('string');
12 | const CoinGeckoClient = new CoinGecko();
13 | const process = require('node:process');
14 |
15 | let meta = { 'data': [] };
16 | let skipped = [];
17 | let count = 0;
18 | let cgCoinsList = '';
19 | let queryTimeout = 15000; // milliseconds for sleeping between api calls to avoid rate limiting
20 |
21 |
22 | //* makes the call to the CoinGecko API and sets the resJSON global variable to the response
23 | //* also tracks the number of attempts made to get the data and if it fails, it will increase the attempt number and try again
24 | async function getCGdata(coin, index) {
25 | let attempt = 1;
26 | let resJSON;
27 | while (!resJSON && attempt <= 10) {
28 | try {
29 | resJSON = await CoinGeckoClient.coins.fetch(coin, {
30 | 'localization': false, 'tickers': false,
31 | 'market_data': false, 'developer_data': false
32 | });
33 | } catch {
34 | console.log(chalk.yellowBright(`Attempt ${chalk.magentaBright(attempt)} failed for ${chalk.cyanBright(coin)} : (${index})` + (attempt === 10 ? chalk.redBright(' ---> All attempts failed!') : ' --> Re-attempting')));
35 | attempt++;
36 | await sleep(queryTimeout);
37 | }
38 | }
39 | if (attempt > 1) chalk.greenBright(`Attempt ${attempt} succeeded for ${chalk.cyanBright(coin)}`);
40 | return resJSON;
41 | }
42 |
43 | //* collects the metadata for a coin and does some cleanup and formatting on the data before then adding it to the meta object
44 | async function collectMetadata(coin, index) {
45 | const resJSON = await getCGdata(coin, index);
46 | if (!resJSON || resJSON.error || !resJSON.data.symbol || !resJSON.data.name) {
47 | skipped.push(coin);
48 | console.log(chalk.yellowBright(`SKIPPED COIN: ${chalk.cyan(coin)} due to missing or bad data. Proceeding...`));
49 | return;
50 | }
51 |
52 | // set the description re-formatted, otherwise just leave it blank if there isn't one found (the bot will handle this properly)
53 | const desc = resJSON.data.description ? formatDescription(resJSON.data.description.en) : '';
54 | if (!desc) console.log(chalk.magenta(`No description found for: ${chalk.cyan(coin)} - Saving a blank description and proceeding...`));
55 |
56 | // now can assemble a new meta object for this coin and then add it to the global meta json array for writing to file later
57 | meta.data.push({
58 | id: ++count,
59 | coin: resJSON.data.symbol.toUpperCase(),
60 | name: resJSON.data.name,
61 | slug: resJSON.data.id,
62 | logo: resJSON.data.image.large,
63 | description: desc,
64 | links: resJSON.data.links
65 | });
66 | }
67 |
68 | //* formatting and cleaning up data in the description field for the coin
69 | function formatDescription(description) {
70 | const descDOM = new JSDOM(description);
71 | const elements = descDOM.window.document.getElementsByTagName('a');
72 | const convertedLinks = Array.from(elements).map(e => `[${e.text}](${e.href})`);
73 |
74 | // replace each html link in the description string its the corresponding converted link we created earlier
75 | convertedLinks.forEach(link => {
76 | const locatedString = S(description).between('`;
78 | description = description.replace(lookupString, link);
79 | });
80 |
81 | // clean up the newline formatting and whitespace, then return the description
82 | // Clean up the newline formatting and whitespace, then return the description
83 | try {
84 | return S(description).collapseWhitespace().replaceAll('\r\n', '\n').s;
85 | }
86 | catch (e) {
87 | console.error(chalk.yellow('Description formatting failed, returning a blank string. Error details:\n', e));
88 | return '';
89 | }
90 | }
91 |
92 | //* once all of the coins have been collected and had their data formatted, this will get called to write the meta object to a file
93 | function writeToFile() {
94 | fs.writeFileSync('./common/metadata.json', JSON.stringify(meta));
95 | if (skipped.length > 0) {
96 | console.log(chalk.yellow(`Warning: The following coins were skipped due to missing data on API at their call time: ${chalk.cyan(skipped.toString())}`));
97 | }
98 | console.log(chalk.greenBright('Caching operation completed successfully and file was written!'));
99 | }
100 |
101 | //* utility function used to wait in an async function
102 | function sleep(ms) {
103 | return new Promise(resolve => setTimeout(resolve, ms));
104 | }
105 |
106 | //* starts the process of collecting the metadata for all of the coins and handles rate limiting and calling of the other functions
107 | async function startup() {
108 | cgCoinsList = await CoinGeckoClient.coins.list();
109 | if (cgCoinsList == 0) {
110 | console.log(chalk.red('Could not grab coins list, likely currently rate limited or API is down. Exiting..'));
111 | process.exit(1);
112 | }
113 | for (let i = 0; i < cgCoinsList.data.length; i++) {
114 | const coinData = cgCoinsList.data[i];
115 | const progress = chalk.green(` (${i + 1} of ${cgCoinsList.data.length})`);
116 | if (!coinData.id) {
117 | console.log(chalk.yellow('NO ID FOUND [SKIPPED]') + progress);
118 | } else {
119 | console.log(chalk.cyan(coinData.id) + progress);
120 | await collectMetadata(coinData.id, i + 1);
121 | }
122 | await sleep(queryTimeout); // Rate limiting requests to not exceed API limits
123 | }
124 | writeToFile();
125 | }
126 |
127 | // for starting when running this file directly
128 | startup();
129 | // for exporting to be imported and used in other files like the bot files
130 | exports.run = startup;
131 |
--------------------------------------------------------------------------------
/getCoinsCG.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const chalk = require('chalk');
3 |
4 | //
5 | //
6 | // The purpose of this function is to gather all available tickers on CoinGecko and write them in JSON format to file.
7 | // This is so the bot can check and verify coin existence, and also refer to the coins by their market ticker instead of the full name.
8 | // This file should be run once before starting the bot for the first time. It will be auto-run by the bot after.
9 | //
10 | //
11 |
12 |
13 | // Import coingecko-api
14 | const CoinGecko = require('coingecko-api');
15 |
16 | // Initiate the CoinGecko API Client
17 | const CoinGeckoClient = new CoinGecko();
18 |
19 | // Make API call and do JSON build operation
20 | var update = async () => {
21 | let data, tickers = [];
22 | try {
23 | data = await CoinGeckoClient.coins.list();
24 | for (const value of data.data) {
25 | tickers.push(value.symbol.toUpperCase());
26 | }
27 | } catch (err) {
28 | if (data?.code) {
29 | console.log(chalk.red(`Unable to grab list of all CG coins: Error ${data.code}: ${data.message}`));
30 | }
31 | }
32 |
33 | //console.log(data);
34 |
35 | // Write the identification JSON to file
36 | fs.writeFileSync('./common/coinsCG.json', JSON.stringify(data.data));
37 | fs.writeFileSync('./common/coinsCGtickers.json', JSON.stringify(tickers));
38 | //console.log("CoinGecko coin list complete!");
39 | };
40 |
41 | update();
42 |
43 | exports.update = update;
44 |
--------------------------------------------------------------------------------
/metaProcess.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps": [
3 | {
4 | "name": "cg-meta-cache",
5 | "script": "getCoinMeta.js",
6 | "log_date_format": "YYYY-MM-DD HH:mm",
7 | "ignoreWatch": [
8 | "node_modules",
9 | "common",
10 | "public",
11 | "chartscreens",
12 | "stuff"
13 | ],
14 | "watch": true,
15 | "args": [
16 | "--no-autorestart",
17 | "--color"
18 | ],
19 | "env": {
20 | "DEBUG_COLORS": true
21 | },
22 | "node-args": [
23 | "--max-old-space-size=6144"
24 | ]
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tsukibot",
3 | "version": "1.0.0",
4 | "description": "Discord bot for cryptocurrency prices, charts, coin details, market statistics, personalized tracking tools, and so much more!",
5 | "main": "main.js",
6 | "directories": {
7 | "doc": "docs"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no tests available yet!\" && exit 1",
11 | "dev": "node main.js -d"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/EthyMoney/TsukiBot.git"
16 | },
17 | "keywords": [
18 | "discord",
19 | "cryptocurrency",
20 | "crypto",
21 | "trading",
22 | "stocks",
23 | "bitcoin",
24 | "ethereum",
25 | "eth",
26 | "btc",
27 | "tsuki",
28 | "tsukibot"
29 | ],
30 | "author": "Logan S. (EthyMoney)",
31 | "license": "MIT",
32 | "bugs": {
33 | "url": "https://github.com/EthyMoney/TsukiBot/issues"
34 | },
35 | "homepage": "https://github.com/EthyMoney/TsukiBot#readme",
36 | "dependencies": {
37 | "@google-cloud/translate": "^8.5.0",
38 | "ccxt": "^1.95.43",
39 | "chalk": "^4.1.2",
40 | "coingecko-api": "^1.0.10",
41 | "coinmarketcap-api": "^3.1.1",
42 | "cryptocompare": "^1.0.0",
43 | "currencyexchanges": "^1.1.1",
44 | "didyoumean": "^1.2.2",
45 | "discord.js": "^14.19.3",
46 | "express": "^4.21.2",
47 | "fast-average-color-node": "^3.1.0",
48 | "finnhub": "^1.2.19",
49 | "graviex": "^1.0.0",
50 | "jsdom": "^24.1.3",
51 | "node-schedule": "^2.1.1",
52 | "pg": "^8.16.0",
53 | "pixel-diff": "^1.0.1",
54 | "puppeteer": "^23.11.1",
55 | "puppeteer-cluster": "^0.24.0",
56 | "string": "^3.3.3",
57 | "topgg-autoposter": "^2.0.2",
58 | "web3": "^1.10.4",
59 | "ws": "^8.18.2"
60 | },
61 | "devDependencies": {
62 | "eslint": "^8.57.1"
63 | },
64 | "engines": {
65 | "node": ">=16.9.0",
66 | "npm": ">=8.13.3"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/process.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps": [
3 | {
4 | "name": "tsuki",
5 | "script": "main.js",
6 | "log_date_format": "YYYY-MM-DD HH:mm",
7 | "ignoreWatch": [
8 | "node_modules",
9 | "common",
10 | "public",
11 | "chartscreens",
12 | "stuff"
13 | ],
14 | "watch": false,
15 | "args": [
16 | "--color"
17 | ],
18 | "env": {
19 | "DEBUG_COLORS": true
20 | },
21 | "node-args": [
22 | "--max-old-space-size=6144"
23 | ]
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/public/bera1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/bera1.png
--------------------------------------------------------------------------------
/public/bera2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/bera2.png
--------------------------------------------------------------------------------
/public/blul1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/blul1.png
--------------------------------------------------------------------------------
/public/blul2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/blul2.png
--------------------------------------------------------------------------------
/public/crab0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/crab0.png
--------------------------------------------------------------------------------
/public/crab1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/crab1.png
--------------------------------------------------------------------------------
/public/crab2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/crab2.png
--------------------------------------------------------------------------------
/public/crab3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/crab3.png
--------------------------------------------------------------------------------
/public/cryptosoy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/cryptosoy1.png
--------------------------------------------------------------------------------
/public/cryptosoy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/cryptosoy2.png
--------------------------------------------------------------------------------
/public/tsukilogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthyMoney/TsukiBot/82cb4bb9d81de14edf67ea6922cd01324b64b496/public/tsukilogo.png
--------------------------------------------------------------------------------
/puppeteer.config.cjs:
--------------------------------------------------------------------------------
1 | const { join } = require('path');
2 |
3 | /**
4 | * @type {import("puppeteer").Configuration}
5 | */
6 | module.exports = {
7 | // Changes the cache location for Puppeteer.
8 | cacheDirectory: join(__dirname, 'common', 'puppeteer-cache'),
9 | };
--------------------------------------------------------------------------------
/scheduledactiontestinhell.js:
--------------------------------------------------------------------------------
1 | //------------------------------------------
2 | //------------------------------------------
3 |
4 |
5 | // !!! Maybe make a separate commands() function that just takes the command content and returns whatever it's output woulda been.
6 | // !!! Then send that with .channels.cache.get('1234567890').send('Hello world.');
7 | // !!! idk dude, I'm fukin cracked rn and this is kinda ass. we need a fukin message object, but it be mega gay and can't save.
8 | // !!! the other option we have would be to call constructors up tha ass and create new objects with the client to generate a message object
9 | // !!! that we can pass over to the normal commands processor. This would mean a chain of constructors for message(), guild(), author() and so on
10 | // !!! So in summary, the 4am me says to you: go fuck yourself and good luck ;)
11 |
12 | // Scheduled commands handler
13 | async function scheduledCommandsEngine(message, action, frequency, channel) {
14 | if (action) {
15 |
16 | // Need to check for admin perms here
17 | // Also need to pull existing jobs for the guild to count them and make a new job ID
18 | // Useful later: .channels.cache.get('1234567890').send('Hello world.');
19 |
20 | console.log("bru")
21 | action = action.toLowerCase();
22 | switch (action) {
23 | case "create":
24 | let helpText = "Enter your interval in HH:MM format. For example," + " every 30 minutes = 00:30 and every day = 24:00. The shortest allowed interval is 5 minutes (00:05)";
25 | let jobID = uniqid();
26 | let timeframeMS, channelID;
27 | let lastFired = 0;
28 | let command = message.content.match(/"([^']+)"/)[1];
29 |
30 | // Validate and process input
31 | if (command && frequency && channel) {
32 | // Validate the timeframe
33 | if (validateTime(frequency)) {
34 | let a = frequency.split(":");
35 | timeframeMS = ((+a[0]) * 60 * 60 + (+a[1]) * 60) * 1000;
36 | // Validate the command
37 | if (command) {
38 | if (message.mentions.channels.first()) {
39 | channelID = message.mentions.channels.first().id;
40 | }
41 | else {
42 | channelID = channel;
43 | }
44 | console.log(channelID);
45 | // Validate the channel
46 | if (channelID) {
47 | // Yay, all checks have passed! Let's get this confirmed with the user now
48 | let filter = m => m.author.id === message.author.id;
49 | message.channel.send(`Just to confirm, you want to run the command \`${command}\` in <#${channelID}> every ${(a[0] > 0) ? +a[0] + " hours " : ""}` +
50 | `${(a[1] > 0) ? +a[1] + " minutes" : ""}. Does this look correct?`).then(() => {
51 | message.channel.awaitMessages(filter, {
52 | max: 1,
53 | time: 60000,
54 | errors: ['time']
55 | })
56 | .then(message => {
57 | message = message.first();
58 | if (message.content.toUpperCase() == 'YES' || message.content.toUpperCase() == 'Y') {
59 | message.channel.send('Got it, your scheduled command task has been created! You can view all of your scheduled commands with `.tb schedule show`.');
60 | // Send to the db
61 | connp.none('INSERT INTO tsukibot.scheduled_actions(job_id, creation_ts, command, schedule, last_fired_ts, msg_object, channel_id) ' +
62 | 'VALUES(${jobID}, ${creationTS}, ${command}, ${scheduleMS}, ${lastFire}, ${msgObject}, ${channelID})', {
63 | jobID: jobID,
64 | creationTS: Date.now(),
65 | command: command,
66 | scheduleMS: timeframeMS,
67 | lastFire: lastFired,
68 | msgObject: JSON.stringify(message),
69 | channelID: channelID
70 | }).catch(err => {
71 | console.log(err + "----schedule action creation db insertion error");
72 | message.channel.send("OOPS nevermind. I ran into an issue when saving the scheduled command. Please try again later or notify us in the support server if this persists!");
73 | });
74 | } else if (message.content.toUpperCase() == 'NO' || message.content.toUpperCase() == 'N') {
75 | message.channel.send("Alright, I won't save it. You can start over by running this command again.");
76 | } else {
77 | message.channel.send("Aborted: Invalid response. Expecting yes or no input.");
78 | }
79 | })
80 | .catch(collected => {
81 | console.log(collected);
82 | message.channel.send("I didn't hear any response from you so I\'ll cancel this action. You can try again by re-running this command.");
83 | });
84 | });
85 | }
86 | else {
87 | message.reply("Invalid channel provided. Tag the channel like #Channel or provide the ID number you get by right clicking on it.");
88 | }
89 | }
90 | else {
91 | message.reply("Invalid command entered. Remember to enter the command just as you would normally in chat, but surround it with quotes like \"this\". Example: \".tb hmap\"");
92 | }
93 | }
94 | else {
95 | message.reply("Invalid timeframe entered. " + helpText);
96 | return;
97 | }
98 | }
99 | else {
100 | message.reply("Missing some arguments! Here\'s how to use this command:\n" + sendHelp());
101 | }
102 |
103 |
104 | break;
105 |
106 | case "delete":
107 | // First we gather all tasks, then find the ones that are due to run
108 | let res = await connp.any('SELECT * FROM tsukibot.scheduled_actions');
109 | console.log(res);
110 | let queuedToRun = [];
111 | res.forEach((item, index, array) => {
112 | if (Date.now() - item.last_fired_ts >= item.schedule) {
113 | // Let's grab the message object from the db
114 | let msg = JSON.parse(item.msg_object);
115 | // Update the channel propery with correct channel
116 | msg.channel = item.channel_id;
117 | // Forward the message to commands processor for normal handling
118 | commands(msg);
119 | // Now lets update the "last fired" timestamp of this job in the db so we can track this run
120 | connp.query('INSERT INTO tsukibot.scheduled_actions(last_fired_ts) VALUES($1) WHERE job_id = $2)', Date.now(), item.job_id);
121 | }
122 | });
123 | break;
124 |
125 | case "show":
126 | console.log("wttfff")
127 | let gay = await connp.any('SELECT * FROM tsukibot.scheduled_actions');
128 | console.log(gay);
129 | client.channels.cache.get('567970908451635202').send('Hello here!');
130 |
131 | break;
132 | }
133 | }
134 | // Do the normal tasks if no user action is provided (function called without user input)
135 | else {
136 | // First we gather all tasks, then find the ones that are due to run
137 | let res = await connp.any('SELECT * FROM tsukibot.scheduled_actions');
138 | console.log(res);
139 | let queuedToRun = [];
140 | res.forEach((item, index, array) => {
141 | if (Date.now() - item.last_fired_ts >= item.schedule) {
142 | //queuedToRun.push(item);
143 | // Let's build a message object based on the job so we can send it to the commands processor
144 | let msg = new Discord.Message(client, {
145 | id: 848465205919088650,
146 | type: 'DEFAULT',
147 | content: item.command,
148 | author: item.author_id,
149 | pinned: null,
150 | tts: null,
151 | embeds: null,
152 | attachments: null,
153 | nonce: "123" // idfk
154 | }, client.channels.cache.get(item.channel_id));
155 | // Send the generated message to the commands processor
156 | commands(msg);
157 | // Now lets update the "last fired" timestamp of this job in the db so we can track this run
158 | connp.query('INSERT INTO tsukibot.scheduled_actions(last_fired_ts) VALUES($1) WHERE job_id = $2)', Date.now(), item.job_id);
159 | }
160 | });
161 | }
162 | }
--------------------------------------------------------------------------------