├── .dockerignore ├── .eslintrc.json ├── .github └── workflows │ ├── Deploy.yml │ └── ESLint.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── commands.js ├── index.js ├── logger.js └── redis.js └── update.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .github/ 3 | .vscode/ 4 | build/ 5 | old/ 6 | 7 | LICENSE 8 | README.md 9 | renovate.json 10 | update.sh 11 | *.lock 12 | *.log 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@augu/eslint-config" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/Deploy.yml: -------------------------------------------------------------------------------- 1 | #name: Deploy to server 2 | #on: 3 | # push: 4 | # branches: 5 | # - 'master' 6 | # paths-ignore: 7 | # - '.github/**' 8 | # - '.vscode/**' 9 | # - '*.md' 10 | # - 'LICENSE' 11 | # - '.gitignore' 12 | #jobs: 13 | # deploy: 14 | # runs-on: ubuntu-latest 15 | # steps: 16 | # - uses: actions/checkout@v2 17 | # - name: Use Node.js v14.x 18 | # uses: actions/setup-node@v1 19 | # with: 20 | # node-version: 14.x 21 | # - name: Install global packages 22 | # run: npm i -g eslint 23 | # - name: Installs dependencies 24 | # run: npm install 25 | # - name: Lint the repository 26 | # run: eslint src --ext .js --fix 27 | # - name: Deploy to server 28 | # uses: appleboy/ssh-action@master 29 | # with: 30 | # host: ${{ secrets.HOST }} 31 | # port: 22 32 | # username: ${{ secrets.USERNAME }} 33 | # password: ${{ secrets.PASSWORD }} 34 | # script: | 35 | # cd ~/pressfbot 36 | # git pull 37 | # rm -fr node_modules 38 | # rm yarn.lock 39 | # yarn 40 | # pm2 restart pressfbot 41 | -------------------------------------------------------------------------------- /.github/workflows/ESLint.yml: -------------------------------------------------------------------------------- 1 | name: ESLint 2 | on: 3 | push: 4 | branches: 5 | - 'master' 6 | paths-ignore: 7 | - '.github/**' 8 | - '.vscode/**' 9 | - '*.md' 10 | - 'LICENSE' 11 | - '.gitignore' 12 | pull_request: 13 | branches: 14 | - 'master' 15 | paths-ignore: 16 | - '.github/**' 17 | - '.vscode/**' 18 | - '*.md' 19 | - 'LICENSE' 20 | - '.gitignore' 21 | jobs: 22 | lint: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | node-version: [10.x, 12.x, 13.x, 14.x] 27 | steps: 28 | - uses: actions/checkout@v2 29 | 30 | - name: Use Node.js ${{ matrix.node-version }} 31 | uses: actions/setup-node@v2 32 | with: 33 | node-version: ${{ matrix.node-version }} 34 | 35 | - name: Install global packages 36 | run: npm i -g eslint 37 | 38 | - name: Installs packages 39 | run: npm ci 40 | 41 | - name: Lint the repository 42 | run: eslint src --ext .js --fix 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | old/ 4 | *.env 5 | 6 | *.lock 7 | *.log 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | LABEL MAINTAINER="Chris \"August\" Hernandez" 4 | RUN apk add --no-cache --update nodejs-current npm 5 | 6 | WORKDIR /opt/PressFBot 7 | COPY . . 8 | RUN npm ci 9 | RUN npm run build 10 | 11 | ENTRYPOINT [ "npm", "run", "start" ] 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2021 August 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PressFBot 2 | ![Workflow Status](https://github.com/auguwu/PressFBot/workflows/ESLint/badge.svg) 3 | 4 | press f in chat bois 5 | 6 | ## Installation 7 | ### Requirements 8 | - Docker (optional) 9 | - Sentry (optional) 10 | - Node.js v10 or higher 11 | - Redis 12 | 13 | ### Process (locally) 14 | - [Fork](https://github.com/auguwu/PressFBot/fork) the repository under your username and run `git clone https://github.com/$USERNAME/PressFBot` 15 | - omit `$USERNAME` with your actual username on GitHub. 16 | - Change to the directory (`cd PressFBot`) and run `npm i` to install all dependencies 17 | - Complete the `.env` file under the `.env.example` file (`cp .env.example .env`) 18 | - Run `npm start` to start the bot 19 | 20 | ### Process (Docker) 21 | > Notice: **This is the recommended way to run PressFBot so you don't need to install any dependencies on your machine.** 22 | > 23 | > :warning: **If you are using Windows or macOS, please install Docker Desktop for your system if you are going to use this method.** 24 | 25 | - [Fork](https://github.com/auguwu/PressFBot/fork) the repository under your username and run `git clone https://github.com/$USERNAME/PressFBot` 26 | - omit `$USERNAME` with your actual username on GitHub. 27 | - Change to the directory (`cd PressFBot`) and complete the `.env` file under the `.env.example` file (`cp .env.example .env`) 28 | - Run `npm run docker:build` to create a image called **pressfbot** under the **latest** tag. 29 | - Run the image by running `npm run docker:run` to start 2 processes of Redis and the bot itself. 30 | 31 | ## License 32 | **PressFBot** is released under the MIT License, read [here](/LICENSE) for more information. 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@august/pressfbot", 3 | "description": "Press F in chat bois", 4 | "version": "3.0.0", 5 | "main": "build/bot.js", 6 | "license": "MIT", 7 | "repository": "https://github.com/auguwu/PressFBot", 8 | "author": "Chris \"August\" Hernandez ", 9 | "scripts": { 10 | "docker:build": "docker build . -t pressfbot:latest", 11 | "docker:run": "docker run -d --name pressfbot pressfbot:latest", 12 | "build": "npm run lint && rm -rf build && tsc", 13 | "prepare": "npm run lint", 14 | "start": "cd build && node bot.js", 15 | "lint": "eslint src --ext .js --fix" 16 | }, 17 | "dependencies": { 18 | "@augu/dotenv": "1.3.0", 19 | "@augu/orchid": "2.2.3", 20 | "@augu/utils": "1.2.0", 21 | "ioredis": "4.24.2", 22 | "loggaby": "4.0.3", 23 | "wumpcord": "1.1.0" 24 | }, 25 | "devDependencies": { 26 | "@augu/eslint-config": "1.10.0", 27 | "@augu/tsconfig": "1.0.1", 28 | "@types/ioredis": "4.22.0", 29 | "@types/node": "14.14.35", 30 | "eslint": "7.22.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "automerge": true, 3 | "extends": ["config:base"] 4 | } -------------------------------------------------------------------------------- /src/commands.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020-2021 August 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | const { EmbedBuilder, version: wumpVer } = require('wumpcord'); 24 | const { version } = require('../package.json'); 25 | const { inspect } = require('util'); 26 | const utils = require('@augu/utils'); 27 | const redis = require('./redis'); 28 | 29 | const filterOut = (client, script) => script.replace(new RegExp([ 30 | client.token, 31 | process.env.BOATS_TOKEN, 32 | process.env.REDIS_HOST, 33 | process.env.REDIS_PASSWORD 34 | ].filter(Boolean).join('|'), 'gi'), 'uwu my owo?'); 35 | 36 | /** 37 | * list of commands available 38 | * @type {{ [x: string]: CommandExecutor; }} 39 | */ 40 | module.exports = { 41 | async stats(event, args) { 42 | if (args[0] === 'gateway') { 43 | const shards = this.shards.map(shard => { 44 | const isCurr = shard.id === event.guild.shardID; 45 | return `${shard.status === 'connected' ? '+' : shard.status === 'handshaking' || shard.status === 'nearly' ? '*' : '-'} Shard #${shard.id}${isCurr ? ' (current)' : ''} | G: ${this.guilds.cache.size} / U: ${this.users.cache.size} / C: ${this.channels.cache.size} / L: ${shard.ping}ms / S: ${shard.status}`; 46 | }); 47 | 48 | return event.channel.send(`\`\`\`diff\n${shards.join('\n')}\`\`\``); 49 | } 50 | 51 | const counter = await redis.get('pressfbot:counter').then(Number).catch(() => 0); 52 | const guildCount = await redis.get(`pressfbot:counter:${event.guild.id}`).then(Number).catch(() => 0); 53 | 54 | const embed = new EmbedBuilder() 55 | .setColor(0x9AB4D0) 56 | .setTitle(`PressFBot v${version}`) 57 | .setDescription([ 58 | `❯ **Global Counter** ~ ${counter.toLocaleString()} (${guildCount.toLocaleString()} in guild)`, 59 | `❯ **Channels** ~ ${this.channels.cache.size.toLocaleString()}`, 60 | `❯ **Library** ~ [Wumpcord v${wumpVer}](https://github.com/auguwu/Wumpcord)`, 61 | `❯ **Creator** ~ ${process.env.OWNERS.split(',').map(r => this.users.get(r)).filter(r => r !== null).map(u => u.tag).join(', ')}`, 62 | `❯ **Guilds** ~ ${this.guilds.cache.size.toLocaleString()}`, 63 | `❯ **Shards** ~ ${event.guild.shardID}/${this.shards.size} (${this.shards.ping}ms avg.)`, 64 | `❯ **Users** ~ ${this.users.cache.size.toLocaleString()}` 65 | ]); 66 | 67 | return event.channel.send({ embed: embed.build() }); 68 | }, 69 | 70 | async eval(event, args) { 71 | if (!process.env.OWNERS.split(',').includes(event.message.author.id)) 72 | return; 73 | 74 | if (!args.length) 75 | return event.message.reply('gimme stuff to eval >w<', { // could care less tbh 76 | mentions: { replied: true } 77 | }); 78 | 79 | const script = args.join(' '); 80 | let result; 81 | let customScope = script.includes('return') || script.includes('await'); 82 | 83 | if (script.startsWith('```js') && script.endsWith('```')) { 84 | script = script.replace('```js', ''); 85 | script = script.replace('```', ''); 86 | 87 | customScope = true; // force to be in custom scope 88 | } 89 | 90 | const start = process.hrtime(); 91 | try { 92 | result = eval(customScope ? `const __main__ = () => {${script}}; __main__();` : script); 93 | if (result instanceof Promise) result = await result; 94 | if (typeof result !== 'string') 95 | result = inspect(result, { 96 | depth: 2, 97 | showHidden: false, 98 | }); 99 | 100 | const returned = filterOut(this, result); 101 | const endTime = utils.calculateHRTime(start); 102 | return event.channel.send(`:thumbsup: **${endTime}ms**\n\`\`\`js\n${returned ?? '// Nothing was returned.'}\`\`\``); 103 | } catch(ex) { 104 | return event.channel.send(`:x: **${utils.calculateHRTime(start)}ms**\n\`\`\`js\n${ex.stack}\`\`\``); 105 | } 106 | }, 107 | 108 | invite(event) { 109 | return event.channel.send(`:link: **** / https://discord.gg/JjHGR6vhcG`); 110 | } 111 | }; 112 | 113 | /** 114 | * @typedef {(this: import('wumpcord').Client, event: import('wumpcord').MessageCreateEvent, args: string[]) => any} CommandExecutor The command's executor 115 | */ 116 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020-2021 August 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* eslint-disable camelcase */ 24 | 25 | // im about to be a skid and use switch cases for commands 26 | // because this bot is basic as fuck 27 | 28 | require('@augu/dotenv').parse({ 29 | schema: { 30 | DISCORD_TOKEN: { 31 | type: 'string', 32 | default: undefined 33 | }, 34 | OWNERS: { 35 | type: 'array', 36 | default: [] 37 | }, 38 | BOATS_TOKEN: { 39 | type: 'string', 40 | default: undefined 41 | }, 42 | REDIS_HOST: { 43 | type: 'string', 44 | default: 'localhost' 45 | }, 46 | REDIS_PORT: { 47 | type: 'int', 48 | default: 6379 49 | }, 50 | REDIS_PASSWORD: { 51 | type: 'string', 52 | default: undefined 53 | }, 54 | NODE_ENV: { 55 | type: 'string', 56 | oneOf: ['development', 'production'], 57 | default: undefined 58 | } 59 | }, 60 | 61 | populate: true, 62 | delimiter: ',', 63 | file: (require('path')).join(__dirname, '..', '.env') 64 | }); 65 | 66 | const { Client, EmbedBuilder } = require('wumpcord'); 67 | const commands = require('./commands'); 68 | const logger = require('./logger'); 69 | const orchid = require('@augu/orchid'); 70 | const redis = require('./redis'); 71 | 72 | // create the client 73 | const client = new Client({ 74 | getAllUsers: false, 75 | shardCount: 'auto', 76 | token: process.env.DISCORD_TOKEN, 77 | ws: { intents: ['guilds', 'guildMessages'] } 78 | }); 79 | 80 | // listen when the bot is ready 81 | client.on('ready', () => { 82 | logger.log(`Logged in as ${client.user.tag}!`); 83 | client.setStatus('online', { 84 | type: 2, 85 | name: `to f in chat | ${client.guilds.cache.size.toLocaleString()} Guilds` 86 | }); 87 | 88 | postStats(); 89 | }); 90 | 91 | // listen for messages 92 | client.on('message', async event => { 93 | // ignore bots 94 | if (event.message.author.bot) return; 95 | 96 | // check if it's a text or news channel 97 | if (!['text', 'news'].includes(event.channel.type)) 98 | return; 99 | 100 | // check if they reacted with F 101 | if ( 102 | event.message.content === 'f' || 103 | event.message.content === 'F' || 104 | event.message.content === ':regional_indicator_f:' 105 | ) { 106 | const count = (await redis.get('pressfbot:counter').then(Number).catch(() => 0)) + 1; 107 | const guildCount = (await redis.get(`pressfbot:counter:${event.guild.id}`).then(Number).catch(() => 0)) + 1; 108 | 109 | await redis.set('pressfbot:counter', `${count}`); // force to be string 110 | await redis.set(`pressfbot:counter:${event.guild.id}`, `${guildCount}`); 111 | 112 | return event.channel.send({ 113 | content: [ 114 | `<@!${event.message.author.id}> has paid respects.`, 115 | '', 116 | `> **Global Counter**: ${count.toLocaleString()}`, 117 | `> **${event.guild.name}**: ${guildCount.toLocaleString()}` 118 | ].join('\n'), 119 | 120 | mentions: { users: [] } 121 | }); 122 | } 123 | 124 | // check for commands 125 | if (event.message.content.startsWith('f ')) { 126 | const args = event.message.content.slice('f '.length).split(/ +/g); 127 | const name = args.shift(); 128 | 129 | // ignore on no command 130 | if (!commands.hasOwnProperty(name)) 131 | return; 132 | 133 | // run the command 134 | try { 135 | await commands[name].call(client, event, args); 136 | } catch(ex) { 137 | const embed = new EmbedBuilder() 138 | .setTitle(`Unable to run command '${name}'`) 139 | .setDescription(`\`\`\`js\n${ex.stack ?? '// No callstack is available'}\`\`\``) 140 | .setColor(0x9AB4D0) 141 | .build(); 142 | 143 | logger.error(ex); 144 | return event.channel.send({ embed }); 145 | } 146 | } 147 | }); 148 | 149 | // listen on guild events 150 | client.on('guildCreate', async event => { 151 | logger.log(`Joined ${event.guild.name}!`); 152 | await postStats(); 153 | 154 | const channel = client.channels.get(process.env.GUILD_POST_CHANNEL); 155 | channel?.send({ 156 | embed: new EmbedBuilder() 157 | .setTitle(`Joined ${event.guild.name}! :smiley:`) 158 | .setColor(0x9AB4D0) 159 | .build() 160 | }); 161 | }); 162 | 163 | client.on('guildDelete', async event => { 164 | logger.warn(`Left ${event.guild.name}!`); 165 | await postStats(); 166 | 167 | const channel = client.channels.get(process.env.GUILD_POST_CHANNEL); 168 | channel?.send({ 169 | embed: new EmbedBuilder() 170 | .setTitle(`Left ${event.guild.name}... :sob:`) 171 | .setColor(0x9AB4D0) 172 | .build() 173 | }); 174 | }); 175 | 176 | // listen on shard events 177 | client.on('shardReady', id => logger.log(`[#${id}] Shard is ready.`)); 178 | client.on('shardClose', (id, error) => logger.error(`[#${id}] Shard has closed connection with Discord\n`, error)); 179 | client.on('debug', console.debug); 180 | 181 | // listen to redis shit 182 | redis.on('ready', () => logger.log('Redis has connected successfully')); 183 | 184 | // now run everything 185 | async function main() { 186 | logger.log('Now connecting to Discord...'); 187 | 188 | await redis.connect(); 189 | await client.connect(); 190 | 191 | process.on('SIGINT', () => { 192 | logger.warn('told to disconnect'); 193 | 194 | redis.disconnect(); 195 | client.disconnect(false); 196 | process.exit(0); 197 | }); 198 | } 199 | 200 | async function postStats() { 201 | if (process.env.NODE_ENV === 'development') 202 | return; 203 | 204 | if (process.env.BOATS_TOKEN !== undefined) { 205 | const res = await orchid.post({ 206 | url: `https://discord.boats/api/v2/bot/${client.user.id}`, 207 | 208 | headers: { 209 | Authorization: process.env.BOATS_TOKEN 210 | }, 211 | 212 | data: { 213 | server_count: client.guilds.cache.size 214 | } 215 | }); 216 | 217 | logger.log(`Posted to discord.boats (${res.status})\n${JSON.stringify(res.json(), null, 2)}`); 218 | } 219 | } 220 | 221 | main(); 222 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020-2021 August 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | const Loggaby = require('loggaby'); 24 | 25 | /** @type {ReturnConstructorType} */ 26 | module.exports = new Loggaby({ 27 | format: '{grey}[{level.color}{level.name}{grey} | {magenta}{time}{magenta}{grey}] ' 28 | }); 29 | 30 | /** 31 | * @typedef {T extends new (...args: any[]) => infer P ? P : never} ReturnConstructorType 32 | * @template T 33 | */ 34 | 35 | // {grey}[{level.color}{level.name}{grey} | {magenta}${name}:${filename.join('/')}{magenta}{grey} | {cyan}{time}{cyan}{grey}] 36 | -------------------------------------------------------------------------------- /src/redis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020-2021 August 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | const IORedis = require('ioredis'); 24 | 25 | /** singleton of a redis instance */ 26 | module.exports = new IORedis({ 27 | password: process.env.REDIS_PASSWORD, 28 | host: process.env.REDIS_HOST, 29 | port: process.env.REDIS_PORT, 30 | db: 6, 31 | 32 | lazyConnect: true 33 | }); 34 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | # Updates on local machine 2 | 3 | DOCKER_PID=$(echo $(docker ps -aqf name="pressfbot") | sed 's/\=//') 4 | 5 | docker stop $DOCKER_PID 6 | docker rm $DOCKER_PID 7 | docker build . -t pressfbot:latest 8 | docker run --name pressfbot -d pressfbot:latest 9 | --------------------------------------------------------------------------------